diff --git a/etc/apache2.site b/etc/apache2.site index 4c1c24cd2..afd0a862d 100644 --- a/etc/apache2.site +++ b/etc/apache2.site @@ -21,7 +21,7 @@ RequestHeader unset Accept-Encoding SetEnv no-gzip 1 ProxyHTMLBufSize 32768 - ProxyHTMLEnable On + # ProxyHTMLEnable On ProxyHTMLStripComments Off ProxyHTMLMeta On ProxyHTMLDocType HTML diff --git a/external/rpi-rgb-led-matrix b/external/rpi-rgb-led-matrix index d73456c21..21410d2b0 160000 --- a/external/rpi-rgb-led-matrix +++ b/external/rpi-rgb-led-matrix @@ -1 +1 @@ -Subproject commit d73456c2164b182d06c9c87513fe3913f87a1994 +Subproject commit 21410d2b0bac006b4a1661594926af347b3ce334 diff --git a/external/rpi_ws281x b/external/rpi_ws281x index 428026eb3..6b01e53c3 160000 --- a/external/rpi_ws281x +++ b/external/rpi_ws281x @@ -1 +1 @@ -Subproject commit 428026eb37f6caad247690a4d37d6ad693f1e487 +Subproject commit 6b01e53c3f8bbcfd2c49c447d4c6a6e2b0031370 diff --git a/src/MultiSync.cpp b/src/MultiSync.cpp index 594d57cff..b66f26059 100644 --- a/src/MultiSync.cpp +++ b/src/MultiSync.cpp @@ -82,6 +82,57 @@ NetInterfaceInfo::~NetInterfaceInfo() { } } + +void MultiSyncSystem::update(MultiSyncSystemType type, + unsigned int majorVersion, unsigned int minorVersion, + FPPMode fppMode, + const std::string &address, + const std::string &hostname, + const std::string &version, + const std::string &model, + const std::string &ranges) { + this->type = type; + this->majorVersion = majorVersion; + this->minorVersion = minorVersion; + this->address = address; + this->hostname = hostname; + this->fppMode = fppMode; + this->version = version; + this->model = model; + this->ranges = ranges; + std::vector parts = split(address, '.'); + this->ipa = atoi(parts[0].c_str()); + this->ipb = atoi(parts[1].c_str()); + this->ipc = atoi(parts[2].c_str()); + this->ipd = atoi(parts[3].c_str()); +} + +Json::Value MultiSyncSystem::toJSON(bool local, bool timestamps) { + Json::Value system; + + system["type"] = MultiSync::GetTypeString(type, local); + if (timestamps) { + system["lastSeen"] = (Json::UInt64)lastSeen; + system["lastSeenStr"] = lastSeenStr; + } + system["majorVersion"] = majorVersion; + system["minorVersion"] = minorVersion; + system["fppMode"] = fppMode; + + char *s = modeToString(fppMode); + system["fppModeString"] = s; + free(s); + + system["address"] = address; + system["hostname"] = hostname; + system["version"] = version; + system["model"] = model; + system["channelRanges"] = ranges; + + return system; +} + + /* * */ @@ -92,13 +143,14 @@ MultiSync::MultiSync() m_receiveSock(-1), m_lastMediaHalfSecond(0), m_remoteOffset(0.0), - m_numLocalSystems(0), m_lastPingTime(0), m_lastCheckTime(0), m_lastFrame(0), m_sendMulticast(false), m_sendBroadcast(false) { + memset(rcvBuffers, 0, sizeof(rcvBuffers)); + memset(rcvCmbuf, 0, sizeof(rcvCmbuf)); } /* @@ -162,48 +214,43 @@ void MultiSync::UpdateSystem(MultiSyncSystemType type, const std::string &ranges ) { + + char timeStr[32]; + memset(timeStr, 0, sizeof(timeStr)); + time_t t = time(NULL); + struct tm tm; + localtime_r(&t, &tm); + sprintf(timeStr,"%4d-%.2d-%.2d %.2d:%.2d:%.2d", + 1900+tm.tm_year, tm.tm_mon+1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); + std::unique_lock lock(m_systemsLock); - int found = -1; - for (int i = 0; i < m_systems.size(); i++) { - if ((address == m_systems[i].address) && - (hostname == m_systems[i].hostname)) { - found = i; - } - } - - if (found < 0) { - MultiSyncSystem newSystem; - - m_systems.push_back(newSystem); - - found = m_systems.size() - 1; - } - - char timeStr[32]; - time_t t = time(NULL); - struct tm tm; - - m_systems[found].lastSeen = (unsigned long)t; - m_systems[found].type = type; - m_systems[found].majorVersion = majorVersion; - m_systems[found].minorVersion = minorVersion; - m_systems[found].address = address; - m_systems[found].hostname = hostname; - m_systems[found].fppMode = fppMode; - m_systems[found].version = version; - m_systems[found].model = model; - m_systems[found].ranges = ranges; - std::vector parts = split(address, '.'); - m_systems[found].ipa = atoi(parts[0].c_str()); - m_systems[found].ipb = atoi(parts[1].c_str()); - m_systems[found].ipc = atoi(parts[2].c_str()); - m_systems[found].ipd = atoi(parts[3].c_str()); - - localtime_r(&t, &tm); - sprintf(timeStr,"%4d-%.2d-%.2d %.2d:%.2d:%.2d", - 1900+tm.tm_year, tm.tm_mon+1, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec); - m_systems[found].lastSeenStr = timeStr; + bool found = false; + for (auto & sys : m_remoteSystems) { + if ((address == sys.address) && + (hostname == sys.hostname)) { + found = true; + sys.update(type, majorVersion, minorVersion, fppMode, address, hostname, version, model, ranges); + sys.lastSeenStr = timeStr; + sys.lastSeen = t; + } + } + for (auto & sys : m_localSystems) { + if ((address == sys.address) && + (hostname == sys.hostname)) { + found = true; + sys.update(type, majorVersion, minorVersion, fppMode, address, hostname, version, model, ranges); + sys.lastSeen = t; + sys.lastSeenStr = timeStr; + } + } + if (!found) { + MultiSyncSystem sys; + sys.update(type, majorVersion, minorVersion, fppMode, address, hostname, version, model, ranges); + sys.lastSeenStr = timeStr; + sys.lastSeen = t; + m_remoteSystems.push_back(sys); + } } /* @@ -279,6 +326,7 @@ bool MultiSync::FillLocalSystemInfo(void) if (tmp->ifa_addr && tmp->ifa_addr->sa_family == AF_INET) { if (strncmp("usb", tmp->ifa_name, 3) != 0) { //skip the usb* interfaces as we won't support multisync on those + memset(addressBuf, 0, sizeof(addressBuf)); GetInterfaceAddress(tmp->ifa_name, addressBuf, NULL, NULL); if (isSupportedForMultisync(addressBuf, tmp->ifa_name)) { addresses.push_back(addressBuf); @@ -291,6 +339,7 @@ bool MultiSync::FillLocalSystemInfo(void) } freeifaddrs(interfaces); } else { + memset(addressBuf, 0, sizeof(addressBuf)); GetInterfaceAddress(multiSyncInterface.c_str(), addressBuf, NULL, NULL); addresses.push_back(addressBuf); } @@ -316,22 +365,22 @@ bool MultiSync::FillLocalSystemInfo(void) newSystem.ipc = 0; newSystem.ipd = 0; - LogDebug(VB_SYNC, "Host name: \n", newSystem.hostname.c_str()); - LogDebug(VB_SYNC, "Version: \n", newSystem.version.c_str()); - LogDebug(VB_SYNC, "Model: \n", newSystem.model.c_str()); + LogDebug(VB_SYNC, "Host name: %s\n", newSystem.hostname.c_str()); + LogDebug(VB_SYNC, "Version: %s\n", newSystem.version.c_str()); + LogDebug(VB_SYNC, "Model: %s\n", newSystem.model.c_str()); bool changed = false; std::unique_lock lock(m_systemsLock); for (auto address : addresses) { bool found = false; - for (auto &sys : m_systems) { + for (auto &sys : m_localSystems) { if (sys.address == address) { found = true; } } if (!found) { - LogDebug(VB_SYNC, "Adding Local System Address: \n", address.c_str()); + LogDebug(VB_SYNC, "Adding Local System Address: %s\n", address.c_str()); changed = true; newSystem.address = address; std::vector parts = split(newSystem.address, '.'); @@ -339,12 +388,7 @@ bool MultiSync::FillLocalSystemInfo(void) newSystem.ipb = atoi(parts[1].c_str()); newSystem.ipc = atoi(parts[2].c_str()); newSystem.ipd = atoi(parts[3].c_str()); - if (m_numLocalSystems >= m_systems.size()) { - m_systems.push_back(newSystem); - } else { - m_systems.insert(m_systems.begin() + m_numLocalSystems, newSystem); - } - m_numLocalSystems++; + m_localSystems.push_back(newSystem); } } return changed; @@ -452,12 +496,13 @@ std::string MultiSync::GetTypeString(MultiSyncSystemType type, bool local) static std::string createRanges(std::vector> ranges, int limit) { bool first = true; - std::string range; + std::string range(""); + char buf[64]; + memset(buf, 0, sizeof(buf)); for (auto &a : ranges) { if (!first) { range += ","; } - char buf[64]; sprintf(buf, "%d-%d", a.first, (a.first + a.second - 1)); range += buf; first = false; @@ -490,43 +535,22 @@ Json::Value MultiSync::GetSystems(bool localOnly, bool timestamps) { Json::Value result; Json::Value systems(Json::arrayValue); - std::unique_lock lock(m_systemsLock); - - int max = localOnly ? m_numLocalSystems : m_systems.size(); + const std::vector> &ranges = GetOutputRanges(); std::string range = createRanges(ranges, 999999); - - for (int i = 0; i < max; i++) { - Json::Value system; - - system["type"] = GetTypeString(m_systems[i].type, i < m_numLocalSystems); - if (timestamps) { - system["lastSeen"] = (Json::UInt64)m_systems[i].lastSeen; - system["lastSeenStr"] = m_systems[i].lastSeenStr; - } - system["majorVersion"] = m_systems[i].majorVersion; - system["minorVersion"] = m_systems[i].minorVersion; - system["fppMode"] = m_systems[i].fppMode; - - char *s = modeToString(m_systems[i].fppMode); - system["fppModeString"] = s; - free(s); - - system["address"] = m_systems[i].address; - system["hostname"] = m_systems[i].hostname; - system["version"] = m_systems[i].version; - system["model"] = m_systems[i].model; - if (i < m_numLocalSystems) { - m_systems[i].ranges = range; + std::unique_lock lock(m_systemsLock); + for (auto &sys : m_localSystems) { + sys.ranges = range; + systems.append(sys.toJSON(true, timestamps)); + } + if (!localOnly) { + for (auto &sys : m_remoteSystems) { + systems.append(sys.toJSON(false, timestamps)); } - system["channelRanges"] = m_systems[i].ranges; - - systems.append(system); - } + } result["systems"] = systems; - return result; } @@ -535,7 +559,7 @@ Json::Value MultiSync::GetSystems(bool localOnly, bool timestamps) */ void MultiSync::Ping(int discover, bool broadcast) { - LogDebug(VB_SYNC, "MultiSync::Ping(%d)\n", discover); + LogDebug(VB_SYNC, "MultiSync::Ping(%d, %d)\n", discover, broadcast); time_t t = time(NULL); m_lastPingTime = (unsigned long)t; @@ -547,20 +571,20 @@ void MultiSync::Ping(int discover, bool broadcast) //update the range for local systems so it's accurate const std::vector> &ranges = GetOutputRanges(); std::string range = createRanges(ranges, 120); - for (int x = 0; x < m_numLocalSystems; x++) { - std::unique_lock lock(m_systemsLock); - m_systems[x].ranges = range; - MultiSyncSystem sysInfo = m_systems[x]; + char outBuf[768]; + + std::unique_lock lock(m_systemsLock); + for (auto & sys : m_localSystems) { + memset(outBuf, 0, sizeof(outBuf)); + sys.ranges = range; + int len = CreatePingPacket(sys, outBuf, discover); lock.unlock(); - - char outBuf[512]; - bzero(outBuf, sizeof(outBuf)); - int len = CreatePingPacket(sysInfo, outBuf, discover); if (broadcast) { SendBroadcastPacket(outBuf, len); } else { SendMulticastPacket(outBuf, len); } + lock.lock(); } } void MultiSync::PeriodicPing() { @@ -573,13 +597,13 @@ void MultiSync::PeriodicPing() { //once an hour, we'll send a ping letting everyone know we're still here //mark ourselves as seen std::unique_lock lock(m_systemsLock); - for (int x = 0; x < m_numLocalSystems; x++) { - m_systems[x].lastSeen = (unsigned long)t; + for (auto &sys : m_localSystems) { + sys.lastSeen = (unsigned long)t; } lock.unlock(); Ping(); } - //every 10 minutes we'll loop through real quick and check for instances + //every 10 minutes we'll loop through real quick and check for remote instances //we haven't heard from in a while lpt = m_lastCheckTime + 60*10; if (lpt < (unsigned long)t) { @@ -591,13 +615,13 @@ void MultiSync::PeriodicPing() { //to any of those 4, it's got to be down/gone. Remove it. unsigned long timeoutRemove = (unsigned long)t - 60*120; std::unique_lock lock(m_systemsLock); - for (auto it = m_systems.begin(); it != m_systems.end(); ) { + for (auto it = m_remoteSystems.begin(); it != m_remoteSystems.end(); ) { if (it->lastSeen < timeoutRemove) { LogInfo(VB_SYNC, "Have not seen %s in over 2 hours, removing\n", it->address.c_str()); - m_systems.erase(it); + m_remoteSystems.erase(it); } else if (it->lastSeen < timeoutRePing) { //do a ping - PingSingleRemote(it - m_systems.begin()); + PingSingleRemote(*it); ++it; } else { ++it; @@ -605,14 +629,17 @@ void MultiSync::PeriodicPing() { } } } -void MultiSync::PingSingleRemote(int sysIdx) { +void MultiSync::PingSingleRemote(MultiSyncSystem &sys) { + if (m_localSystems.empty()) { + return; + } char outBuf[512]; memset(outBuf, 0, sizeof(outBuf)); - int len = CreatePingPacket(m_systems[0], outBuf, 1); + int len = CreatePingPacket(m_localSystems[0], outBuf, 1); struct sockaddr_in dest_addr; memset(&dest_addr, 0, sizeof(dest_addr)); dest_addr.sin_family = AF_INET; - dest_addr.sin_addr.s_addr = inet_addr(m_systems[sysIdx].address.c_str()); + dest_addr.sin_addr.s_addr = inet_addr(sys.address.c_str()); dest_addr.sin_port = htons(FPP_CTRL_PORT); std::unique_lock lock(m_socketLock); sendto(m_controlSock, outBuf, len, MSG_DONTWAIT, (struct sockaddr*)&dest_addr, sizeof(dest_addr)); @@ -1577,13 +1604,14 @@ bool MultiSync::isSupportedForMultisync(const char *address, const char *intface } void MultiSync::setupMulticastReceive() { - struct ip_mreq mreq; - memset(&mreq, 0, sizeof(mreq)); - mreq.imr_multiaddr.s_addr = inet_addr(MULTISYNC_MULTICAST_ADDRESS); + LogDebug(VB_SYNC, "setupMulticastReceive()\n"); //loop through all the interfaces and subscribe to the group std::unique_lock lock(m_socketLock); for (auto &a : m_interfaces) { LogDebug(VB_SYNC, " Adding interface %s - %s\n", a.second.interfaceName.c_str(), a.second.interfaceAddress.c_str()); + struct ip_mreq mreq; + memset(&mreq, 0, sizeof(mreq)); + mreq.imr_multiaddr.s_addr = inet_addr(MULTISYNC_MULTICAST_ADDRESS); mreq.imr_interface.s_addr = a.second.address; int rc = 0; if ((rc = setsockopt(m_receiveSock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq))) < 0) { @@ -1925,6 +1953,7 @@ void MultiSync::ProcessPingPacket(ControlPkt *pkt, int len) FPPMode systemMode = (FPPMode)extraData[7]; char addrStr[16]; + memset(addrStr, 0, sizeof(addrStr)); bool isInstance = true; if (extraData[8] == 0 && extraData[9] == 0 @@ -1943,6 +1972,7 @@ void MultiSync::ProcessPingPacket(ControlPkt *pkt, int len) std::string address = addrStr; char tmpStr[128]; + memset(tmpStr, 0, sizeof(tmpStr)); strcpy(tmpStr, (char*)(extraData + 12)); std::string hostname(tmpStr); diff --git a/src/MultiSync.h b/src/MultiSync.h index b60bfe437..3d850a8e0 100644 --- a/src/MultiSync.h +++ b/src/MultiSync.h @@ -109,23 +109,37 @@ typedef enum systemType { kSysTypeESPixelStick = 0xC2 } MultiSyncSystemType; -typedef struct multiSyncSystem { - unsigned long lastSeen; +class MultiSyncSystem { +public: + MultiSyncSystem() { + } + unsigned long lastSeen = 0; std::string lastSeenStr; - MultiSyncSystemType type; - unsigned int majorVersion; - unsigned int minorVersion; - FPPMode fppMode; + MultiSyncSystemType type = kSysTypeUnknown; + unsigned int majorVersion = 0; + unsigned int minorVersion = 0; + FPPMode fppMode = FPPMode::PLAYER_MODE; std::string address; std::string hostname; std::string version; std::string model; std::string ranges; - unsigned char ipa; - unsigned char ipb; - unsigned char ipc; - unsigned char ipd; -} MultiSyncSystem; + unsigned char ipa = 0; + unsigned char ipb = 0; + unsigned char ipc = 0; + unsigned char ipd = 0; + + + void update(MultiSyncSystemType type, + unsigned int majorVersion, unsigned int minorVersion, + FPPMode fppMode, + const std::string &address, + const std::string &hostname, + const std::string &version, + const std::string &model, + const std::string &ranges); + Json::Value toJSON(bool local, bool timestamps); +}; class MultiSyncPlugin { @@ -223,17 +237,18 @@ class MultiSync { int OpenControlSockets(); + static std::string GetTypeString(MultiSyncSystemType type, bool local = false); + private: bool isSupportedForMultisync(const char *address, const char *intface); void setupMulticastReceive(); - void PingSingleRemote(int sysIdx); + void PingSingleRemote(MultiSyncSystem &sys); int CreatePingPacket(MultiSyncSystem &sys, char* outBuf, int discover); MultiSyncSystemType ModelStringToType(std::string model); bool FillLocalSystemInfo(void); std::string GetHardwareModel(void); - std::string GetTypeString(MultiSyncSystemType type, bool local = false); int OpenBroadcastSocket(void); void SendBroadcastPacket(void *outBuf, int len); @@ -257,8 +272,8 @@ class MultiSync { void ProcessPluginPacket(ControlPkt *pkt, int len); std::mutex m_systemsLock; - std::vector m_systems; - int m_numLocalSystems; + std::vector m_localSystems; + std::vector m_remoteSystems; std::map m_interfaces; bool m_sendMulticast; diff --git a/src/NetworkMonitor.cpp b/src/NetworkMonitor.cpp index 0ce7feca5..071753cd1 100644 --- a/src/NetworkMonitor.cpp +++ b/src/NetworkMonitor.cpp @@ -101,12 +101,17 @@ void NetworkMonitor::Init(std::map> &callbacks) { } void NetworkMonitor::callCallbacks(NetEventType nl, int up, const std::string &n) { for (auto &cb : callbacks) { - cb(nl, up, n); + cb.second(nl, up, n); } } -void NetworkMonitor::registerCallback(std::function &callback) { - callbacks.push_back(callback); +int NetworkMonitor::registerCallback(std::function &callback) { + int id = curId++; + callbacks[id] = callback; + return id; } +void NetworkMonitor::removeCallback(int id) { + callbacks.erase(id); +} diff --git a/src/NetworkMonitor.h b/src/NetworkMonitor.h index fccdf66bd..018a5151f 100644 --- a/src/NetworkMonitor.h +++ b/src/NetworkMonitor.h @@ -35,20 +35,22 @@ class NetworkMonitor { }; - NetworkMonitor() {} + NetworkMonitor() : curId(0) {} ~NetworkMonitor() {} void Init(std::map> &callbacks); - void registerCallback(std::function &callback); - void addCallback(std::function &callback) { registerCallback(callback); } + int registerCallback(std::function &callback); + int addCallback(std::function &callback) { return registerCallback(callback); } + void removeCallback(int id); static NetworkMonitor INSTANCE; private: void callCallbacks(NetEventType, int, const std::string &n); - std::list> callbacks; + std::map> callbacks; + int curId; }; #endif diff --git a/src/PixelOverlay.cpp b/src/PixelOverlay.cpp index f4f68c8b0..15470e675 100644 --- a/src/PixelOverlay.cpp +++ b/src/PixelOverlay.cpp @@ -162,7 +162,8 @@ void PixelOverlayModel::doText(const std::string &msg, int fontSize, bool antialias, const std::string &position, - int pixelsPerSecond) { + int pixelsPerSecond, + bool autoEnable) { if (updateThread) { threadKeepRunning = false; updateThread->join(); @@ -177,10 +178,34 @@ void PixelOverlayModel::doText(const std::string &msg, image.fontPointsize(fontSize); image.antiAlias(antialias); - - Magick::TypeMetric metrics; - image.fontTypeMetrics(msg, &metrics); + bool disableWhenDone = false; + if ((autoEnable) && (getState().getState() == PixelOverlayState::PixelState::Disabled)) + { + setState(PixelOverlayState(PixelOverlayState::PixelState::Enabled)); + disableWhenDone = true; + } + + int maxWid = 0; + int totalHi = 0; + int lines = 1; + int last = 0; + for (int x = 0; x < msg.length(); x++) { + if (msg[x] == '\n') { + lines++; + std::string newM = msg.substr(last, x); + Magick::TypeMetric metrics; + image.fontTypeMetrics(newM, &metrics); + maxWid = std::max(maxWid, (int)metrics.textWidth()); + totalHi += (int)metrics.textHeight(); + last = x + 1; + } + } + std::string newM = msg.substr(last); + Magick::TypeMetric metrics; + image.fontTypeMetrics(newM, &metrics); + maxWid = std::max(maxWid, (int)metrics.textWidth()); + totalHi += (int)metrics.textHeight(); if (position == "Centered" || position == "Center") { image.magick("RGB"); @@ -202,6 +227,9 @@ void PixelOverlayModel::doText(const std::string &msg, image.write( &blob ); setData((uint8_t*)blob.data()); + + if (disableWhenDone) + setState(PixelOverlayState(PixelOverlayState::PixelState::Disabled)); } else { //movement double rr = r; @@ -210,8 +238,9 @@ void PixelOverlayModel::doText(const std::string &msg, rr /= 255.0f; rg /= 255.0f; rb /= 255.0f; + - Magick::Image image2(Magick::Geometry(metrics.textWidth(), metrics.textHeight()), Magick::Color("black")); + Magick::Image image2(Magick::Geometry(maxWid, totalHi), Magick::Color("black")); image2.quiet(true); image2.depth(8); image2.font(font); @@ -225,12 +254,12 @@ void PixelOverlayModel::doText(const std::string &msg, image2.strokeAntiAlias(antialias); image2.annotate(msg, Magick::CenterGravity); - double y = (getHeight() / 2.0) - (metrics.textHeight() / 2.0); - double x = (getWidth() / 2.0) - (metrics.textWidth() / 2.0); + double y = (getHeight() / 2.0) - ((totalHi) / 2.0); + double x = (getWidth() / 2.0) - (maxWid / 2.0); if (position == "R2L") { x = getWidth(); } else if (position == "L2R") { - x = -metrics.textWidth(); + x = -maxWid; } else if (position == "B2T") { y = getHeight(); } else if (position == "T2B") { @@ -267,10 +296,10 @@ void PixelOverlayModel::doText(const std::string &msg, copyImageData(x, y); lock(); threadKeepRunning = true; - updateThread = new std::thread(&PixelOverlayModel::doImageMovementThread, this, position, (int)x, (int)y, pixelsPerSecond); + updateThread = new std::thread(&PixelOverlayModel::doImageMovementThread, this, position, (int)x, (int)y, pixelsPerSecond, disableWhenDone); } } -void PixelOverlayModel::doImageMovementThread(const std::string direction, int x, int y, int speed) { +void PixelOverlayModel::doImageMovementThread(const std::string &direction, int x, int y, int speed, bool disableWhenDone) { int msDelay = 1000 / speed; bool done = false; while (threadKeepRunning && !done) { @@ -298,6 +327,9 @@ void PixelOverlayModel::doImageMovementThread(const std::string direction, int x } copyImageData(x, y); } + if (disableWhenDone) + setState(PixelOverlayState(PixelOverlayState::PixelState::Disabled)); + unlock(); } @@ -915,6 +947,7 @@ static void findFonts(const std::string &dir, std::map fonts[fname] = dname; } } + closedir(dp); } } @@ -924,6 +957,7 @@ void PixelOverlayManager::loadFonts() { char **mlfonts = MagickLib::GetTypeList("*", &i); for (int x = 0; x < i; x++) { fonts[mlfonts[x]] = ""; + free(mlfonts[x]); } findFonts("/usr/share/fonts/truetype/", fonts); findFonts("/usr/local/share/fonts/", fonts); @@ -1121,6 +1155,10 @@ const httpserver::http_response PixelOverlayManager::render_PUT(const httpserver int fontSize = root["FontSize"].asInt(); bool aa = root["AntiAlias"].asBool(); int pps = root["PixelsPerSecond"].asInt(); + bool autoEnable = false; + if (root.isMember("AutoEnable")) { + autoEnable = root["AutoEnable"].asBool(); + } std::string f = fonts[font]; if (f == "") { @@ -1135,7 +1173,8 @@ const httpserver::http_response PixelOverlayManager::render_PUT(const httpserver fontSize, aa, position, - pps); + pps, + autoEnable); return httpserver::http_response_builder("OK", 200); } } @@ -1242,6 +1281,11 @@ class TextOverlayCommand : public OverlayCommand { args.push_back(CommandArg("FontAntiAlias", "bool", "Anti-Aliased").setDefaultValue("false")); args.push_back(CommandArg("Position", "string", "Position").setContentList({"Center", "Right to Left", "Left to Right", "Bottom to Top", "Top to Bottom"})); args.push_back(CommandArg("Speed", "int", "Scroll Speed").setRange(0, 200).setDefaultValue("10")); + args.push_back(CommandArg("AutoEnable", "bool", "Auto Enable/Disable Model").setDefaultValue("false")); + + // keep text as last argument if possible as the MQTT commands will, by default, use the payload of the mqtt + // msg as the last argument. Thus, this allows all of the above to be topic paths, but the text to be + // sent in the payload args.push_back(CommandArg("Text", "string", "Text").setAdjustable()); } @@ -1261,8 +1305,8 @@ class TextOverlayCommand : public OverlayCommand { } virtual std::unique_ptr run(const std::vector &args) override { - if (args.size() != 8) { - return std::make_unique("Command needs 8 arguments, found " + std::to_string(args.size())); + if (args.size() < 8) { + return std::make_unique("Command needs 9 arguments, found " + std::to_string(args.size())); } std::unique_lock lock(getLock()); auto m = manager->getModel(args[0]); @@ -1281,8 +1325,13 @@ class TextOverlayCommand : public OverlayCommand { bool aa = args[4] == "true" || args[4] == "1"; std::string position = mapPosition(args[5]); int pps = std::atoi(args[6].c_str()); - std::string msg = args[7]; + std::string msg = args[7]; + bool autoEnable = false; + if (args.size() == 9) { + autoEnable = (msg == "true" || msg == "1"); + msg = args[8]; + } m->doText(msg, (cint >> 16) & 0xFF, @@ -1292,7 +1341,8 @@ class TextOverlayCommand : public OverlayCommand { fontSize, aa, position, - pps); + pps, + autoEnable); } return std::make_unique("Model Filled"); } diff --git a/src/PixelOverlay.h b/src/PixelOverlay.h index 9c8922732..bf71e5094 100644 --- a/src/PixelOverlay.h +++ b/src/PixelOverlay.h @@ -103,7 +103,8 @@ class PixelOverlayModel { int fontSize, bool antialias, const std::string &position, - int pixelsPerSecond); + int pixelsPerSecond, + bool autoEnable); int getStartChannel() const; @@ -118,7 +119,7 @@ class PixelOverlayModel { private: void copyImageData(int xoff, int yoff); - void doImageMovementThread(const std::string direction, int x, int y, int speed); + void doImageMovementThread(const std::string &direction, int x, int y, int speed, bool disableWhenDone); std::string name; FPPChannelMemoryMapControlBlock *block; diff --git a/src/Plugins.cpp b/src/Plugins.cpp index 72ed962bb..fbda7e01c 100644 --- a/src/Plugins.cpp +++ b/src/Plugins.cpp @@ -106,9 +106,7 @@ void FPPPlugin::reloadSettings() { class MediaCallback { public: - MediaCallback(const std::string name, const std::string &filename) { - mName = name; - mFilename = filename; + MediaCallback(const std::string &name, const std::string &filename) : mName(name), mFilename(filename) { } virtual ~MediaCallback() {} @@ -123,9 +121,7 @@ class MediaCallback class PlaylistCallback { public: - PlaylistCallback(const std::string name, const std::string &filename) { - mName = name; - mFilename = filename; + PlaylistCallback(const std::string &name, const std::string &filename) : mName(name), mFilename(filename) { } virtual ~PlaylistCallback() {} @@ -140,9 +136,7 @@ class PlaylistCallback class EventCallback { public: - EventCallback(const std::string name, const std::string &filename) { - mName = name; - mFilename = filename; + EventCallback(const std::string &name, const std::string &filename) : mName(name), mFilename(filename) { } virtual ~EventCallback() {} @@ -200,17 +194,17 @@ class ScriptFPPPlugin : public FPPPlugin { return otherTypes; } - virtual void eventCallback(const char *id, const char *impetus) { + virtual void eventCallback(const char *id, const char *impetus) override { if (m_eventCallback) { m_eventCallback->run(id, impetus); } } - virtual void mediaCallback(const Json::Value &playlist, const MediaDetails &mediaDetails) { + virtual void mediaCallback(const Json::Value &playlist, const MediaDetails &mediaDetails) override { if (m_mediaCallback) { m_mediaCallback->run(playlist, mediaDetails); } } - virtual void playlistCallback(const Json::Value &playlist, const std::string &action, const std::string §ion, int item) { + virtual void playlistCallback(const Json::Value &playlist, const std::string &action, const std::string §ion, int item) override { if (m_playlistCallback) { m_playlistCallback->run(playlist, action, section, item); } diff --git a/src/ScheduleEntry.cpp b/src/ScheduleEntry.cpp index c0793e6b2..6650cf81e 100644 --- a/src/ScheduleEntry.cpp +++ b/src/ScheduleEntry.cpp @@ -32,37 +32,24 @@ #include "ScheduleEntry.h" ScheduleEntry::ScheduleEntry() - : m_enabled(0), - m_playlistName(""), - m_priority(0), - m_repeating(0), - m_dayIndex(0), - m_weeklySecondCount(0), - m_startTime(0), - m_endTime(0), - m_startHour(0), - m_startMinute(0), - m_startSecond(0), - m_endHour(0), - m_endMinute(0), - m_endSecond(0), - m_startDate(0), - m_endDate(0), - m_state(SS_IDLE), - m_lastStartTime(0), - m_lastEndTime(0), - m_thisStartTime(0), - m_thisEndTime(0), - m_nextStartTime(0), - m_nextEndTime(0) + : enabled(false), + playlist(""), + repeat(false), + dayIndex(0), + weeklySecondCount(0), + startHour(0), + startMinute(0), + startSecond(0), + endHour(0), + endMinute(0), + endSecond(0), + startDate(0), + endDate(0) { - for (int i = 0; i < DAYS_PER_WEEK; i++) - { - m_weeklyStartSeconds[i] = 0; - m_weeklyEndSeconds[i] = 0; + for (int i = 0; i < DAYS_PER_WEEK; i++) { + weeklyStartSeconds[i] = 0; + weeklyEndSeconds[i] = 0; } - - m_state = SS_IDLE; } ScheduleEntry::~ScheduleEntry() @@ -73,86 +60,35 @@ int ScheduleEntry::LoadFromString(std::string entryStr) { std::vector elems = split(entryStr, ','); - if (elems.size() < 10) - { + if (elems.size() < 10) { LogErr(VB_SCHEDULE, "Invalid Schedule Entry: '%s', %d elements\n", entryStr.c_str(), elems.size()); return 0; } - m_enabled = atoi(elems[0].c_str()); - m_playlistName = elems[1]; - m_dayIndex = atoi(elems[2].c_str()); - m_startHour = atoi(elems[3].c_str()); - m_startMinute = atoi(elems[4].c_str()); - m_startSecond = atoi(elems[5].c_str()); - m_endHour = atoi(elems[6].c_str()); - m_endMinute = atoi(elems[7].c_str()); - m_endSecond = atoi(elems[8].c_str()); - m_repeating = atoi(elems[9].c_str()); + enabled = atoi(elems[0].c_str()); + playlist = elems[1]; + dayIndex = atoi(elems[2].c_str()); + startHour = atoi(elems[3].c_str()); + startMinute = atoi(elems[4].c_str()); + startSecond = atoi(elems[5].c_str()); + endHour = atoi(elems[6].c_str()); + endMinute = atoi(elems[7].c_str()); + endSecond = atoi(elems[8].c_str()); + repeat = atoi(elems[9].c_str()); if ((elems.size() > 10) && (elems[10].length() == 10)) - m_startDate = DateStrToInt(elems[10].c_str()); + startDate = DateStrToInt(elems[10].c_str()); else - m_startDate = 20150101; + startDate = 20150101; if ((elems.size() > 11) && (elems[11].length() == 10)) - m_endDate = DateStrToInt(elems[11].c_str()); + endDate = DateStrToInt(elems[11].c_str()); else - m_startDate = 20991231; - - m_state = SS_IDLE; + startDate = 20991231; return 1; } -void ScheduleEntry::CalculateTimes(void) -{ - if (!m_enabled) - { - m_nextStartTime = 0; - m_nextEndTime = 0; - m_thisStartTime = 0; - m_thisEndTime = 0; - - return; - } - - time_t currTime = time(NULL); - struct tm now; - int nextStartDate = GetCurrentDateInt(); - - localtime_r(&currTime, &now); - - if (CurrentDateInRange(m_startDate, m_endDate)) - { - if (now.tm_hour > m_endHour) - { - nextStartDate = GetCurrentDateInt(1); - } - else if (now.tm_hour < m_startHour) - { - } - else if (now.tm_hour == m_startHour) - { - } - } - else - { - nextStartDate = m_startDate; - } - - - - if (m_state != ScheduleEntry::SS_IDLE) - { - m_thisStartTime = m_nextStartTime; - m_thisEndTime = m_nextEndTime; - } - - return; -} - - diff --git a/src/ScheduleEntry.h b/src/ScheduleEntry.h index 6f8895a95..d1cd73cfc 100644 --- a/src/ScheduleEntry.h +++ b/src/ScheduleEntry.h @@ -39,47 +39,23 @@ class ScheduleEntry { ~ScheduleEntry(); int LoadFromString(std::string entryStr); - void CalculateTimes(void); - - typedef enum { - SS_IDLE = 0, - SS_PLAYING, - SS_STOPPING - } ScheduleState; - - int m_enabled; - std::string m_playlistName; - int m_priority; - int m_repeating; - int m_dayIndex; - int m_weeklySecondCount; - int m_weeklyStartSeconds[DAYS_PER_WEEK]; - int m_weeklyEndSeconds[DAYS_PER_WEEK]; - int m_startTime; // HHMMSS format as an integer - int m_endTime; // HHMMSS format as an integer - int m_startHour; - int m_startMinute; - int m_startSecond; - int m_endHour; - int m_endMinute; - int m_endSecond; - int m_startDate; // YYYYMMDD format as an integer - int m_endDate; // YYYYMMDD format as an integer - - ScheduleState m_state; - - // The last start/stop block - time_t m_lastStartTime; - time_t m_lastEndTime; - - // The current start/stop block. if not playing then == next - time_t m_thisStartTime; - time_t m_thisEndTime; - - // The next scheduled start/stop block - time_t m_nextStartTime; - time_t m_nextEndTime; + bool enabled; + std::string playlist; + + int dayIndex; + int startHour; + int startMinute; + int startSecond; + int endHour; + int endMinute; + int endSecond; + bool repeat; + int weeklySecondCount; + int weeklyStartSeconds[DAYS_PER_WEEK]; + int weeklyEndSeconds[DAYS_PER_WEEK]; + int startDate; // YYYYMMDD format as an integer + int endDate; // YYYYMMDD format as an integer }; #endif /* _SCHEDULEENTRY_H */ diff --git a/src/Scheduler.cpp b/src/Scheduler.cpp index 4bf4ed98d..0273175d9 100644 --- a/src/Scheduler.cpp +++ b/src/Scheduler.cpp @@ -47,8 +47,7 @@ Scheduler *scheduler = NULL; ///////////////////////////////////////////////////////////////////////////// Scheduler::Scheduler() - : m_ScheduleEntryCount(0), - m_CurrentScheduleHasbeenLoaded(0), + : m_CurrentScheduleHasbeenLoaded(0), m_NextScheduleHasbeenLoaded(0), m_nowWeeklySeconds2(0), m_lastLoadDate(0), @@ -58,7 +57,6 @@ Scheduler::Scheduler() m_runThread(0), m_threadIsRunning(0) { - bzero(&m_currentSchedulePlaylist, sizeof(m_currentSchedulePlaylist)); pthread_mutex_init(&m_scheduleLock, NULL); } @@ -119,11 +117,11 @@ void Scheduler::CheckIfShouldBePlayingNow(int ignoreRepeat) int nowWeeklySeconds = GetWeeklySeconds(now.tm_wday, now.tm_hour, now.tm_min, now.tm_sec); LoadScheduleFromFile(); - for(i=0;iPlay(m_Schedule[m_currentSchedulePlaylist.ScheduleEntryIndex].playList, + playlist->Play(m_Schedule[m_currentSchedulePlaylist.ScheduleEntryIndex].playlist.c_str(), 0, m_Schedule[m_currentSchedulePlaylist.ScheduleEntryIndex].repeat, 1); } } @@ -168,13 +166,13 @@ std::string Scheduler::GetPlaylistThatShouldBePlaying(int &repeat) if (playlist->getPlaylistStatus() != FPP_STATUS_IDLE) { repeat = m_Schedule[m_currentSchedulePlaylist.ScheduleEntryIndex].repeat; - return m_Schedule[m_currentSchedulePlaylist.ScheduleEntryIndex].playList; + return m_Schedule[m_currentSchedulePlaylist.ScheduleEntryIndex].playlist; } int nowWeeklySeconds = GetWeeklySeconds(now.tm_wday, now.tm_hour, now.tm_min, now.tm_sec); - for(i=0;i= m_Schedule[i].weeklyStartSeconds[j]) && (nowWeeklySeconds < m_Schedule[i].weeklyEndSeconds[j]))) { repeat = m_Schedule[i].repeat; - return m_Schedule[i].playList; + return m_Schedule[i].playlist; } } } @@ -208,9 +206,9 @@ int Scheduler::GetNextScheduleEntry(int *weeklySecondIndex) localtime_r(&currTime, &now); int nowWeeklySeconds = GetWeeklySeconds(now.tm_wday, now.tm_hour, now.tm_min, now.tm_sec); - for(i=0;i= 0) - { - GetNextPlaylistText(p); - GetNextScheduleStartText(t); - LogDebug(VB_SCHEDULE, "Next Scheduled Playlist is index %d: '%s' for %s\n", m_nextSchedulePlaylist.ScheduleEntryIndex, p, t); - } + m_nextSchedulePlaylist.ScheduleEntryIndex = GetNextScheduleEntry(&m_nextSchedulePlaylist.weeklySecondIndex); + m_NextScheduleHasbeenLoaded = 1; + + if (m_nextSchedulePlaylist.ScheduleEntryIndex != SCHEDULE_INDEX_INVALID) { + char t[64]; + char p[64]; + GetNextPlaylistText(p); + GetNextScheduleStartText(t); + LogDebug(VB_SCHEDULE, "Next Scheduled Playlist is index %d: '%s' for %s\n", m_nextSchedulePlaylist.ScheduleEntryIndex, p, t); + } } void Scheduler::GetSunInfo(int set, int &hour, int &minute, int &second) @@ -317,7 +315,7 @@ void Scheduler::GetSunInfo(int set, int &hour, int &minute, int &second) LogDebug(VB_SCHEDULE, "Sunrise is at %02d:%02d:%02d\n", hour, minute, second); } -void Scheduler::SetScheduleEntrysWeeklyStartAndEndSeconds(ScheduleEntryStruct * entry) +void Scheduler::SetScheduleEntrysWeeklyStartAndEndSeconds(ScheduleEntry *entry) { if (entry->dayIndex & INX_DAY_MASK) { @@ -578,7 +576,7 @@ void Scheduler::PlayListLoadCheck(void) m_Schedule[m_currentSchedulePlaylist.ScheduleEntryIndex].endHour, m_Schedule[m_currentSchedulePlaylist.ScheduleEntryIndex].endMinute, m_Schedule[m_currentSchedulePlaylist.ScheduleEntryIndex].endSecond, - m_Schedule[m_currentSchedulePlaylist.ScheduleEntryIndex].playList, + m_Schedule[m_currentSchedulePlaylist.ScheduleEntryIndex].playlist.c_str(), m_currentSchedulePlaylist.endWeeklySeconds - m_currentSchedulePlaylist.startWeeklySeconds); LogDebug(VB_SCHEDULE, "NowSecs = %d, CurrStartSecs = %d, CurrEndSecs = %d (%d seconds away)\n", nowWeeklySeconds, m_currentSchedulePlaylist.startWeeklySeconds, m_currentSchedulePlaylist.endWeeklySeconds, displayDiff); @@ -586,7 +584,7 @@ void Scheduler::PlayListLoadCheck(void) if ((playlist->getPlaylistStatus() != FPP_STATUS_IDLE) && (!playlist->WasScheduled())) playlist->StopNow(1); - playlist->Play(m_Schedule[m_currentSchedulePlaylist.ScheduleEntryIndex].playList, + playlist->Play(m_Schedule[m_currentSchedulePlaylist.ScheduleEntryIndex].playlist.c_str(), 0, m_Schedule[m_currentSchedulePlaylist.ScheduleEntryIndex].repeat, 1); } } @@ -660,13 +658,13 @@ void Scheduler::LoadScheduleFromFile(void) FILE *fp; char buf[512]; char *s; - m_ScheduleEntryCount=0; + int scheduleEntryCount = 0; int day; m_lastLoadDate = GetCurrentDateInt(); pthread_mutex_lock(&m_scheduleLock); - m_schedule.clear(); + m_Schedule.clear(); LogInfo(VB_SCHEDULE, "Loading Schedule from %s\n",getScheduleFile()); fp = fopen((const char *)getScheduleFile(), "r"); @@ -678,82 +676,33 @@ void Scheduler::LoadScheduleFromFile(void) { ScheduleEntry scheduleEntry; scheduleEntry.LoadFromString(buf); - m_schedule.push_back(scheduleEntry); - - while (isspace(buf[strlen(buf)-1])) - buf[strlen(buf)-1] = 0x0; - - // Enable - s=strtok(buf,","); - m_Schedule[m_ScheduleEntryCount].enable = atoi(s); - // Playlist Name - s=strtok(NULL,","); - strcpy(m_Schedule[m_ScheduleEntryCount].playList,s); - // Start Day index - s=strtok(NULL,","); - m_Schedule[m_ScheduleEntryCount].dayIndex = atoi(s); - // Start Hour - s=strtok(NULL,","); - m_Schedule[m_ScheduleEntryCount].startHour = atoi(s); - // Start Minute - s=strtok(NULL,","); - m_Schedule[m_ScheduleEntryCount].startMinute = atoi(s); - // Start Second - s=strtok(NULL,","); - m_Schedule[m_ScheduleEntryCount].startSecond = atoi(s); - // End Hour - s=strtok(NULL,","); - m_Schedule[m_ScheduleEntryCount].endHour = atoi(s); - // End Minute - s=strtok(NULL,","); - m_Schedule[m_ScheduleEntryCount].endMinute = atoi(s); - // End Second - s=strtok(NULL,","); - m_Schedule[m_ScheduleEntryCount].endSecond = atoi(s); - // Repeat - s=strtok(NULL,","); - m_Schedule[m_ScheduleEntryCount].repeat = atoi(s); - - // Start Date - s=strtok(NULL,","); - if (s && strcmp(s, "")) - m_Schedule[m_ScheduleEntryCount].startDate = DateStrToInt(s); - else - m_Schedule[m_ScheduleEntryCount].startDate = 20140101; - - // End Date - s=strtok(NULL,","); - if (s && strcmp(s, "")) - m_Schedule[m_ScheduleEntryCount].endDate = DateStrToInt(s); - else - m_Schedule[m_ScheduleEntryCount].endDate = 20991231; // Check for sunrise/sunset flags - if (m_Schedule[m_ScheduleEntryCount].startHour == 25) + if (scheduleEntry.startHour == 25) GetSunInfo( 0, - m_Schedule[m_ScheduleEntryCount].startHour, - m_Schedule[m_ScheduleEntryCount].startMinute, - m_Schedule[m_ScheduleEntryCount].startSecond); - else if (m_Schedule[m_ScheduleEntryCount].startHour == 26) + scheduleEntry.startHour, + scheduleEntry.startMinute, + scheduleEntry.startSecond); + else if (scheduleEntry.startHour == 26) GetSunInfo( 1, - m_Schedule[m_ScheduleEntryCount].startHour, - m_Schedule[m_ScheduleEntryCount].startMinute, - m_Schedule[m_ScheduleEntryCount].startSecond); + scheduleEntry.startHour, + scheduleEntry.startMinute, + scheduleEntry.startSecond); - if (m_Schedule[m_ScheduleEntryCount].endHour == 25) + if (scheduleEntry.endHour == 25) GetSunInfo( 0, - m_Schedule[m_ScheduleEntryCount].endHour, - m_Schedule[m_ScheduleEntryCount].endMinute, - m_Schedule[m_ScheduleEntryCount].endSecond); - else if (m_Schedule[m_ScheduleEntryCount].endHour == 26) + scheduleEntry.endHour, + scheduleEntry.endMinute, + scheduleEntry.endSecond); + else if (scheduleEntry.endHour == 26) GetSunInfo( 1, - m_Schedule[m_ScheduleEntryCount].endHour, - m_Schedule[m_ScheduleEntryCount].endMinute, - m_Schedule[m_ScheduleEntryCount].endSecond); + scheduleEntry.endHour, + scheduleEntry.endMinute, + scheduleEntry.endSecond); // Set WeeklySecond start and end times - SetScheduleEntrysWeeklyStartAndEndSeconds(&m_Schedule[m_ScheduleEntryCount]); - m_ScheduleEntryCount++; + SetScheduleEntrysWeeklyStartAndEndSeconds(&scheduleEntry); + m_Schedule.push_back(scheduleEntry); } fclose(fp); @@ -771,12 +720,11 @@ void Scheduler::SchedulePrint(void) LogInfo(VB_SCHEDULE, "Current Schedule: (Status: '+' = Enabled, '-' = Disabled, '!' = Outside Date Range, '*' = Repeat)\n"); LogInfo(VB_SCHEDULE, "St Start & End Dates Days Start & End Times Playlist\n"); LogInfo(VB_SCHEDULE, "--- ----------------------- ------------ ------------------- ---------------------------------------------\n"); - for(i=0;i= currentDate) && - (m_Schedule[i].endDate < schedDate)) - { + (m_Schedule[i].endDate < schedDate)) { index = i; schedDate = m_Schedule[i].endDate; } @@ -847,16 +793,12 @@ void Scheduler::GetNextScheduleStartText(char * txt) if (!m_NextScheduleHasbeenLoaded) return; - if (m_nextSchedulePlaylist.ScheduleEntryIndex >= 0) - { + if (m_nextSchedulePlaylist.ScheduleEntryIndex >= 0) { GetScheduleEntryStartText(m_nextSchedulePlaylist.ScheduleEntryIndex,m_nextSchedulePlaylist.weeklySecondIndex,txt); - } - else - { + } else { char dayText[16]; int found = FindNextStartingScheduleIndex(); - if (found >= 0) - { + if (found >= 0) { GetDayTextFromDayIndex(m_Schedule[found].dayIndex,dayText); sprintf(txt, "%04d-%02d-%02d @ %02d:%02d:%02d - (%s)\n", (int)(m_Schedule[found].startDate / 10000), @@ -877,14 +819,14 @@ void Scheduler::GetNextPlaylistText(char * txt) if (m_nextSchedulePlaylist.ScheduleEntryIndex >= 0) { - strcpy(txt,m_Schedule[m_nextSchedulePlaylist.ScheduleEntryIndex].playList); + strcpy(txt, m_Schedule[m_nextSchedulePlaylist.ScheduleEntryIndex].playlist.c_str()); } else { int found = FindNextStartingScheduleIndex(); if (found >= 0) - strcpy(txt,m_Schedule[found].playList); + strcpy(txt, m_Schedule[found].playlist.c_str()); } } diff --git a/src/Scheduler.h b/src/Scheduler.h index ef62e19e4..782ec94d0 100644 --- a/src/Scheduler.h +++ b/src/Scheduler.h @@ -33,7 +33,6 @@ #include "ScheduleEntry.h" #define SCHEDULE_INDEX_INVALID -1 -#define MAX_SCHEDULE_ENTRIES 64 #define SECONDS_PER_MINUTE 60 #define SECONDS_PER_HOUR 3600 #define SECONDS_PER_DAY 86400 @@ -65,31 +64,17 @@ #define INX_DAY_MASK_FRIDAY 0x00200 #define INX_DAY_MASK_SATURDAY 0x00100 -typedef struct{ - char enable; - char playList[128]; - int dayIndex; - int startHour; - int startMinute; - int startSecond; - int endHour; - int endMinute; - int endSecond; - char repeat; - int weeklySecondCount; - int weeklyStartSeconds[DAYS_PER_WEEK]; - int weeklyEndSeconds[DAYS_PER_WEEK]; - int startDate; // YYYYMMDD format as an integer - int endDate; // YYYYMMDD format as an integer -} ScheduleEntryStruct; - -typedef struct { - int ScheduleEntryIndex; - int weeklySecondIndex; - int startWeeklySeconds; - int endWeeklySeconds; -} SchedulePlaylistDetails; +class SchedulePlaylistDetails { +public: + SchedulePlaylistDetails() {} + ~SchedulePlaylistDetails() {} + + int ScheduleEntryIndex = 0; + int weeklySecondIndex = 0; + int startWeeklySeconds = 0; + int endWeeklySeconds = 0; +}; class Scheduler { public: @@ -110,7 +95,7 @@ class Scheduler { void LoadCurrentScheduleInfo(void); void LoadNextScheduleInfo(void); void GetSunInfo(int set, int &hour, int &minute, int &second); - void SetScheduleEntrysWeeklyStartAndEndSeconds(ScheduleEntryStruct * entry); + void SetScheduleEntrysWeeklyStartAndEndSeconds(ScheduleEntry *entry); void PlayListLoadCheck(void); void PlayListStopCheck(void); void LoadScheduleFromFile(void); @@ -123,7 +108,6 @@ class Scheduler { void GetDayTextFromDayIndex(int index,char * txt); - int m_ScheduleEntryCount; unsigned char m_CurrentScheduleHasbeenLoaded; unsigned char m_NextScheduleHasbeenLoaded; int m_nowWeeklySeconds2; @@ -138,9 +122,8 @@ class Scheduler { int m_threadIsRunning; pthread_mutex_t m_scheduleLock; - std::vector m_schedule; + std::vector m_Schedule; - ScheduleEntryStruct m_Schedule[MAX_SCHEDULE_ENTRIES]; SchedulePlaylistDetails m_currentSchedulePlaylist; SchedulePlaylistDetails m_nextSchedulePlaylist; }; diff --git a/src/Sequence.cpp b/src/Sequence.cpp index 921b56014..b999b352d 100644 --- a/src/Sequence.cpp +++ b/src/Sequence.cpp @@ -571,8 +571,10 @@ void Sequence::CloseSequenceFile(void) { if ((!IsEffectRunning()) && ((getFPPmode() != REMOTE_MODE) && (playlist->getPlaylistStatus() != FPP_STATUS_PLAYLIST_PLAYING)) || - (getSettingInt("blankBetweenSequences"))) + (getSettingInt("blankBetweenSequences"))) { SendBlankingData(); + } + } /* diff --git a/src/Warnings.cpp b/src/Warnings.cpp index 7573b6972..0c6516a5b 100644 --- a/src/Warnings.cpp +++ b/src/Warnings.cpp @@ -1,22 +1,43 @@ - +#include #include "Warnings.h" -std::set WarningHolder::warnings; +std::map WarningHolder::warnings; std::mutex WarningHolder::warningsLock; + + + void WarningHolder::AddWarning(const std::string &w) { std::unique_lock lock(warningsLock); - warnings.insert(w); + warnings[w] = -1; } +void WarningHolder::AddWarningTimeout(const std::string &w, int toSeconds) { + std::unique_lock lock(warningsLock); + auto nowtime = std::chrono::steady_clock::now(); + int seconds = std::chrono::duration_cast(nowtime.time_since_epoch()).count(); + warnings[w] = seconds + toSeconds; +} + + void WarningHolder::RemoveWarning(const std::string &w) { std::unique_lock lock(warningsLock); warnings.erase(w); } void WarningHolder::AddWarningsToStatus(Json::Value &root) { + auto nowtime = std::chrono::steady_clock::now(); + int now = std::chrono::duration_cast(nowtime.time_since_epoch()).count(); + std::list remove; std::unique_lock lock(warningsLock); for (auto &a : warnings) { - root["warnings"].append(a); + if (a.second == -1 || a.second > now) { + root["warnings"].append(a.first); + } else { + remove.push_back(a.first); + } + } + for (auto &a : remove) { + warnings.erase(a); } } diff --git a/src/Warnings.h b/src/Warnings.h index dd41025a8..05678bda5 100644 --- a/src/Warnings.h +++ b/src/Warnings.h @@ -16,7 +16,7 @@ #ifndef _FPP_WARNINGS_H #define _FPP_WARNINGS_H -#include +#include #include #include @@ -26,11 +26,13 @@ class WarningHolder { static void AddWarning(const std::string &w); static void RemoveWarning(const std::string &w); + static void AddWarningTimeout(const std::string &w, int seconds); + static void AddWarningsToStatus(Json::Value &root); private: static std::mutex warningsLock; - static std::set warnings; + static std::map warnings; }; #endif diff --git a/src/channeloutput/ArtNet.cpp b/src/channeloutput/ArtNet.cpp index 312e5be51..4ef1ebdeb 100644 --- a/src/channeloutput/ArtNet.cpp +++ b/src/channeloutput/ArtNet.cpp @@ -101,6 +101,11 @@ static struct iovec ArtNetSyncIovecs = { (void*)ArtNetSyncPacket, ARTNET_SYNC_PA static struct sockaddr_in ArtNetSyncAddress; +static const std::string ARTNETTYPE = "ArtNet"; + +const std::string &ArtNetOutputData::GetOutputTypeString() const { + return ARTNETTYPE; +} ArtNetOutputData::ArtNetOutputData(const Json::Value &config) : UDPOutputData(config), sequenceNumber(1), universeCount(1) { @@ -111,7 +116,7 @@ ArtNetOutputData::ArtNetOutputData(const Json::Value &config) memset((char *) &ArtNetSyncAddress, 0, sizeof(sockaddr_in)); ArtNetSyncAddress.sin_family = AF_INET; - ArtNetSyncAddress.sin_port = htons(0); + ArtNetSyncAddress.sin_port = htons(ARTNET_DEST_PORT); ArtNetSyncAddress.sin_addr.s_addr = inet_addr("255.255.255.255"); universe = config["id"].asInt(); diff --git a/src/channeloutput/ArtNet.h b/src/channeloutput/ArtNet.h index bf77a094d..a6b65304c 100644 --- a/src/channeloutput/ArtNet.h +++ b/src/channeloutput/ArtNet.h @@ -36,17 +36,19 @@ class ArtNetOutputData : public UDPOutputData { public: - ArtNetOutputData(const Json::Value &config); + explicit ArtNetOutputData(const Json::Value &config); virtual ~ArtNetOutputData(); - virtual bool IsPingable(); - virtual void PrepareData(unsigned char *channelData); - virtual void CreateMessages(std::vector &ipMsgs); - virtual void CreateBroadcastMessages(std::vector &bMsgs); - virtual void AddPostDataMessages(std::vector &bMsgs); - virtual void DumpConfig(); - virtual void GetRequiredChannelRange(int &min, int & max); + virtual bool IsPingable() override; + virtual void PrepareData(unsigned char *channelData) override; + virtual void CreateMessages(std::vector &ipMsgs) override; + virtual void CreateBroadcastMessages(std::vector &bMsgs) override; + virtual void AddPostDataMessages(std::vector &bMsgs) override; + virtual void DumpConfig() override; + virtual void GetRequiredChannelRange(int &min, int & max) override; + virtual const std::string &GetOutputTypeString() const override; + int universe; int universeCount; int priority; diff --git a/src/channeloutput/BBB48String.h b/src/channeloutput/BBB48String.h index 4fb29fe1d..e4b84ca5b 100644 --- a/src/channeloutput/BBB48String.h +++ b/src/channeloutput/BBB48String.h @@ -51,16 +51,16 @@ typedef struct { class BBB48StringOutput : public ChannelOutputBase { public: BBB48StringOutput(unsigned int startChannel, unsigned int channelCount); - ~BBB48StringOutput(); + virtual ~BBB48StringOutput(); - int Init(Json::Value config); - int Close(void); + virtual int Init(Json::Value config) override; + virtual int Close(void) override; - int SendData(unsigned char *channelData); - void PrepData(unsigned char *channelData); - void DumpConfig(void); + virtual int SendData(unsigned char *channelData) override; + virtual void PrepData(unsigned char *channelData) override; + virtual void DumpConfig(void) override; - virtual void GetRequiredChannelRanges(const std::function &addRange); + virtual void GetRequiredChannelRanges(const std::function &addRange) override; private: void StopPRU(bool wait = true); diff --git a/src/channeloutput/BBBMatrix.cpp b/src/channeloutput/BBBMatrix.cpp index 6ef0254e9..31a20e7a4 100644 --- a/src/channeloutput/BBBMatrix.cpp +++ b/src/channeloutput/BBBMatrix.cpp @@ -253,8 +253,8 @@ class NoInterleaveHandler : public InterleaveHandler { NoInterleaveHandler() {} virtual ~NoInterleaveHandler() {} - virtual void mapRow(int &y) {} - virtual void mapCol(int y, int &x) {} + virtual void mapRow(int &y) override {} + virtual void mapCol(int y, int &x) override {} }; class SimpleInterleaveHandler : public InterleaveHandler { public: @@ -262,12 +262,12 @@ class SimpleInterleaveHandler : public InterleaveHandler { : InterleaveHandler(), m_interleave(interleave), m_panelHeight(ph), m_panelWidth(pw), m_panelScan(ps), m_flipRows(flip) {} virtual ~SimpleInterleaveHandler() {} - virtual void mapRow(int &y) { + virtual void mapRow(int &y) override { while (y >= m_panelScan) { y -= m_panelScan; } } - virtual void mapCol(int y, int &x) { + virtual void mapCol(int y, int &x) override { int whichInt = x / m_interleave; if (m_flipRows) { if (y & m_panelScan) { @@ -295,12 +295,12 @@ class ZigZagInterleaveHandler : public InterleaveHandler { : InterleaveHandler(), m_interleave(interleave), m_panelHeight(ph), m_panelWidth(pw), m_panelScan(ps) {} virtual ~ZigZagInterleaveHandler() {} - virtual void mapRow(int &y) { + virtual void mapRow(int &y) override { while (y >= m_panelScan) { y -= m_panelScan; } } - virtual void mapCol(int y, int &x) { + virtual void mapCol(int y, int &x) override { int whichInt = x / m_interleave; int offInInt = x % m_interleave; int mult = y / m_panelScan; diff --git a/src/channeloutput/BBBMatrix.h b/src/channeloutput/BBBMatrix.h index cf9179183..c2feb5662 100644 --- a/src/channeloutput/BBBMatrix.h +++ b/src/channeloutput/BBBMatrix.h @@ -54,16 +54,16 @@ class BBBMatrix : public ChannelOutputBase { BBBMatrix(unsigned int startChannel, unsigned int channelCount); virtual ~BBBMatrix(); - int Init(Json::Value config); - int Close(void); + virtual int Init(Json::Value config) override; + virtual int Close(void) override; - void PrepData(unsigned char *channelData); + virtual void PrepData(unsigned char *channelData) override; - int SendData(unsigned char *channelData); + virtual int SendData(unsigned char *channelData) override; - void DumpConfig(void); + virtual void DumpConfig(void) override; - virtual void GetRequiredChannelRanges(const std::function &addRange); + virtual void GetRequiredChannelRanges(const std::function &addRange) override; private: void calcBrightnessFlags(std::vector &sargs); diff --git a/src/channeloutput/BBBSerial.h b/src/channeloutput/BBBSerial.h index 92418e4f2..d8f84ea79 100644 --- a/src/channeloutput/BBBSerial.h +++ b/src/channeloutput/BBBSerial.h @@ -48,16 +48,16 @@ typedef struct { class BBBSerialOutput : public ThreadedChannelOutputBase { public: BBBSerialOutput(unsigned int startChannel, unsigned int channelCount); - ~BBBSerialOutput(); + virtual ~BBBSerialOutput(); - int Init(Json::Value config); - int Close(void); + virtual int Init(Json::Value config) override; + virtual int Close(void) override; - int RawSendData(unsigned char *channelData); + virtual int RawSendData(unsigned char *channelData) override; - void DumpConfig(void); + virtual void DumpConfig(void) override; - virtual void GetRequiredChannelRanges(const std::function &addRange); + virtual void GetRequiredChannelRanges(const std::function &addRange) override; private: int m_outputs; int m_pixelnet; diff --git a/src/channeloutput/ColorLight-5a-75.h b/src/channeloutput/ColorLight-5a-75.h index f830c8bff..fbb4685a0 100644 --- a/src/channeloutput/ColorLight-5a-75.h +++ b/src/channeloutput/ColorLight-5a-75.h @@ -41,17 +41,17 @@ class ColorLight5a75Output : public ChannelOutputBase { public: ColorLight5a75Output(unsigned int startChannel, unsigned int channelCount); - ~ColorLight5a75Output(); + virtual ~ColorLight5a75Output(); - virtual int Init(Json::Value config); - virtual int Close(void); + virtual int Init(Json::Value config) override; + virtual int Close(void) override; - virtual void PrepData(unsigned char *channelData); - virtual int SendData(unsigned char *channelData); + virtual void PrepData(unsigned char *channelData) override; + virtual int SendData(unsigned char *channelData) override; - void DumpConfig(void); + virtual void DumpConfig(void) override; - virtual void GetRequiredChannelRanges(const std::function &addRange); + virtual void GetRequiredChannelRanges(const std::function &addRange) override; private: void SetHostMACs(void *data); diff --git a/src/channeloutput/DDP.cpp b/src/channeloutput/DDP.cpp index 1c21cfa7e..590981924 100644 --- a/src/channeloutput/DDP.cpp +++ b/src/channeloutput/DDP.cpp @@ -138,6 +138,12 @@ #define DDP_PACKET_LEN (DDP_HEADER_LEN + DDP_CHANNELS_PER_PACKET) +static const std::string DDPTYPE = "DDP"; + +const std::string &DDPOutputData::GetOutputTypeString() const { + return DDPTYPE; +} + DDPOutputData::DDPOutputData(const Json::Value &config) : UDPOutputData(config), sequenceNumber(1) { memset((char *) &ddpAddress, 0, sizeof(sockaddr_in)); ddpAddress.sin_family = AF_INET; @@ -196,6 +202,7 @@ DDPOutputData::~DDPOutputData() { for (int x = 0; x < pktCount; x++) { free(ddpBuffers[x]); } + free(ddpBuffers); free(ddpIovecs); } diff --git a/src/channeloutput/DDP.h b/src/channeloutput/DDP.h index dbe47d9de..18ea57795 100644 --- a/src/channeloutput/DDP.h +++ b/src/channeloutput/DDP.h @@ -32,14 +32,16 @@ class DDPOutputData : public UDPOutputData { public: - DDPOutputData(const Json::Value &config); + explicit DDPOutputData(const Json::Value &config); virtual ~DDPOutputData(); - virtual bool IsPingable() { return true; } - virtual void PrepareData(unsigned char *channelData); - virtual void CreateMessages(std::vector &ipMsgs); - virtual void DumpConfig(); + virtual bool IsPingable() override { return true; } + virtual void PrepareData(unsigned char *channelData) override; + virtual void CreateMessages(std::vector &ipMsgs) override; + virtual void DumpConfig() override; + virtual const std::string &GetOutputTypeString() const override; + char sequenceNumber; sockaddr_in ddpAddress; diff --git a/src/channeloutput/DebugOutput.h b/src/channeloutput/DebugOutput.h index 7d1183790..33c964885 100644 --- a/src/channeloutput/DebugOutput.h +++ b/src/channeloutput/DebugOutput.h @@ -39,22 +39,22 @@ class DebugOutput : public ChannelOutputBase { public: DebugOutput(unsigned int startChannel, unsigned int channelCount); - ~DebugOutput(); + virtual ~DebugOutput(); virtual int Init(Json::Value config) override; // Close the derived class. This method must also call the // base class Close() method. - int Close(void); + virtual int Close(void) override; // Main routine to send channel data out - int SendData(unsigned char *channelData); + virtual int SendData(unsigned char *channelData) override; // Dump the config variables for debugging. This method must // also call the base class DumpConfig() method. - void DumpConfig(void); + virtual void DumpConfig(void) override; - virtual void GetRequiredChannelRanges(const std::function &addRange) { + virtual void GetRequiredChannelRanges(const std::function &addRange) override { addRange(m_startChannel, m_startChannel + m_channelCount - 1); } diff --git a/src/channeloutput/E131.cpp b/src/channeloutput/E131.cpp index cb291b364..8985f8c95 100644 --- a/src/channeloutput/E131.cpp +++ b/src/channeloutput/E131.cpp @@ -70,6 +70,11 @@ const unsigned char E131header[] = { }; +static const std::string E131TYPE = "e1.31"; + +const std::string &E131OutputData::GetOutputTypeString() const { + return E131TYPE; +} E131OutputData::E131OutputData(const Json::Value &config) : UDPOutputData(config), E131sequenceNumber(1), universeCount(1) { diff --git a/src/channeloutput/E131.h b/src/channeloutput/E131.h index 10088513a..7da3d9a93 100644 --- a/src/channeloutput/E131.h +++ b/src/channeloutput/E131.h @@ -35,15 +35,16 @@ class E131OutputData : public UDPOutputData { public: - E131OutputData(const Json::Value &config); + explicit E131OutputData(const Json::Value &config); virtual ~E131OutputData(); - virtual bool IsPingable(); - virtual void PrepareData(unsigned char *channelData); - virtual void CreateMessages(std::vector &ipMsgs); - virtual void DumpConfig(); - virtual void GetRequiredChannelRange(int &min, int & max); + virtual bool IsPingable() override; + virtual void PrepareData(unsigned char *channelData) override; + virtual void CreateMessages(std::vector &ipMsgs) override; + virtual void DumpConfig() override; + virtual void GetRequiredChannelRange(int &min, int & max) override; + virtual const std::string &GetOutputTypeString() const override; int universe; int universeCount; diff --git a/src/channeloutput/FBMatrix.cpp b/src/channeloutput/FBMatrix.cpp index 57c89b48c..31c3704e6 100644 --- a/src/channeloutput/FBMatrix.cpp +++ b/src/channeloutput/FBMatrix.cpp @@ -291,7 +291,7 @@ int FBMatrixOutput::Close(void) } if (m_frame) { - delete m_frame; + delete [] m_frame; m_frame = nullptr; } return ChannelOutputBase::Close(); @@ -336,7 +336,6 @@ void FBMatrixOutput::PrepData(unsigned char *channelData) { unsigned char *dR; unsigned char *dG; unsigned char *dB; - unsigned char *dA; int add = m_bpp / 8; for (int y = 0; y < m_height; y++) { @@ -362,7 +361,6 @@ void FBMatrixOutput::PrepData(unsigned char *channelData) { dR += add; dG += add; dB += add; - dA += add; } srow++; diff --git a/src/channeloutput/FBMatrix.h b/src/channeloutput/FBMatrix.h index b81ecf1bc..5c0d29a24 100644 --- a/src/channeloutput/FBMatrix.h +++ b/src/channeloutput/FBMatrix.h @@ -34,17 +34,17 @@ class FBMatrixOutput : public ChannelOutputBase { public: FBMatrixOutput(unsigned int startChannel, unsigned int channelCount); - ~FBMatrixOutput(); + virtual ~FBMatrixOutput(); - virtual int Init(Json::Value config); - int Close(void); + virtual int Init(Json::Value config) override; + virtual int Close(void) override; - int SendData(unsigned char *channelData); - void PrepData(unsigned char *channelData); + virtual int SendData(unsigned char *channelData) override; + virtual void PrepData(unsigned char *channelData) override; - void DumpConfig(void); + virtual void DumpConfig(void) override; - virtual void GetRequiredChannelRanges(const std::function &addRange); + virtual void GetRequiredChannelRanges(const std::function &addRange) override; private: int m_fbFd; diff --git a/src/channeloutput/FBVirtualDisplay.cpp b/src/channeloutput/FBVirtualDisplay.cpp index 2e8b1609d..53c7f2857 100644 --- a/src/channeloutput/FBVirtualDisplay.cpp +++ b/src/channeloutput/FBVirtualDisplay.cpp @@ -85,6 +85,10 @@ int FBVirtualDisplayOutput::Init(Json::Value config) if (!VirtualDisplayOutput::Init(config)) return 0; + if (m_virtualDisplay) { + free(m_virtualDisplay); + m_virtualDisplay = nullptr; + } m_device = "/dev/"; if (config.isMember("device")) @@ -192,9 +196,6 @@ int FBVirtualDisplayOutput::Init(Json::Value config) ioctl(m_ttyFd, KDSETMODE, KD_GRAPHICS); } - if (m_virtualDisplay) { - free(m_virtualDisplay); - } m_virtualDisplay = (unsigned char*)mmap(0, m_screenSize, PROT_READ | PROT_WRITE, MAP_SHARED, m_fbFd, 0); if ((char *)m_virtualDisplay == (char *)-1) @@ -204,6 +205,7 @@ int FBVirtualDisplayOutput::Init(Json::Value config) close(m_fbFd); return 0; } + memset(m_virtualDisplay, 0, m_screenSize); if (m_bpp == 16) { @@ -255,8 +257,6 @@ int FBVirtualDisplayOutput::Init(Json::Value config) } } - bzero(m_virtualDisplay, m_screenSize); - return InitializePixelMap(); } @@ -267,8 +267,10 @@ int FBVirtualDisplayOutput::Close(void) { LogDebug(VB_CHANNELOUT, "FBVirtualDisplayOutput::Close()\n"); - munmap(m_virtualDisplay, m_screenSize); - m_virtualDisplay = nullptr; + if (m_virtualDisplay) { + munmap(m_virtualDisplay, m_screenSize); + m_virtualDisplay = nullptr; + } if (m_device == "/dev/fb0") { diff --git a/src/channeloutput/FBVirtualDisplay.h b/src/channeloutput/FBVirtualDisplay.h index d34126d40..5439a015c 100644 --- a/src/channeloutput/FBVirtualDisplay.h +++ b/src/channeloutput/FBVirtualDisplay.h @@ -33,12 +33,12 @@ class FBVirtualDisplayOutput : protected VirtualDisplayOutput { public: FBVirtualDisplayOutput(unsigned int startChannel, unsigned int channelCount); - ~FBVirtualDisplayOutput(); + virtual ~FBVirtualDisplayOutput(); - int Init(Json::Value config); - int Close(void); + virtual int Init(Json::Value config) override; + virtual int Close(void) override; - int SendData(unsigned char *channelData); + virtual int SendData(unsigned char *channelData) override; private: int m_fbFd; diff --git a/src/channeloutput/GPIO.h b/src/channeloutput/GPIO.h index 40d67c734..0926929e5 100644 --- a/src/channeloutput/GPIO.h +++ b/src/channeloutput/GPIO.h @@ -34,16 +34,16 @@ class GPIOOutput : public ChannelOutputBase { GPIOOutput(unsigned int startChannel, unsigned int channelCount); ~GPIOOutput(); - virtual int Init(Json::Value config); + virtual int Init(Json::Value config) override; - int Init(char *configStr); - int Close(void); + virtual int Init(char *configStr) override; + virtual int Close(void) override; - int SendData(unsigned char *channelData); + virtual int SendData(unsigned char *channelData) override; - void DumpConfig(void); + virtual void DumpConfig(void) override; - virtual void GetRequiredChannelRanges(const std::function &addRange) { + virtual void GetRequiredChannelRanges(const std::function &addRange) override { addRange(m_startChannel, m_startChannel); } diff --git a/src/channeloutput/GPIO595.h b/src/channeloutput/GPIO595.h index c34b0b8c0..9c8cec1f7 100644 --- a/src/channeloutput/GPIO595.h +++ b/src/channeloutput/GPIO595.h @@ -32,18 +32,18 @@ class GPIO595Output : public ThreadedChannelOutputBase { public: GPIO595Output(unsigned int startChannel, unsigned int channelCount); - ~GPIO595Output(); + virtual ~GPIO595Output(); - virtual int Init(Json::Value config); - int Init(char *configStr); + virtual int Init(Json::Value config) override; + virtual int Init(char *configStr) override; - int Close(void); + virtual int Close(void) override; - int RawSendData(unsigned char *channelData); + virtual int RawSendData(unsigned char *channelData) override; - void DumpConfig(void); + virtual void DumpConfig(void) override; - virtual void GetRequiredChannelRanges(const std::function &addRange) { + virtual void GetRequiredChannelRanges(const std::function &addRange) override { addRange(m_startChannel, m_startChannel + m_channelCount - 1); } diff --git a/src/channeloutput/GenericSPI.h b/src/channeloutput/GenericSPI.h index 5f6e63fee..07c2bf28f 100644 --- a/src/channeloutput/GenericSPI.h +++ b/src/channeloutput/GenericSPI.h @@ -32,19 +32,19 @@ class GenericSPIOutput : public ThreadedChannelOutputBase { public: GenericSPIOutput(unsigned int startChannel, unsigned int channelCount); - ~GenericSPIOutput(); + virtual ~GenericSPIOutput(); - virtual int Init(Json::Value config); + virtual int Init(Json::Value config) override; - int Init(char *configStr); + virtual int Init(char *configStr) override; - int Close(void); + virtual int Close(void) override; - int RawSendData(unsigned char *channelData); + virtual int RawSendData(unsigned char *channelData) override; - void DumpConfig(void); + virtual void DumpConfig(void) override; - virtual void GetRequiredChannelRanges(const std::function &addRange); + virtual void GetRequiredChannelRanges(const std::function &addRange) override; private: SPIUtils *m_spi; diff --git a/src/channeloutput/GenericSerial.h b/src/channeloutput/GenericSerial.h index f5c88f8b0..c9e2c2d3a 100644 --- a/src/channeloutput/GenericSerial.h +++ b/src/channeloutput/GenericSerial.h @@ -35,17 +35,17 @@ class GenericSerialOutput : public ThreadedChannelOutputBase { public: GenericSerialOutput(unsigned int startChannel, unsigned int channelCount); - ~GenericSerialOutput(); + virtual ~GenericSerialOutput(); - virtual int Init(Json::Value config); - int Init(char *configStr); + virtual int Init(Json::Value config) override; + virtual int Init(char *configStr) override; - int Close(void); + virtual int Close(void) override; - int RawSendData(unsigned char *channelData); + virtual int RawSendData(unsigned char *channelData) override; - void DumpConfig(void); - virtual void GetRequiredChannelRanges(const std::function &addRange); + virtual void DumpConfig(void) override; + virtual void GetRequiredChannelRanges(const std::function &addRange) override; private: std::string m_deviceName; diff --git a/src/channeloutput/GenericUDPOutput.cpp b/src/channeloutput/GenericUDPOutput.cpp index 7ba7b08c6..eab1c28f9 100644 --- a/src/channeloutput/GenericUDPOutput.cpp +++ b/src/channeloutput/GenericUDPOutput.cpp @@ -12,7 +12,7 @@ extern "C" { } } - +static const std::string GENERIC_UDP_TYPE = "GenericUDP"; class GenericUDPOutputData : public UDPOutputData { public: @@ -99,8 +99,13 @@ class GenericUDPOutputData : public UDPOutputData { udpIovecs[idx].iov_len = channelCount; } } - ~GenericUDPOutputData() { + virtual ~GenericUDPOutputData() { + } + + virtual const std::string &GetOutputTypeString() const override { + return GENERIC_UDP_TYPE; } + void addLittleEndian(std::vector &bytes, int v) { int a = v & 0xFF; int b = (v >> 8) & 0xFF; @@ -113,10 +118,10 @@ class GenericUDPOutputData : public UDPOutputData { bytes.push_back(a); bytes.push_back(b); } - virtual bool IsPingable() { + virtual bool IsPingable() override { return !isMulticast && !isBroadcast; }; - virtual void PrepareData(unsigned char *channelData) { + virtual void PrepareData(unsigned char *channelData) override { if (valid && active) { count++; int start = startChannel - 1; @@ -127,7 +132,7 @@ class GenericUDPOutputData : public UDPOutputData { } // unicast and multicast messages for data - virtual void CreateMessages(std::vector &udpMsgs) { + virtual void CreateMessages(std::vector &udpMsgs) override { if (!isBroadcast) { if (valid && active) { struct mmsghdr msg; @@ -145,7 +150,7 @@ class GenericUDPOutputData : public UDPOutputData { } } } - virtual void CreateBroadcastMessages(std::vector &bMsgs) { + virtual void CreateBroadcastMessages(std::vector &bMsgs) override { if (isBroadcast) { if (valid && active) { struct mmsghdr msg; @@ -164,7 +169,7 @@ class GenericUDPOutputData : public UDPOutputData { } } - virtual void DumpConfig() { + virtual void DumpConfig() override { } int port; diff --git a/src/channeloutput/GenericUDPOutput.h b/src/channeloutput/GenericUDPOutput.h index b99e4d58d..d5987569f 100644 --- a/src/channeloutput/GenericUDPOutput.h +++ b/src/channeloutput/GenericUDPOutput.h @@ -25,14 +25,14 @@ class GenericUDPOutput : public ChannelOutputBase { public: GenericUDPOutput(unsigned int startChannel, unsigned int channelCount); - ~GenericUDPOutput(); + virtual ~GenericUDPOutput(); - virtual int Init(Json::Value config); - virtual int Close(void); - virtual int SendData(unsigned char *channelData); + virtual int Init(Json::Value config) override; + virtual int Close(void) override; + virtual int SendData(unsigned char *channelData) override; - virtual void GetRequiredChannelRanges(const std::function &addRange); + virtual void GetRequiredChannelRanges(const std::function &addRange) override; private: }; #endif diff --git a/src/channeloutput/HTTPVirtualDisplay.cpp b/src/channeloutput/HTTPVirtualDisplay.cpp index 8c81c5707..876143b89 100644 --- a/src/channeloutput/HTTPVirtualDisplay.cpp +++ b/src/channeloutput/HTTPVirtualDisplay.cpp @@ -31,9 +31,14 @@ #include #include +#include +#include +#include +#include #include #include "common.h" +#include "fppversion_defines.h" #include "log.h" #include "HTTPVirtualDisplay.h" #include "Sequence.h" @@ -205,17 +210,6 @@ int HTTPVirtualDisplayOutput::Close(void) void HTTPVirtualDisplayOutput::ConnectionThread(void) { int client; - const char sseResp[] = "HTTP/1.1 200 OK\r\n" - "Content-Type: text/event-stream;charset=UTF-8\r\n" - "Transfer-Encoding: chunked\r\n" - "Connection: close\r\n" - "Date: Mon, 01 Jan 1970 00:00:00 GMT\r\n" - "Server: fppd\r\n" - "X-Powered-By: FPP/7.2.14\r\n" - "Cache-Control: no-cache, private\r\n" - "Access-Control-Allow-Origin: *\r\n" - "Access-Control-Allow-Credentials: true\r\n" - "\r\n"; while (m_running) { @@ -223,10 +217,35 @@ void HTTPVirtualDisplayOutput::ConnectionThread(void) if (client >= 0) { + auto t = std::time(nullptr); + auto tm = *std::localtime(&t); + std::stringstream sstr; + sstr << std::put_time(&tm, "%a %b %d %H:%M:%S %Z %Y"); + + std::string sseResp; + sseResp = + "HTTP/1.1 200 OK\r\n" + "Content-Type: text/event-stream;charset=UTF-8\r\n" + "Transfer-Encoding: chunked\r\n" + "Connection: close\r\n" + "Date: "; + sseResp += sstr.str(); + sseResp += + "\r\n" + "Server: fppd\r\n" + "X-Powered-By: FPP/" FPP_SOURCE_VERSION_STR "\r\n" + "Cache-Control: no-cache, private\r\n" + "Access-Control-Allow-Origin: *\r\n" + "Access-Control-Allow-Credentials: true\r\n" + "\r\n"; + + // Reset our display cache so we draw everything needed + bzero(m_virtualDisplay, m_screenSize); + std::unique_lock lock(m_connListLock); m_connList.push_back(client); - write(client, sseResp, strlen(sseResp)); + write(client, sseResp.c_str(), sseResp.length()); m_connListChanged = true; } @@ -240,7 +259,7 @@ void HTTPVirtualDisplayOutput::SelectThread(void) { fd_set active_fd_set; fd_set read_fd_set; - int selectResult; + int selectResult; struct timeval timeout; char buf[1024]; int bytesRead; diff --git a/src/channeloutput/HTTPVirtualDisplay.h b/src/channeloutput/HTTPVirtualDisplay.h index 79fc4b313..c70ed4fbd 100644 --- a/src/channeloutput/HTTPVirtualDisplay.h +++ b/src/channeloutput/HTTPVirtualDisplay.h @@ -36,13 +36,13 @@ class HTTPVirtualDisplayOutput : protected VirtualDisplayOutput { public: HTTPVirtualDisplayOutput(unsigned int startChannel, unsigned int channelCount); - ~HTTPVirtualDisplayOutput(); + virtual ~HTTPVirtualDisplayOutput(); - int Init(Json::Value config); - int Close(void); + virtual int Init(Json::Value config) override; + virtual int Close(void) override; - void PrepData(unsigned char *channelData); - int SendData(unsigned char *channelData); + virtual void PrepData(unsigned char *channelData) override; + virtual int SendData(unsigned char *channelData) override; void ConnectionThread(void); void SelectThread(void); diff --git a/src/channeloutput/Hill320.h b/src/channeloutput/Hill320.h index dabf68f14..f6e074917 100644 --- a/src/channeloutput/Hill320.h +++ b/src/channeloutput/Hill320.h @@ -32,16 +32,16 @@ class Hill320Output : public ThreadedChannelOutputBase { public: Hill320Output(unsigned int startChannel, unsigned int channelCount); - ~Hill320Output(); + virtual ~Hill320Output(); - int Init(Json::Value config); - int Close(void); + virtual int Init(Json::Value config) override; + virtual int Close(void) override; - int RawSendData(unsigned char *channelData); + virtual int RawSendData(unsigned char *channelData) override; - void DumpConfig(void); + virtual void DumpConfig(void) override; - virtual void GetRequiredChannelRanges(const std::function &addRange) { + virtual void GetRequiredChannelRanges(const std::function &addRange) override { addRange(m_startChannel, m_startChannel + m_channelCount - 1); } diff --git a/src/channeloutput/ILI9488.h b/src/channeloutput/ILI9488.h index da211266a..1209768d3 100644 --- a/src/channeloutput/ILI9488.h +++ b/src/channeloutput/ILI9488.h @@ -31,16 +31,16 @@ class ILI9488Output : public ThreadedChannelOutputBase { public: ILI9488Output(unsigned int startChannel, unsigned int channelCount); - ~ILI9488Output(); + virtual ~ILI9488Output(); - int Init(Json::Value config); - int Close(void); + virtual int Init(Json::Value config) override; + virtual int Close(void) override; - int RawSendData(unsigned char *channelData); + virtual int RawSendData(unsigned char *channelData) override; - void DumpConfig(void); + virtual void DumpConfig(void) override; - virtual void GetRequiredChannelRanges(const std::function &addRange) { + virtual void GetRequiredChannelRanges(const std::function &addRange) override { addRange(m_startChannel, m_startChannel + m_pixels * 3 - 1); } diff --git a/src/channeloutput/LOR.h b/src/channeloutput/LOR.h index 5bddb0d66..365790b3a 100644 --- a/src/channeloutput/LOR.h +++ b/src/channeloutput/LOR.h @@ -28,18 +28,18 @@ class LOROutputData; class LOROutput : public ChannelOutputBase { public: LOROutput(unsigned int startChannel, unsigned int channelCount); - ~LOROutput(); + virtual ~LOROutput(); - virtual int Init(Json::Value config); - int Init(char *configStr); + virtual int Init(Json::Value config) override; + virtual int Init(char *configStr) override; - int Close(void); + virtual int Close(void) override; - int SendData(unsigned char *channelData); + virtual int SendData(unsigned char *channelData) override; - void DumpConfig(void); + virtual void DumpConfig(void) override; - virtual void GetRequiredChannelRanges(const std::function &addRange); + virtual void GetRequiredChannelRanges(const std::function &addRange) override; private: LOROutputData *data; diff --git a/src/channeloutput/Linsn-RV9.h b/src/channeloutput/Linsn-RV9.h index 6570b6b6a..0d73f47d2 100644 --- a/src/channeloutput/Linsn-RV9.h +++ b/src/channeloutput/Linsn-RV9.h @@ -44,17 +44,17 @@ class LinsnRV9Output : public ChannelOutputBase { public: LinsnRV9Output(unsigned int startChannel, unsigned int channelCount); - ~LinsnRV9Output(); + virtual ~LinsnRV9Output(); - int Init(Json::Value config); - int Close(void); + virtual int Init(Json::Value config) override; + virtual int Close(void) override; - void PrepData(unsigned char *channelData); - int SendData(unsigned char *channelData); + virtual void PrepData(unsigned char *channelData) override; + virtual int SendData(unsigned char *channelData) override; - void DumpConfig(void); + virtual void DumpConfig(void) override; - virtual void GetRequiredChannelRanges(const std::function &addRange); + virtual void GetRequiredChannelRanges(const std::function &addRange) override; private: void HandShake(void); diff --git a/src/channeloutput/MAX7219Matrix.h b/src/channeloutput/MAX7219Matrix.h index e7eb2bc10..311afb2d3 100644 --- a/src/channeloutput/MAX7219Matrix.h +++ b/src/channeloutput/MAX7219Matrix.h @@ -34,16 +34,16 @@ class MAX7219MatrixOutput : public ChannelOutputBase { public: MAX7219MatrixOutput(unsigned int startChannel, unsigned int channelCount); - ~MAX7219MatrixOutput(); + virtual ~MAX7219MatrixOutput(); - int Init(Json::Value config); - int Close(void); + virtual int Init(Json::Value config) override; + virtual int Close(void) override; - int SendData(unsigned char *channelData); + virtual int SendData(unsigned char *channelData) override; - void DumpConfig(void); + virtual void DumpConfig(void) override; - virtual void GetRequiredChannelRanges(const std::function &addRange); + virtual void GetRequiredChannelRanges(const std::function &addRange) override; private: void WriteCommand(uint8_t cmd, uint8_t value); diff --git a/src/channeloutput/MCP23017.h b/src/channeloutput/MCP23017.h index 2f30bfbdd..0b71fea24 100644 --- a/src/channeloutput/MCP23017.h +++ b/src/channeloutput/MCP23017.h @@ -32,17 +32,17 @@ class MCP23017Output : public ChannelOutputBase { public: MCP23017Output(unsigned int startChannel, unsigned int channelCount); - ~MCP23017Output(); + virtual ~MCP23017Output(); - int Init(Json::Value config); - int Close(void); + virtual int Init(Json::Value config) override; + virtual int Close(void) override; - int SendData(unsigned char *channelData); + virtual int SendData(unsigned char *channelData) override; - void DumpConfig(void); + virtual void DumpConfig(void) override; - virtual void GetRequiredChannelRanges(const std::function &addRange) { + virtual void GetRequiredChannelRanges(const std::function &addRange) override { addRange(m_startChannel, m_startChannel + m_channelCount - 1); } diff --git a/src/channeloutput/OLAOutput.h b/src/channeloutput/OLAOutput.h index 58975d2d6..32a901f60 100644 --- a/src/channeloutput/OLAOutput.h +++ b/src/channeloutput/OLAOutput.h @@ -37,16 +37,16 @@ class OLAOutput : public ThreadedChannelOutputBase { public: OLAOutput(unsigned int startChannel, unsigned int channelCount); - ~OLAOutput(); + virtual ~OLAOutput(); - int Init(Json::Value config); - int Close(void); + virtual int Init(Json::Value config) override; + virtual int Close(void) override; - int RawSendData(unsigned char *channelData); + virtual int RawSendData(unsigned char *channelData) override; - void DumpConfig(void); + virtual void DumpConfig(void) override; - virtual void GetRequiredChannelRanges(const std::function &addRange); + virtual void GetRequiredChannelRanges(const std::function &addRange) override; private: ola::DmxBuffer m_buffer; diff --git a/src/channeloutput/RGBMatrix.h b/src/channeloutput/RGBMatrix.h index 97d489a2f..529a9c47f 100644 --- a/src/channeloutput/RGBMatrix.h +++ b/src/channeloutput/RGBMatrix.h @@ -43,18 +43,18 @@ using rgb_matrix::FrameCanvas; class RGBMatrixOutput : public ChannelOutputBase { public: RGBMatrixOutput(unsigned int startChannel, unsigned int channelCount); - ~RGBMatrixOutput(); + virtual ~RGBMatrixOutput(); - int Init(Json::Value config); - int Close(void); + virtual int Init(Json::Value config) override; + virtual int Close(void) override; - void PrepData(unsigned char *channelData); + virtual void PrepData(unsigned char *channelData) override; - int SendData(unsigned char *channelData); + virtual int SendData(unsigned char *channelData) override; - void DumpConfig(void); + virtual void DumpConfig(void) override; - virtual void GetRequiredChannelRanges(const std::function &addRange); + virtual void GetRequiredChannelRanges(const std::function &addRange) override; private: GPIO *m_gpio; diff --git a/src/channeloutput/RHL_DVI_E131.h b/src/channeloutput/RHL_DVI_E131.h index 649dab3eb..a73b684ac 100644 --- a/src/channeloutput/RHL_DVI_E131.h +++ b/src/channeloutput/RHL_DVI_E131.h @@ -33,16 +33,16 @@ class RHLDVIE131Output : public ChannelOutputBase { public: RHLDVIE131Output(unsigned int startChannel, unsigned int channelCount); - ~RHLDVIE131Output(); + virtual ~RHLDVIE131Output(); - int Init(Json::Value config); - int Close(void); + virtual int Init(Json::Value config) override; + virtual int Close(void) override; - int SendData(unsigned char *channelData); + virtual int SendData(unsigned char *channelData) override; - void DumpConfig(void); + virtual void DumpConfig(void) override; - virtual void GetRequiredChannelRanges(const std::function &addRange) { + virtual void GetRequiredChannelRanges(const std::function &addRange) override { //FIXME?? addRange(0, FPPD_MAX_CHANNELS); } diff --git a/src/channeloutput/SPInRF24L01.h b/src/channeloutput/SPInRF24L01.h index d477d6fb0..af52adb62 100644 --- a/src/channeloutput/SPInRF24L01.h +++ b/src/channeloutput/SPInRF24L01.h @@ -28,18 +28,18 @@ class SPInRF24L01PrivData; class SPInRF24L01Output : public ChannelOutputBase { public: SPInRF24L01Output(unsigned int startChannel, unsigned int channelCount); - ~SPInRF24L01Output(); + virtual ~SPInRF24L01Output(); - virtual int Init(Json::Value config); - int Init(char *configStr); + virtual int Init(Json::Value config) override; + virtual int Init(char *configStr) override; - int Close(void); + virtual int Close(void) override; - int SendData(unsigned char *channelData); + virtual int SendData(unsigned char *channelData) override; - void DumpConfig(void); + virtual void DumpConfig(void) override; - virtual void GetRequiredChannelRanges(const std::function &addRange); + virtual void GetRequiredChannelRanges(const std::function &addRange) override; private: SPInRF24L01PrivData *data; diff --git a/src/channeloutput/SPIws2801.h b/src/channeloutput/SPIws2801.h index a677c60f9..df50aa22e 100644 --- a/src/channeloutput/SPIws2801.h +++ b/src/channeloutput/SPIws2801.h @@ -32,19 +32,19 @@ class SPIws2801Output : public ThreadedChannelOutputBase { public: SPIws2801Output(unsigned int startChannel, unsigned int channelCount); - ~SPIws2801Output(); + virtual ~SPIws2801Output(); - virtual int Init(Json::Value config); + virtual int Init(Json::Value config) override; - int Init(char *configStr); + virtual int Init(char *configStr) override; - int Close(void); + virtual int Close(void) override; - int RawSendData(unsigned char *channelData); + virtual int RawSendData(unsigned char *channelData) override; - void DumpConfig(void); + virtual void DumpConfig(void) override; - virtual void GetRequiredChannelRanges(const std::function &addRange); + virtual void GetRequiredChannelRanges(const std::function &addRange) override; private: SPIUtils *m_spi; diff --git a/src/channeloutput/ThreadedChannelOutputBase.h b/src/channeloutput/ThreadedChannelOutputBase.h index a45a5aef9..bcc643d71 100644 --- a/src/channeloutput/ThreadedChannelOutputBase.h +++ b/src/channeloutput/ThreadedChannelOutputBase.h @@ -42,11 +42,11 @@ class ThreadedChannelOutputBase : public ChannelOutputBase { virtual ~ThreadedChannelOutputBase(); - virtual int Init(Json::Value config); - virtual int Init(char *configStr); - virtual int Close(void) override; + virtual int Init(Json::Value config) override; + virtual int Init(char *configStr) override; + virtual int Close(void) override; - virtual int SendData(unsigned char *channelData) override; + virtual int SendData(unsigned char *channelData) override; void OutputThread(void); @@ -54,7 +54,7 @@ class ThreadedChannelOutputBase : public ChannelOutputBase { int Init(void); protected: - virtual void DumpConfig(void); + virtual void DumpConfig(void) override; virtual int RawSendData(unsigned char *channelData) = 0; int StartOutputThread(void); int StopOutputThread(void); diff --git a/src/channeloutput/UDPOutput.cpp b/src/channeloutput/UDPOutput.cpp index bcfe527e3..6d53194b8 100644 --- a/src/channeloutput/UDPOutput.cpp +++ b/src/channeloutput/UDPOutput.cpp @@ -38,6 +38,7 @@ #include "common.h" #include "settings.h" +#include "NetworkMonitor.h" #include "E131.h" #include "DDP.h" @@ -50,7 +51,15 @@ extern "C" { } } -const std::string WARNING_PREFIX = "Cannot Ping UDP Channel Data Target "; + +static inline std::string createWarning(const std::string &host, const std::string &type) { + return "Cannot Ping " + type + " Channel Data Target " + host; +} + +static void DoPingThread(UDPOutput *output) { + output->BackgroundThreadPing(); +} + UDPOutput* UDPOutput::INSTANCE = nullptr; @@ -77,6 +86,12 @@ UDPOutputData::UDPOutputData(const Json::Value &config) UDPOutputData::~UDPOutputData() { } +static const std::string UNKNOWN_TYPE = "UDP"; +const std::string &UDPOutputData::GetOutputTypeString() const { + return UNKNOWN_TYPE; +} + + in_addr_t UDPOutputData::toInetAddr(const std::string &ipAddress, bool &valid) { valid = true; bool isAlpha = false; @@ -101,14 +116,23 @@ in_addr_t UDPOutputData::toInetAddr(const std::string &ipAddress, bool &valid) { UDPOutput::UDPOutput(unsigned int startChannel, unsigned int channelCount) - : pingThread(nullptr), rebuildOutputLists(false) + : pingThread(nullptr), runPingThread(true), rebuildOutputLists(false), + errCount(0), networkCallbackId(0) { INSTANCE = this; sendSocket = -1; + broadcastSocket = -1; } UDPOutput::~UDPOutput() { INSTANCE = nullptr; - runDisabledPings = false; + runPingThread = false; + pingThreadCondition.notify_all(); + if (pingThread) { + pingThread->join(); + delete pingThread; + pingThread = nullptr; + } + NetworkMonitor::INSTANCE.removeCallback(networkCallbackId); for (auto a : outputs) { delete a; } @@ -148,9 +172,10 @@ int UDPOutput::Init(Json::Value config) { getifaddrs(&interfaces); tmp = interfaces; //loop through all the interfaces and get the addresses + char address[16]; + memset(address, 0, sizeof(address)); while (tmp) { if (tmp->ifa_addr && tmp->ifa_addr->sa_family == AF_INET) { - char address[16]; GetInterfaceAddress(tmp->ifa_name, address, NULL, NULL); myIps.emplace(address); } @@ -172,11 +197,37 @@ int UDPOutput::Init(Json::Value config) { } + std::function f = [this](NetworkMonitor::NetEventType i, int up, const std::string &s) { + std::string interface = getE131interface(); + if (s == interface && i == NetworkMonitor::NetEventType::NEW_ADDR && up) { + LogInfo(VB_CHANNELOUT, "UDP Interface now up\n"); + PingControllers(); + std::this_thread::sleep_for(std::chrono::milliseconds(200)); + InitNetwork(); + rebuildOutputLists = true; + } else if (s == interface && i == NetworkMonitor::NetEventType::DEL_ADDR) { + LogInfo(VB_CHANNELOUT, "UDP Interface now down\n"); + CloseNetwork(); + } + }; + networkCallbackId = NetworkMonitor::INSTANCE.registerCallback(f); + + InitNetwork(); PingControllers(); + rebuildOutputLists = true; + pingThread = new std::thread(DoPingThread, this); return ChannelOutputBase::Init(config); } -int UDPOutput::Close() { +int UDPOutput::Close() { + runPingThread = false; + pingThreadCondition.notify_all(); + if (pingThread) { + pingThread->join(); + delete pingThread; + pingThread = nullptr; + } + NetworkMonitor::INSTANCE.removeCallback(networkCallbackId); return ChannelOutputBase::Close(); } void UDPOutput::PrepData(unsigned char *channelData) { @@ -215,11 +266,20 @@ int UDPOutput::SendMessages(int socket, std::vector &sendmsgs) { return 0; } - int oc = sendmmsg(socket, msgs, msgCount, 0); + if (sendSocket == -1) { + return msgCount; + } + + errno = 0; + int oc = sendmmsg(socket, msgs, msgCount, MSG_DONTWAIT); int outputCount = oc; - while (oc > 0 && outputCount != msgCount) { - int oc = sendmmsg(sendSocket, &msgs[outputCount], msgCount - outputCount, 0); - if (oc >= 0) { + while (outputCount != msgCount) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + return outputCount; + } + errno = 0; + int oc = sendmmsg(socket, &msgs[outputCount], msgCount - outputCount, MSG_DONTWAIT); + if (oc > 0) { outputCount += oc; } } @@ -231,77 +291,55 @@ int UDPOutput::SendData(unsigned char *channelData) { if ((udpMsgs.size() == 0 && broadcastMsgs.size() == 0) || !enabled) { return 0; } - std::chrono::high_resolution_clock clock; - auto t1 = clock.now(); - int outputCount = SendMessages(sendSocket, udpMsgs); - auto t2 = clock.now(); - long diff = std::chrono::duration_cast(t2 - t1).count(); - if ((outputCount != udpMsgs.size()) || (diff > 100)) { - //failed to send all messages or it took more than 100ms to send them - LogErr(VB_CHANNELOUT, "sendmmsg() failed for UDP output (output count: %d/%d time: %u ms) with error: %d %s\n", - outputCount, udpMsgs.size(), diff, - errno, - strerror(errno)); - - //we'll ping the controllers and rebuild the valid message list, this could take time - - PingControllers(); - return 0; + isSending = true; + if (udpMsgs.size() > 0) { + std::chrono::high_resolution_clock clock; + auto t1 = clock.now(); + int outputCount = SendMessages(sendSocket, udpMsgs); + auto t2 = clock.now(); + long diff = std::chrono::duration_cast(t2 - t1).count(); + if ((outputCount != udpMsgs.size()) || (diff > 100)) { + errCount++; + + //failed to send all messages or it took more than 100ms to send them + LogErr(VB_CHANNELOUT, "sendmmsg() failed for UDP output (output count: %d/%d time: %u ms errCount: %d) with error: %d %s\n", + outputCount, udpMsgs.size(), diff, errCount, + errno, + strerror(errno)); + + if (errCount >= 3) { + //we'll ping the controllers and rebuild the valid message list, this could take time + pingThreadCondition.notify_all(); + errCount = 0; + } + return 0; + } else { + errCount = 0; + } } - outputCount = SendMessages(broadcastSocket, broadcastMsgs); - + SendMessages(broadcastSocket, broadcastMsgs); + isSending = false; return 1; } -void DoPingThread(UDPOutput *output) { - output->BackgroundThreadPing(); -} void UDPOutput::BackgroundThreadPing() { - while (runDisabledPings) { - std::this_thread::sleep_for (std::chrono::seconds(10)); - bool newValid = false; - - std::map done; - - std::unique_lock lck (invalidOutputsMutex); - for (auto a : invalidOutputs) { - if (!a->valid) { - std::string host = a->ipAddress; - if (done[host] == 0) { - int p = ping(host); - if (p <= 0) { - p = -1; - } - done[host] = p; - if (p > 0) { - LogWarn(VB_CHANNELOUT, "Can ping host %s, re-adding to outputs\n", - host.c_str()); - } - } - if (done[host] > 0) { - WarningHolder::RemoveWarning(WARNING_PREFIX + host); - } - a->valid = done[host] > 0; - } - if (a->valid) { - newValid = true; - } - } - + std::unique_lock lk(pingThreadMutex); + pingThreadCondition.wait_for(lk, std::chrono::seconds(10)); + while (runPingThread) { + bool newValid = PingControllers(); if (newValid) { - //at least one output became valid, let main thread know to rebuild the + //at least one output became valid or invalid, let main thread know to rebuild the //output message maps rebuildOutputLists = true; } + pingThreadCondition.wait_for(lk, std::chrono::seconds(10)); } - std::thread *t = pingThread; - pingThread = nullptr; - delete t; } -void UDPOutput::PingControllers() { - LogDebug(VB_CHANNELOUT, "Pinging controllers to see what is online\n"); +bool UDPOutput::PingControllers() { + LogExcess(VB_CHANNELOUT, "Pinging controllers to see what is online\n"); std::map done; + bool newOutputs = false; for (auto o : outputs) { if (o->IsPingable() && o->active) { std::string host = o->ipAddress; @@ -313,9 +351,10 @@ void UDPOutput::PingControllers() { done[host] = p; if (p > 0 && !o->valid) { - WarningHolder::RemoveWarning(WARNING_PREFIX + host); + WarningHolder::RemoveWarning(createWarning(host, o->GetOutputTypeString())); LogWarn(VB_CHANNELOUT, "Could ping host %s, re-adding to outputs\n", host.c_str()); + newOutputs = true; } } } @@ -333,19 +372,21 @@ void UDPOutput::PingControllers() { done[host] = p; if (p < 0 && o->valid) { - WarningHolder::AddWarning(WARNING_PREFIX + host); + WarningHolder::AddWarning(createWarning(host, o->GetOutputTypeString())); LogWarn(VB_CHANNELOUT, "Could not ping host %s, removing from output\n", host.c_str()); + newOutputs = true; } else if (p > 0 && !o->valid) { - WarningHolder::RemoveWarning(WARNING_PREFIX + host); + WarningHolder::RemoveWarning(createWarning(host, o->GetOutputTypeString())); LogWarn(VB_CHANNELOUT, "Could ping host %s, re-adding to outputs\n", host.c_str()); + newOutputs = true; } } o->valid = p > 0; } } - RebuildOutputMessageLists(); + return newOutputs; } void UDPOutput::RebuildOutputMessageLists() { LogDebug(VB_CHANNELOUT, "Rebuilding message lists\n"); @@ -365,20 +406,6 @@ void UDPOutput::RebuildOutputMessageLists() { a->AddPostDataMessages(broadcastMsgs); } } - std::unique_lock lck (invalidOutputsMutex); - invalidOutputs.clear(); - for (auto a : outputs) { - if (!a->valid && a->active && a->IsPingable()) { - //active, but not valid, likely lost the ping - //save it so we can try re-enabling - invalidOutputs.push_back(a); - } - } - - if (!invalidOutputs.empty() && pingThread == nullptr) { - runDisabledPings = true; - pingThread = new std::thread(DoPingThread, this); - } } void UDPOutput::DumpConfig() { ChannelOutputBase::DumpConfig(); @@ -386,14 +413,38 @@ void UDPOutput::DumpConfig() { u->DumpConfig(); } } +void UDPOutput::CloseNetwork() { + int ts = sendSocket; + int bs = broadcastSocket; + + sendSocket = -1; + broadcastSocket = -1; + //if other thread is sending data, give it time to compete + while (isSending) { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + close(ts); + close(bs); + + PingControllers(); + rebuildOutputLists = true; +} bool UDPOutput::InitNetwork() { + if (sendSocket != -1) { + return true; + } char E131LocalAddress[16]; GetInterfaceAddress(getE131interface(), E131LocalAddress, NULL, NULL); LogDebug(VB_CHANNELOUT, "UDPLocalAddress = %s\n",E131LocalAddress); + if (strcmp(E131LocalAddress, "127.0.0.1") == 0) { + return false; + } + + + int sendSocket = socket(AF_INET, SOCK_DGRAM, 0); - sendSocket = socket(AF_INET, SOCK_DGRAM, 0); if (sendSocket < 0) { LogErr(VB_CHANNELOUT, "Error opening datagram socket\n"); exit(1); @@ -426,7 +477,7 @@ bool UDPOutput::InitNetwork() { LogErr(VB_CHANNELOUT, "Error connecting IP_MULTICAST_LOOP socket\n"); } - broadcastSocket = socket(AF_INET, SOCK_DGRAM, 0); + int broadcastSocket = socket(AF_INET, SOCK_DGRAM, 0); if (broadcastSocket < 0) { LogErr(VB_CHANNELOUT, "Error opening datagram socket\n"); exit(1); @@ -451,6 +502,8 @@ bool UDPOutput::InitNetwork() { LogErr(VB_CHANNELOUT, "Error connecting IP_MULTICAST_LOOP socket\n"); } + this->sendSocket = sendSocket; + this->broadcastSocket = broadcastSocket; return true; } diff --git a/src/channeloutput/UDPOutput.h b/src/channeloutput/UDPOutput.h index 6cba7af19..38ea500a0 100644 --- a/src/channeloutput/UDPOutput.h +++ b/src/channeloutput/UDPOutput.h @@ -59,6 +59,8 @@ class UDPOutputData { max = startChannel + channelCount - 1; } + virtual const std::string &GetOutputTypeString() const; + static in_addr_t toInetAddr(const std::string &ip, bool &valid); @@ -69,26 +71,29 @@ class UDPOutputData { int type; std::string ipAddress; bool valid; + + + UDPOutputData(UDPOutputData const &) = delete; + void operator=(UDPOutputData const &x) = delete; }; - class UDPOutput : public ChannelOutputBase { public: UDPOutput(unsigned int startChannel, unsigned int channelCount); - ~UDPOutput(); + virtual ~UDPOutput(); - int Init(Json::Value config); - int Close(void); + virtual int Init(Json::Value config) override; + virtual int Close(void) override; - void PrepData(unsigned char *channelData); - int SendData(unsigned char *channelData); + virtual void PrepData(unsigned char *channelData) override; + virtual int SendData(unsigned char *channelData) override; - void DumpConfig(void); + virtual void DumpConfig(void) override; void BackgroundThreadPing(); - virtual void GetRequiredChannelRanges(const std::function &addRange); + virtual void GetRequiredChannelRanges(const std::function &addRange) override; void addOutput(UDPOutputData*); @@ -97,22 +102,30 @@ class UDPOutput : public ChannelOutputBase { private: int SendMessages(int socket, std::vector &sendmsgs); bool InitNetwork(); - void PingControllers(); + void CloseNetwork(); + bool PingControllers(); void RebuildOutputMessageLists(); int sendSocket; int broadcastSocket; bool enabled; + int errCount; + + std::atomic_bool isSending; + std::list outputs; std::vector udpMsgs; std::vector broadcastMsgs; + int networkCallbackId; + + volatile bool runPingThread; std::thread *pingThread; - volatile bool runDisabledPings; + std::mutex pingThreadMutex; + std::condition_variable pingThreadCondition; + volatile bool rebuildOutputLists; - std::mutex invalidOutputsMutex; - std::list invalidOutputs; }; #endif diff --git a/src/channeloutput/USBDMX.h b/src/channeloutput/USBDMX.h index 9e706b17f..37619f5a9 100644 --- a/src/channeloutput/USBDMX.h +++ b/src/channeloutput/USBDMX.h @@ -33,18 +33,18 @@ class USBDMXOutput : public ThreadedChannelOutputBase { public: USBDMXOutput(unsigned int startChannel, unsigned int channelCount); - ~USBDMXOutput(); + virtual ~USBDMXOutput(); - virtual int Init(Json::Value config); - int Init(char *configStr); + virtual int Init(Json::Value config) override; + virtual int Init(char *configStr) override; - int Close(void); + virtual int Close(void) override; - int RawSendData(unsigned char *channelData); + virtual int RawSendData(unsigned char *channelData) override; - void DumpConfig(void); + virtual void DumpConfig(void) override; - virtual void GetRequiredChannelRanges(const std::function &addRange); + virtual void GetRequiredChannelRanges(const std::function &addRange) override; private: int RawSendDataOpen(unsigned char *channelData); diff --git a/src/channeloutput/USBPixelnet.h b/src/channeloutput/USBPixelnet.h index 65f0329cb..01be6b9c6 100644 --- a/src/channeloutput/USBPixelnet.h +++ b/src/channeloutput/USBPixelnet.h @@ -33,17 +33,17 @@ class USBPixelnetOutput : public ThreadedChannelOutputBase { public: USBPixelnetOutput(unsigned int startChannel, unsigned int channelCount); - ~USBPixelnetOutput(); + virtual ~USBPixelnetOutput(); - virtual int Init(Json::Value config); - int Init(char *configStr); - int Close(void); + virtual int Init(Json::Value config) override; + virtual int Init(char *configStr) override; + virtual int Close(void) override; - int RawSendData(unsigned char *channelData); + virtual int RawSendData(unsigned char *channelData) override; - void DumpConfig(void); + virtual void DumpConfig(void) override; - virtual void GetRequiredChannelRanges(const std::function &addRange); + virtual void GetRequiredChannelRanges(const std::function &addRange) override; private: enum DongleType { diff --git a/src/channeloutput/USBRelay.h b/src/channeloutput/USBRelay.h index 16c9c1306..b3922d38f 100644 --- a/src/channeloutput/USBRelay.h +++ b/src/channeloutput/USBRelay.h @@ -33,16 +33,16 @@ class USBRelayOutput : public ChannelOutputBase { public: USBRelayOutput(unsigned int startChannel, unsigned int channelCount); - ~USBRelayOutput(); + virtual ~USBRelayOutput(); - virtual int Init(Json::Value config); - int Close(void); + virtual int Init(Json::Value config) override; + virtual int Close(void) override; - int SendData(unsigned char *channelData); + virtual int SendData(unsigned char *channelData) override; - void DumpConfig(void); + virtual void DumpConfig(void) override; - virtual void GetRequiredChannelRanges(const std::function &addRange); + virtual void GetRequiredChannelRanges(const std::function &addRange) override; private: enum RelayType { diff --git a/src/channeloutput/USBRenard.h b/src/channeloutput/USBRenard.h index e019acb6a..219e7541c 100644 --- a/src/channeloutput/USBRenard.h +++ b/src/channeloutput/USBRenard.h @@ -28,18 +28,18 @@ class USBRenardOutputData; class USBRenardOutput : public ChannelOutputBase { public: USBRenardOutput(unsigned int startChannel, unsigned int channelCount); - ~USBRenardOutput(); + virtual ~USBRenardOutput(); - virtual int Init(Json::Value config); - int Init(char *configStr); + virtual int Init(Json::Value config) override; + virtual int Init(char *configStr) override; - int Close(void); + virtual int Close(void) override; - int SendData(unsigned char *channelData); + virtual int SendData(unsigned char *channelData) override; - void DumpConfig(void); + virtual void DumpConfig(void) override; - virtual void GetRequiredChannelRanges(const std::function &addRange); + virtual void GetRequiredChannelRanges(const std::function &addRange) override; private: USBRenardOutputData *data; diff --git a/src/channeloutput/VirtualDisplay.h b/src/channeloutput/VirtualDisplay.h index d3b445c0a..19ba6ca02 100644 --- a/src/channeloutput/VirtualDisplay.h +++ b/src/channeloutput/VirtualDisplay.h @@ -66,9 +66,9 @@ typedef struct virtualDisplayPixel { class VirtualDisplayOutput : public ChannelOutputBase { public: VirtualDisplayOutput(unsigned int startChannel, unsigned int channelCount); - ~VirtualDisplayOutput(); + virtual ~VirtualDisplayOutput(); - virtual int Init(Json::Value config); + virtual int Init(Json::Value config) override; int InitializePixelMap(void); int ScaleBackgroundImage(std::string &bgFile, std::string &rgbFile); @@ -80,9 +80,9 @@ class VirtualDisplayOutput : public ChannelOutputBase { unsigned char r, unsigned char g, unsigned char b); void DrawPixels(unsigned char *channelData); - void DumpConfig(void); + virtual void DumpConfig(void) override; - virtual void GetRequiredChannelRanges(const std::function &addRange); + virtual void GetRequiredChannelRanges(const std::function &addRange) override; std::string m_backgroundFilename; float m_backgroundBrightness; diff --git a/src/channeloutput/X11Matrix.h b/src/channeloutput/X11Matrix.h index 6f150eafe..05cd02b05 100644 --- a/src/channeloutput/X11Matrix.h +++ b/src/channeloutput/X11Matrix.h @@ -33,16 +33,16 @@ class X11MatrixOutput : public ThreadedChannelOutputBase { public: X11MatrixOutput(unsigned int startChannel, unsigned int channelCount); - ~X11MatrixOutput(); + virtual ~X11MatrixOutput(); - int Init(Json::Value config); - int Close(void); + virtual int Init(Json::Value config) override; + virtual int Close(void) override; - int RawSendData(unsigned char *channelData); + virtual int RawSendData(unsigned char *channelData) override; - void DumpConfig(void); + virtual void DumpConfig(void) override; - virtual void GetRequiredChannelRanges(const std::function &addRange); + virtual void GetRequiredChannelRanges(const std::function &addRange) override; private: int m_width; diff --git a/src/channeloutput/X11VirtualDisplay.h b/src/channeloutput/X11VirtualDisplay.h index 4583db906..a8d56111a 100644 --- a/src/channeloutput/X11VirtualDisplay.h +++ b/src/channeloutput/X11VirtualDisplay.h @@ -35,13 +35,13 @@ class X11VirtualDisplayOutput : protected VirtualDisplayOutput { public: X11VirtualDisplayOutput(unsigned int startChannel, unsigned int channelCount); - ~X11VirtualDisplayOutput(); + virtual ~X11VirtualDisplayOutput(); - int Init(Json::Value config); - int Close(void); + virtual int Init(Json::Value config) override; + virtual int Close(void) override; - void PrepData(unsigned char *channelData); - int SendData(unsigned char *channelData); + virtual void PrepData(unsigned char *channelData) override; + virtual int SendData(unsigned char *channelData) override; private: char *m_imageData; diff --git a/src/channeloutput/channeloutput.c b/src/channeloutput/channeloutput.c index cf650f433..e628317dd 100644 --- a/src/channeloutput/channeloutput.c +++ b/src/channeloutput/channeloutput.c @@ -41,6 +41,7 @@ #include "settings.h" #include "channeloutput.h" #include "ChannelOutputBase.h" +#include "Warnings.h" //old style that still need porting #include "FPD.h" @@ -336,9 +337,12 @@ int InitializeChannelOutputs(void) { } if (fptr == nullptr) { LogErr(VB_CHANNELOUT, "Could not create Channel Output type: %s\n", type.c_str()); + WarningHolder::AddWarning("Could not create output type " + type + ". Check logs for details."); + dlclose(handle); continue; } channelOutputs[i].output = fptr(start, count); + channelOutputs[i].libHandle = handle; } if ((channelOutputs[i].outputOld) && @@ -372,11 +376,16 @@ int InitializeChannelOutputs(void) { }); i++; } else { + WarningHolder::AddWarning("Could not initialize output type " + type + ". Check logs for details."); delete channelOutputs[i].output; channelOutputs[i].output = nullptr; + if (channelOutputs[i].libHandle) { + dlclose(channelOutputs[i].libHandle); + } } } else { LogErr(VB_CHANNELOUT, "ERROR Opening %s Channel Output\n", type.c_str()); + WarningHolder::AddWarning("Could not create output type " + type + ". Check logs for details."); continue; } @@ -513,6 +522,9 @@ void CloseChannelOutputs(void) { if (channelOutputs[i].output) { delete channelOutputs[i].output; channelOutputs[i].output = NULL; + if (channelOutputs[i].libHandle) { + dlclose(channelOutputs[i].libHandle); + } } } } diff --git a/src/channeloutput/channeloutput.h b/src/channeloutput/channeloutput.h index 41acfc991..b50a18e38 100644 --- a/src/channeloutput/channeloutput.h +++ b/src/channeloutput/channeloutput.h @@ -46,13 +46,18 @@ typedef struct fppChannelOutput { int (*stopThread)(void *data); } FPPChannelOutput; -typedef struct fppChannelOutputInstance { - unsigned int startChannel; - unsigned int channelCount; - FPPChannelOutput *outputOld; - ChannelOutputBase *output; - void *privData; -} FPPChannelOutputInstance; +class FPPChannelOutputInstance { +public: + FPPChannelOutputInstance() {} + ~FPPChannelOutputInstance() {} + + unsigned int startChannel = 0; + unsigned int channelCount = 0; + FPPChannelOutput *outputOld = nullptr; + ChannelOutputBase *output = nullptr; + void *privData = nullptr; + void *libHandle = nullptr; +}; extern char channelData[]; extern pthread_mutex_t channelDataLock; diff --git a/src/channeloutput/processors/BrightnessOutputProcessor.h b/src/channeloutput/processors/BrightnessOutputProcessor.h index 3cccbe9f1..0e61cf92f 100644 --- a/src/channeloutput/processors/BrightnessOutputProcessor.h +++ b/src/channeloutput/processors/BrightnessOutputProcessor.h @@ -25,11 +25,11 @@ class BrightnessOutputProcessor : public OutputProcessor { BrightnessOutputProcessor(const Json::Value &config); virtual ~BrightnessOutputProcessor(); - virtual void ProcessData(unsigned char *channelData) const; + virtual void ProcessData(unsigned char *channelData) const override; - virtual OutputProcessorType getType() const { return BRIGHTNESS; } + virtual OutputProcessorType getType() const override { return BRIGHTNESS; } - virtual void GetRequiredChannelRanges(const std::function &addRange) { + virtual void GetRequiredChannelRanges(const std::function &addRange) override { addRange(start, start + count - 1); } diff --git a/src/channeloutput/processors/ColorOrderOutputProcessor.h b/src/channeloutput/processors/ColorOrderOutputProcessor.h index 2417cc5cc..7d9813bea 100644 --- a/src/channeloutput/processors/ColorOrderOutputProcessor.h +++ b/src/channeloutput/processors/ColorOrderOutputProcessor.h @@ -25,11 +25,11 @@ class ColorOrderOutputProcessor : public OutputProcessor { ColorOrderOutputProcessor(const Json::Value &config); virtual ~ColorOrderOutputProcessor(); - virtual void ProcessData(unsigned char *channelData) const; + virtual void ProcessData(unsigned char *channelData) const override; - virtual OutputProcessorType getType() const { return COLORORDER; } + virtual OutputProcessorType getType() const override { return COLORORDER; } - virtual void GetRequiredChannelRanges(const std::function &addRange) { + virtual void GetRequiredChannelRanges(const std::function &addRange) override { addRange(start, start + (count * 3) - 1); } diff --git a/src/channeloutput/processors/OutputProcessor.cpp b/src/channeloutput/processors/OutputProcessor.cpp index d88692754..1dab6ff19 100644 --- a/src/channeloutput/processors/OutputProcessor.cpp +++ b/src/channeloutput/processors/OutputProcessor.cpp @@ -64,7 +64,7 @@ void OutputProcessors::loadFromJSON(const Json::Value &config, bool clear) { if (clear) { removeAll(); } - for( Json::Value::const_iterator itr = config.begin() ; itr != config.end() ; itr++ ) { + for (Json::Value::const_iterator itr = config.begin() ; itr != config.end() ; ++itr) { std::string name = itr.key().asString(); if (name == "outputProcessors") { Json::Value val = *itr; diff --git a/src/channeloutput/processors/RemapOutputProcessor.h b/src/channeloutput/processors/RemapOutputProcessor.h index c0d7d2008..ec3cee589 100644 --- a/src/channeloutput/processors/RemapOutputProcessor.h +++ b/src/channeloutput/processors/RemapOutputProcessor.h @@ -26,9 +26,9 @@ class RemapOutputProcessor : public OutputProcessor { RemapOutputProcessor(int src, int dst, int count, int loop, int reverse); virtual ~RemapOutputProcessor(); - virtual void ProcessData(unsigned char *channelData) const; + virtual void ProcessData(unsigned char *channelData) const override; - virtual OutputProcessorType getType() const { return REMAP; } + virtual OutputProcessorType getType() const override { return REMAP; } int getSourceChannel() const { return sourceChannel;} int getDestChannel() const { return destChannel;} @@ -36,7 +36,7 @@ class RemapOutputProcessor : public OutputProcessor { int getLoops() const { return loops;} int getReverse() const { return reverse;} - virtual void GetRequiredChannelRanges(const std::function &addRange); + virtual void GetRequiredChannelRanges(const std::function &addRange) override; protected: int sourceChannel; diff --git a/src/channeloutput/processors/SetValueOutputProcessor.h b/src/channeloutput/processors/SetValueOutputProcessor.h index b45301a94..55edb4943 100644 --- a/src/channeloutput/processors/SetValueOutputProcessor.h +++ b/src/channeloutput/processors/SetValueOutputProcessor.h @@ -25,11 +25,11 @@ class SetValueOutputProcessor : public OutputProcessor { SetValueOutputProcessor(const Json::Value &config); virtual ~SetValueOutputProcessor(); - virtual void ProcessData(unsigned char *channelData) const; + virtual void ProcessData(unsigned char *channelData) const override; - virtual OutputProcessorType getType() const { return SETVALUE; } + virtual OutputProcessorType getType() const override { return SETVALUE; } - virtual void GetRequiredChannelRanges(const std::function &addRange) { + virtual void GetRequiredChannelRanges(const std::function &addRange) override { addRange(start, start + count - 1); } diff --git a/src/channeloutput/rpi_ws281x.h b/src/channeloutput/rpi_ws281x.h index 222c323c7..64e48e155 100644 --- a/src/channeloutput/rpi_ws281x.h +++ b/src/channeloutput/rpi_ws281x.h @@ -42,17 +42,17 @@ extern "C" { class RPIWS281xOutput : public ThreadedChannelOutputBase { public: RPIWS281xOutput(unsigned int startChannel, unsigned int channelCount); - ~RPIWS281xOutput(); + virtual ~RPIWS281xOutput(); - int Init(Json::Value config); - int Close(void); + virtual int Init(Json::Value config) override; + virtual int Close(void) override; - void PrepData(unsigned char *channelData); - int RawSendData(unsigned char *channelData); + virtual void PrepData(unsigned char *channelData) override; + virtual int RawSendData(unsigned char *channelData) override; - void DumpConfig(void); + virtual void DumpConfig(void) override; - virtual void GetRequiredChannelRanges(const std::function &addRange); + virtual void GetRequiredChannelRanges(const std::function &addRange) override; private: void SetupCtrlCHandler(void); diff --git a/src/channeloutput/spixels.h b/src/channeloutput/spixels.h index 29bb6f765..ccedc6129 100644 --- a/src/channeloutput/spixels.h +++ b/src/channeloutput/spixels.h @@ -38,17 +38,17 @@ using namespace spixels; class SpixelsOutput : public ThreadedChannelOutputBase { public: SpixelsOutput(unsigned int startChannel, unsigned int channelCount); - ~SpixelsOutput(); + virtual ~SpixelsOutput(); - int Init(Json::Value config); - int Close(void); + virtual int Init(Json::Value config) override; + virtual int Close(void) override; - void PrepData(unsigned char *channelData); - int RawSendData(unsigned char *channelData); + virtual void PrepData(unsigned char *channelData) override; + virtual int RawSendData(unsigned char *channelData) override; - void DumpConfig(void); + virtual void DumpConfig(void) override; - virtual void GetRequiredChannelRanges(const std::function &addRange); + virtual void GetRequiredChannelRanges(const std::function &addRange) override; private: MultiSPI *m_spi; diff --git a/src/channeltester/ChannelTester.h b/src/channeltester/ChannelTester.h index 76481b902..2482ed4d6 100644 --- a/src/channeltester/ChannelTester.h +++ b/src/channeltester/ChannelTester.h @@ -36,7 +36,7 @@ class ChannelTester { public: ChannelTester(); - ~ChannelTester(); + virtual ~ChannelTester(); int SetupTest(std::string configStr); diff --git a/src/channeltester/RGBChase.h b/src/channeltester/RGBChase.h index 20ffd87ca..3251a8ee3 100644 --- a/src/channeltester/RGBChase.h +++ b/src/channeltester/RGBChase.h @@ -36,15 +36,15 @@ class TestPatternRGBChase : public TestPatternBase { public: TestPatternRGBChase(); - ~TestPatternRGBChase(); + virtual ~TestPatternRGBChase(); - int Init(Json::Value config); + virtual int Init(Json::Value config) override; - int SetupTest(void); - void DumpConfig(void); + virtual int SetupTest(void) override; + virtual void DumpConfig(void) override; private: - void CycleData(void); + void CycleData(void) override; std::string m_colorPatternStr; std::vector m_colorPattern; diff --git a/src/channeltester/RGBCycle.h b/src/channeltester/RGBCycle.h index 07dce2cdd..70be54ef3 100644 --- a/src/channeltester/RGBCycle.h +++ b/src/channeltester/RGBCycle.h @@ -28,15 +28,15 @@ class TestPatternRGBCycle : public TestPatternBase { public: TestPatternRGBCycle(); - ~TestPatternRGBCycle(); + virtual ~TestPatternRGBCycle(); - int Init(Json::Value config); + virtual int Init(Json::Value config) override; - int SetupTest(void); - void DumpConfig(void); + virtual int SetupTest(void) override; + virtual void DumpConfig(void) override; private: - void CycleData(void); + void CycleData(void) override; std::string m_colorPatternStr; std::vector m_colorPattern; diff --git a/src/channeltester/RGBFill.h b/src/channeltester/RGBFill.h index f8176dc45..4d72611f5 100644 --- a/src/channeltester/RGBFill.h +++ b/src/channeltester/RGBFill.h @@ -36,12 +36,12 @@ class TestPatternRGBFill : public TestPatternBase { public: TestPatternRGBFill(); - ~TestPatternRGBFill(); + virtual ~TestPatternRGBFill(); - int Init(Json::Value config); + virtual int Init(Json::Value config) override; - int SetupTest(void); - void DumpConfig(void); + virtual int SetupTest(void) override; + virtual void DumpConfig(void) override; private: char m_color1; diff --git a/src/channeltester/SingleChase.h b/src/channeltester/SingleChase.h index f3edf3494..a6f428eb4 100644 --- a/src/channeltester/SingleChase.h +++ b/src/channeltester/SingleChase.h @@ -36,15 +36,15 @@ class TestPatternSingleChase : public TestPatternBase { public: TestPatternSingleChase(); - ~TestPatternSingleChase(); + virtual ~TestPatternSingleChase(); - int Init(Json::Value config); + virtual int Init(Json::Value config) override; - int SetupTest(void); - void DumpConfig(void); + virtual int SetupTest(void) override; + virtual void DumpConfig(void) override; private: - void CycleData(void); + void CycleData(void) override; int m_chaseSize; char m_chaseValue; diff --git a/src/channeltester/TestPatternBase.h b/src/channeltester/TestPatternBase.h index 7c9564295..809da8b6a 100644 --- a/src/channeltester/TestPatternBase.h +++ b/src/channeltester/TestPatternBase.h @@ -37,7 +37,7 @@ class TestPatternBase { public: TestPatternBase(); - ~TestPatternBase(); + virtual ~TestPatternBase(); std::string Name(void) { return m_testPatternName; } int Init(std::string configStr); diff --git a/src/command.c b/src/command.c index 3d6513580..88dc473f5 100644 --- a/src/command.c +++ b/src/command.c @@ -57,7 +57,7 @@ #include - int socket_fd; + int socket_fd = -1; struct sockaddr_un server_address; int integer_buffer; int fppdStartTime = 0; @@ -66,11 +66,15 @@ static void exit_handler(int signum) { LogInfo(VB_GENERAL, "Caught signal %d\n",signum); - CloseCommand(); + char buf[256] = {0}; if(mediaOutputStatus.status == MEDIAOUTPUTSTATUS_PLAYING) { CloseMediaOutput(); } - exit(signum); + ShutdownFPPD(); + sleep(1); + + + CloseCommand(); } int Command_Initialize() @@ -113,8 +117,11 @@ static void exit_handler(int signum) void CloseCommand() { - close(socket_fd); - unlink(FPP_SERVER_SOCKET); + if (socket_fd >= 0) { + close(socket_fd); + unlink(FPP_SERVER_SOCKET); + socket_fd = -1; + } } diff --git a/src/commands/Commands.cpp b/src/commands/Commands.cpp index b622828e7..a4031b6a0 100644 --- a/src/commands/Commands.cpp +++ b/src/commands/Commands.cpp @@ -90,6 +90,7 @@ void CommandManager::Init() { addCommand(new RunScriptEvent()); addCommand(new StartEffectCommand()); addCommand(new StartFSEQAsEffectCommand()); + addCommand(new StopFSEQAsEffectCommand()); addCommand(new StopEffectCommand()); addCommand(new SetVolumeCommand()); addCommand(new AdjustVolumeCommand()); @@ -102,6 +103,7 @@ void CommandManager::Init() { addCommand(new StartRemoteEffectCommand()); addCommand(new StopRemoteEffectCommand()); addCommand(new RunRemoteScriptEvent()); + addCommand(new StartRemoteFSEQEffectCommand()); std::vector pins = PinCapabilities::getPinNames(); diff --git a/src/commands/Commands.h b/src/commands/Commands.h index 23d272087..a574685ab 100644 --- a/src/commands/Commands.h +++ b/src/commands/Commands.h @@ -50,7 +50,7 @@ class Command { ErrorResult() : Result() {} ErrorResult(const std::string &r) : Result(r) {} virtual ~ErrorResult() {} - virtual bool isError() { return true; } + virtual bool isError() override { return true; } }; diff --git a/src/commands/EventCommands.cpp b/src/commands/EventCommands.cpp index 457d859b5..ce3bdc60d 100644 --- a/src/commands/EventCommands.cpp +++ b/src/commands/EventCommands.cpp @@ -109,6 +109,14 @@ std::unique_ptr StopEffectCommand::run(const std::vector("Effect Stopped"); } +std::unique_ptr StopFSEQAsEffectCommand::run(const std::vector &args) { + if (args.empty()) { + return std::make_unique("Not found"); + } + + StopEffect(args[0]); + return std::make_unique("Effect Stopped"); +} std::unique_ptr StartRemoteEffectCommand::run(const std::vector &args) { if (args.empty()) { @@ -120,6 +128,16 @@ std::unique_ptr StartRemoteEffectCommand::run(const std::vector } return CommandManager::INSTANCE.runRemoteCommand(args[0], "Effect Start", newargs); } +std::unique_ptr StartRemoteFSEQEffectCommand::run(const std::vector &args) { + if (args.empty()) { + return std::make_unique("Not found"); + } + std::vector newargs; + for (int x = 1; x < args.size(); x++) { + newargs.push_back(args[x]); + } + return CommandManager::INSTANCE.runRemoteCommand(args[0], "FSEQ Effect Start", newargs); +} std::unique_ptr StopRemoteEffectCommand::run(const std::vector &args) { if (args.empty()) { return std::make_unique("Not found"); diff --git a/src/commands/EventCommands.h b/src/commands/EventCommands.h index da4126c1b..eed227f25 100644 --- a/src/commands/EventCommands.h +++ b/src/commands/EventCommands.h @@ -100,7 +100,14 @@ class StopEffectCommand : public Command { virtual std::unique_ptr run(const std::vector &args) override; }; - +class StopFSEQAsEffectCommand : public Command { +public: + StopFSEQAsEffectCommand() : Command("FSEQ Effect Stop") { + args.push_back(CommandArg("effect", "string", "FSEQ Name").setContentListUrl("api/sequence")); + } + + virtual std::unique_ptr run(const std::vector &args) override; +}; class StartRemoteEffectCommand : public Command { public: @@ -114,6 +121,17 @@ class StartRemoteEffectCommand : public Command { virtual std::unique_ptr run(const std::vector &args) override; }; +class StartRemoteFSEQEffectCommand : public Command { +public: + StartRemoteFSEQEffectCommand() : Command("Remote FSEQ Effect Start") { + args.push_back(CommandArg("remote", "datalist", "Remote IP").setContentListUrl("api/remotes")); + args.push_back(CommandArg("fseq", "string", "FSEQ Name")); + args.push_back(CommandArg("loop", "bool", "Loop Effect").setDefaultValue("true")); + args.push_back(CommandArg("bg", "bool", "Background")); + } + + virtual std::unique_ptr run(const std::vector &args) override; +}; class StopRemoteEffectCommand : public Command { public: StopRemoteEffectCommand() : Command("Remote Effect Stop") { diff --git a/src/commands/MediaCommands.cpp b/src/commands/MediaCommands.cpp index c2ce58def..56770c335 100644 --- a/src/commands/MediaCommands.cpp +++ b/src/commands/MediaCommands.cpp @@ -116,8 +116,8 @@ class CURLResult : public Command::Result { } cleanupCurl(); } - virtual bool isError() { return m_curl == nullptr || m_curlm == nullptr; } - virtual bool isDone() { + virtual bool isError() override { return m_curl == nullptr || m_curlm == nullptr; } + virtual bool isDone() override { if (!isError()) { if (m_isDone) { return true; diff --git a/src/e131bridge.cpp b/src/e131bridge.cpp index 8bfc44cbd..5b1dc86d2 100644 --- a/src/e131bridge.cpp +++ b/src/e131bridge.cpp @@ -842,7 +842,6 @@ void InputUniversesPrint() } -static std::map ERRORS; void AddFakeListener(int port, const std::string &protocol, std::map> &callbacks) { @@ -863,16 +862,17 @@ void AddFakeListener(int port, const std::string &protocol, } std::function f = [sock, protocol](int i) { + std::map errrors; int msgcnt = recvmmsg(sock, msgs, MAX_MSG, 0, nullptr); while (msgcnt > 0) { for (int x = 0; x < msgcnt; x++) { struct in_addr i = inAddress[x].sin_addr; in_addr_t at = i.s_addr; - if (ERRORS[at] == "") { + if (errrors[at] == "") { std::string ne = "Received " + protocol + " data from " + inet_ntoa(inAddress[x].sin_addr); - LogWarn(VB_E131BRIDGE, "%s\n", ne.c_str()); - WarningHolder::AddWarning(ne); - ERRORS[at] = ne; + LogDebug(VB_E131BRIDGE, "%s\n", ne.c_str()); + WarningHolder::AddWarningTimeout(ne, 30); + errrors[at] = ne; } } msgcnt = recvmmsg(sock, msgs, MAX_MSG, 0, nullptr); diff --git a/src/effects.cpp b/src/effects.cpp index 15774e74c..7a2c23251 100644 --- a/src/effects.cpp +++ b/src/effects.cpp @@ -54,6 +54,7 @@ class FPPeffect { static int effectCount = 0; static int pauseBackgroundEffects = 0; static std::array effects; +static std::list> clearRanges; static std::mutex effectsLock; /* @@ -115,6 +116,7 @@ int IsEffectRunning(void) int result = 0; std::unique_lock lock(effectsLock); result = effectCount; + result |= !clearRanges.empty(); return result; } @@ -221,6 +223,18 @@ void StopEffectHelper(int effectID) { FPPeffect *e = NULL; e = effects[effectID]; + + if (e->fp) { + V2FSEQFile *v2fseq = dynamic_cast(e->fp); + if (!v2fseq && v2fseq->m_sparseRanges.size() == 0) { + for (auto &a : v2fseq->m_sparseRanges) { + clearRanges.push_back(std::pair(a.first, a.second)); + } + } else { + //not sparse and not eseq, entire range + clearRanges.push_back(std::pair(0, e->fp->getChannelCount())); + } + } delete e; effects[effectID] = NULL; effectCount--; @@ -314,9 +328,13 @@ int OverlayEffect(int effectID, char *channelData) d->readFrame((uint8_t*)channelData, FPPD_MAX_CHANNELS); delete d; return 1; - } - else + } else { StopEffectHelper(effectID); + for (auto &rng : clearRanges) { + memset(&channelData[rng.first], 0, rng.second); + } + clearRanges.clear(); + } return 0; } @@ -330,6 +348,12 @@ int OverlayEffects(char *channelData) int dataRead = 0; std::unique_lock lock(effectsLock); + + //for effects that have been stopped, we need to clear the data + for (auto &rng : clearRanges) { + memset(&channelData[rng.first], 0, rng.second); + } + clearRanges.clear(); if (effectCount == 0) { return 0; diff --git a/src/events.cpp b/src/events.cpp index c40423b39..222842356 100644 --- a/src/events.cpp +++ b/src/events.cpp @@ -33,7 +33,7 @@ std::string FPPEvent::getEventFileName(const std::string &id) { return filename; } std::string FPPEvent::getEventFileName() { - char id[6]; + char id[6] = {0}; sprintf(id, "%02d_%02d", majorID, minorID); std::string filename = getEventDirectory(); @@ -232,6 +232,7 @@ int TriggerEventByID(const char *id) void UpgradeEvents() { char id[6]; + memset(id, 0, sizeof(id)); for (int major = 1; major <= MAX_EVENT_MAJOR; major++) { for (int minor = 1; minor <= MAX_EVENT_MAJOR; minor++) { sprintf(id, "%02d_%02d", major, minor); diff --git a/src/fppd.c b/src/fppd.c index 0367383ab..990e12a8e 100644 --- a/src/fppd.c +++ b/src/fppd.c @@ -106,6 +106,7 @@ static void handleCrash(int s) { } free(strs); inCrashHandler = false; + runMainFPPDLoop = 0; if (s != SIGQUIT && s != SIGUSR1) { exit(-1); } @@ -542,6 +543,7 @@ int main(int argc, char *argv[]) if (mqtt) delete mqtt; + MagickLib::DestroyMagick(); curl_global_cleanup(); return 0; @@ -600,6 +602,7 @@ void MainLoop(void) int epollf = epoll_create1(EPOLL_CLOEXEC); for (auto &a : callbacks) { epoll_event event; + memset(&event, 0, sizeof(event)); event.events = EPOLLIN; event.data.fd = a.first; int rc = epoll_ctl(epollf, EPOLL_CTL_ADD, a.first, &event); @@ -618,6 +621,7 @@ void MainLoop(void) static const int MAX_EVENTS = 20; epoll_event events[MAX_EVENTS]; + memset(events, 0, sizeof(events)); int idleCount = 0; while (runMainFPPDLoop) { diff --git a/src/fppversion.sh b/src/fppversion.sh index 378727d58..a13b113da 100644 --- a/src/fppversion.sh +++ b/src/fppversion.sh @@ -179,7 +179,11 @@ cat > ./fppversion_defines.h < static void LogErr(int i, const char *fmt, Args... ar static log4cpp::Category &fseq_logger_base = log4cpp::Category::getInstance(std::string("log_base")); char buf[256]; const char *nfmt = fmt; - if (nfmt[strlen(nfmt) - 1] == '\n') { + if (fmt[strlen(fmt) - 1] == '\n') { strcpy(buf, fmt); - buf[strlen(nfmt) - 1] = 0; + buf[strlen(fmt) - 1] = 0; nfmt = buf; } fseq_logger_base.error(nfmt, args...); @@ -72,9 +72,9 @@ template static void LogInfo(int i, const char *fmt, Args... a static log4cpp::Category &fseq_logger_base = log4cpp::Category::getInstance(std::string("log_base")); char buf[256]; const char *nfmt = fmt; - if (nfmt[strlen(nfmt) - 1] == '\n') { + if (fmt[strlen(fmt) - 1] == '\n') { strcpy(buf, fmt); - buf[strlen(nfmt) - 1] = 0; + buf[strlen(fmt) - 1] = 0; nfmt = buf; } fseq_logger_base.info(nfmt, args...); @@ -83,9 +83,9 @@ template static void LogDebug(int i, const char *fmt, Args... static log4cpp::Category &fseq_logger_base = log4cpp::Category::getInstance(std::string("log_base")); char buf[256]; const char *nfmt = fmt; - if (nfmt[strlen(nfmt) - 1] == '\n') { + if (fmt[strlen(fmt) - 1] == '\n') { strcpy(buf, fmt); - buf[strlen(nfmt) - 1] = 0; + buf[strlen(fmt) - 1] = 0; nfmt = buf; } fseq_logger_base.debug(nfmt, args...); @@ -525,7 +525,7 @@ class UncompressedFrameData : public FSEQFile::FrameData { } } - virtual bool readFrame(uint8_t *data, uint32_t maxChannels) { + virtual bool readFrame(uint8_t *data, uint32_t maxChannels) override { if (m_data == nullptr) return false; uint32_t offset = 0; for (auto &rng : m_ranges) { diff --git a/src/mediaoutput/mpg123.h b/src/mediaoutput/mpg123.h index e90f36927..d058166ce 100644 --- a/src/mediaoutput/mpg123.h +++ b/src/mediaoutput/mpg123.h @@ -40,11 +40,11 @@ class mpg123Output : public MediaOutputBase { public: mpg123Output(std::string mediaFilename, MediaOutputStatus *status); - ~mpg123Output(); + virtual ~mpg123Output(); - int Start(void); - int Stop(void); - int Process(void); + virtual int Start(void) override; + virtual int Stop(void) override; + virtual int Process(void) override; private: void PollMusicInfo(void); diff --git a/src/mediaoutput/ogg123.h b/src/mediaoutput/ogg123.h index b37bcf486..56a96994e 100644 --- a/src/mediaoutput/ogg123.h +++ b/src/mediaoutput/ogg123.h @@ -36,11 +36,11 @@ class ogg123Output : public MediaOutputBase { public: ogg123Output(std::string mediaFilename, MediaOutputStatus *status); - ~ogg123Output(); + virtual ~ogg123Output(); - int Start(void); - int Stop(void); - int Process(void); + virtual int Start(void) override; + virtual int Stop(void) override; + virtual int Process(void) override; private: void PollMusicInfo(void); diff --git a/src/mediaoutput/omxplayer.h b/src/mediaoutput/omxplayer.h index feed6f2c2..5e38b4ba4 100644 --- a/src/mediaoutput/omxplayer.h +++ b/src/mediaoutput/omxplayer.h @@ -31,16 +31,16 @@ class omxplayerOutput : public MediaOutputBase { public: omxplayerOutput(std::string mediaFilename, MediaOutputStatus *status); - ~omxplayerOutput(); + virtual ~omxplayerOutput(); - virtual int Start(void); - virtual int Stop(void); - virtual int Process(void); - virtual int IsPlaying(void); - virtual int Close(void); + virtual int Start(void) override; + virtual int Stop(void) override; + virtual int Process(void) override; + virtual int IsPlaying(void) override; + virtual int Close(void) override; - int AdjustSpeed(int delta); - void SetVolume(int volume); + virtual int AdjustSpeed(int delta) override; + virtual void SetVolume(int volume) override; private: int GetVolumeShift(int volume); diff --git a/src/oled/FPPMainMenu.cpp b/src/oled/FPPMainMenu.cpp index f0afb1885..94afdf7cd 100644 --- a/src/oled/FPPMainMenu.cpp +++ b/src/oled/FPPMainMenu.cpp @@ -98,11 +98,11 @@ class BridgeStatsPage : public ListOLEDPage { virtual ~BridgeStatsPage() {} - virtual void displaying() { + virtual void displaying() override { bool on = true; doIteration(on); } - virtual bool doIteration(bool &displayOn) { + virtual bool doIteration(bool &displayOn) override { std::string d = doCurlGet("http://localhost:32322/fppd/e131stats", 10000); Json::Value result; Json::Reader reader; diff --git a/src/oled/FPPOLEDUtils.h b/src/oled/FPPOLEDUtils.h index cf341ac17..727e766b2 100644 --- a/src/oled/FPPOLEDUtils.h +++ b/src/oled/FPPOLEDUtils.h @@ -41,13 +41,13 @@ class FPPOLEDUtils { std::string pin; std::string mode; std::string edge; - int file; - int pollIndex; + int file = -1; + int pollIndex = -1; std::vector actions; const std::string &checkAction(int i, long long time); - struct gpiod_line *gpiodLine; + struct gpiod_line *gpiodLine = nullptr; }; std::vector actions; diff --git a/src/oled/I2C.c b/src/oled/I2C.c index 37507e9b8..544e28faf 100644 --- a/src/oled/I2C.c +++ b/src/oled/I2C.c @@ -217,7 +217,7 @@ int i2c_multiple_writes(int fd, int num, unsigned char *Ptr_buff) ****************************************************************/ int i2c_write_register(int fd, unsigned char reg_addr_or_cntrl, unsigned char val) { - unsigned char buff[1]; + unsigned char buff[2]; int ret = 0; buff[0] = reg_addr_or_cntrl; buff[1] = val; diff --git a/src/oled/OLEDPages.h b/src/oled/OLEDPages.h index a6e30d719..e54b2b793 100644 --- a/src/oled/OLEDPages.h +++ b/src/oled/OLEDPages.h @@ -22,6 +22,10 @@ class OLEDPage { OLEDPage() : autoDeleteOnHide(false) {} virtual ~OLEDPage() {} + + + OLEDPage(const OLEDPage &) = delete; + void operator=(OLEDPage const &) = delete; virtual void displaying() {} virtual void hiding() {} @@ -63,8 +67,8 @@ class PromptOLEDPage : public TitledOLEDPage { const std::function& itemSelectedCallback); virtual ~PromptOLEDPage() {} - virtual void displaying(); - virtual bool doAction(const std::string &action); + virtual void displaying() override; + virtual bool doAction(const std::string &action) override; virtual void ItemSelected(const std::string &item); protected: virtual void display(); @@ -106,7 +110,7 @@ class MenuOLEDPage : public ListOLEDPage { virtual void itemSelected(const std::string &item); protected: - virtual void display(); + virtual void display() override; int curSelected; std::function itemSelectedCallback; }; diff --git a/src/ping.cpp b/src/ping.cpp index 15cbcf2ba..00018efdd 100644 --- a/src/ping.cpp +++ b/src/ping.cpp @@ -70,6 +70,7 @@ int ping(string target) u_char packet[DEFDATALEN + MAXIPLEN + MAXICMPLEN]; u_char outpack[MAXPACKET]; char hnamebuf[MAXHOSTNAMELEN]; + string hostname; struct icmp *icp; int ret, fromlen, hlen; @@ -80,6 +81,12 @@ int ping(string target) int /*start_t, */end_t; bool cont = true; + memset(outpack, 0, sizeof(outpack)); + memset(packet, 0, sizeof(packet)); + memset(hnamebuf, 0, sizeof(hnamebuf)); + memset(&to, 0, sizeof(to)); + memset(&from, 0, sizeof(to)); + to.sin_family = AF_INET; // try to convert as dotted decimal address, else if that fails assume it's a hostname @@ -143,9 +150,9 @@ int ping(string target) // Watch stdin (fd 0) to see when it has input. FD_ZERO(&rfds); FD_SET(pingSocket, &rfds); - // Wait up to one seconds. - tv.tv_sec = 1; - tv.tv_usec = 0; + // Wait up to 1/4 second. + tv.tv_sec = 0; + tv.tv_usec = 250000; while(cont) { @@ -207,7 +214,7 @@ int ping(string target) } else { - //cout << "No data within one seconds.\n"; + //cout << "No data within 1/4 second.\n"; return 0; } } diff --git a/src/playlist/Playlist.cpp b/src/playlist/Playlist.cpp index 3fd899da2..ed706003f 100644 --- a/src/playlist/Playlist.cpp +++ b/src/playlist/Playlist.cpp @@ -46,6 +46,7 @@ #include "Plugins.h" #include "Playlist.h" #include "settings.h" +#include "Sequence.h" #include "PlaylistEntryBoth.h" #include "PlaylistEntryBranch.h" @@ -497,7 +498,7 @@ int Playlist::StopNow(int forceStop) std::unique_lock lck (m_playlistMutex); m_status = FPP_STATUS_STOPPING_NOW; - if (m_currentSection->at(m_sectionPosition)->IsPlaying()) + if (m_currentSection && m_currentSection->at(m_sectionPosition)->IsPlaying()) m_currentSection->at(m_sectionPosition)->Stop(); SetIdle(); @@ -566,7 +567,7 @@ int Playlist::Process(void) std::unique_lock lck (m_playlistMutex); - if (m_sectionPosition >= m_currentSection->size()) { + if (m_currentSection == nullptr || m_sectionPosition >= m_currentSection->size()) { LogErr(VB_PLAYLIST, "Section position %d is outside of section %s\n", m_sectionPosition, m_currentSectionStr.c_str()); StopNow(); @@ -788,6 +789,8 @@ void Playlist::SetIdle(bool exit) if (m_parent && exit) { playlist = m_parent; PL_CLEANUPS.push_back(this); + } else if (exit) { + sequence->SendBlankingData(); } } diff --git a/src/playlist/PlaylistEntryBoth.cpp b/src/playlist/PlaylistEntryBoth.cpp index 2e048f69a..257e6b86a 100644 --- a/src/playlist/PlaylistEntryBoth.cpp +++ b/src/playlist/PlaylistEntryBoth.cpp @@ -128,7 +128,7 @@ int PlaylistEntryBoth::StartPlaying(void) */ int PlaylistEntryBoth::Process(void) { - LogDebug(VB_PLAYLIST, "PlaylistEntryBoth::Process()\n"); + LogExcess(VB_PLAYLIST, "PlaylistEntryBoth::Process()\n"); if (m_mediaEntry) m_mediaEntry->Process(); m_sequenceEntry->Process(); diff --git a/src/playlist/PlaylistEntryBoth.h b/src/playlist/PlaylistEntryBoth.h index 915b401ae..a333233ac 100644 --- a/src/playlist/PlaylistEntryBoth.h +++ b/src/playlist/PlaylistEntryBoth.h @@ -35,18 +35,18 @@ class PlaylistEntryBoth : public PlaylistEntryBase { public: PlaylistEntryBoth(PlaylistEntryBase *parent = NULL); - ~PlaylistEntryBoth(); + virtual ~PlaylistEntryBoth(); - int Init(Json::Value &config); + virtual int Init(Json::Value &config) override; - int StartPlaying(void); - int Process(void); - int Stop(void); + virtual int StartPlaying(void) override; + virtual int Process(void) override; + virtual int Stop(void) override; - void Dump(void); + virtual void Dump(void) override; - Json::Value GetConfig(void); - Json::Value GetMqttStatus(void); + virtual Json::Value GetConfig(void) override; + virtual Json::Value GetMqttStatus(void) override; std::string GetSequenceName(void) { return m_sequenceName; } std::string GetMediaName(void) { return m_mediaName; } diff --git a/src/playlist/PlaylistEntryBranch.h b/src/playlist/PlaylistEntryBranch.h index 0ce0a275b..9f36d81e0 100644 --- a/src/playlist/PlaylistEntryBranch.h +++ b/src/playlist/PlaylistEntryBranch.h @@ -42,19 +42,19 @@ class PlaylistEntryBranch : public PlaylistEntryBase { public: PlaylistEntryBranch(PlaylistEntryBase *parent = NULL); - ~PlaylistEntryBranch(); + virtual ~PlaylistEntryBranch(); - int Init(Json::Value &config); + virtual int Init(Json::Value &config) override; - int StartPlaying(void); + virtual int StartPlaying(void) override; void SetNext(int isTrue); - void Dump(void); + virtual void Dump(void) override; - Json::Value GetConfig(void); + virtual Json::Value GetConfig(void) override; - virtual PlaylistBranchType GetNextBranchType() { return m_nextBranchType; } + virtual PlaylistBranchType GetNextBranchType() override { return m_nextBranchType; } virtual std::string GetNextSection(void) override { return m_nextSection; } virtual int GetNextItem(void) override { return m_nextItem; } diff --git a/src/playlist/PlaylistEntryChannelTest.h b/src/playlist/PlaylistEntryChannelTest.h index 9885ef170..c1289fa25 100644 --- a/src/playlist/PlaylistEntryChannelTest.h +++ b/src/playlist/PlaylistEntryChannelTest.h @@ -33,17 +33,17 @@ class PlaylistEntryChannelTest : public PlaylistEntryBase { public: PlaylistEntryChannelTest(PlaylistEntryBase *parent = NULL); - ~PlaylistEntryChannelTest(); + virtual ~PlaylistEntryChannelTest(); - int Init(Json::Value &config); + virtual int Init(Json::Value &config) override; - int StartPlaying(void); - int Process(void); - int Stop(void); + virtual int StartPlaying(void) override; + virtual int Process(void) override; + virtual int Stop(void) override; - void Dump(void); + virtual void Dump(void) override; - Json::Value GetConfig(void); + virtual Json::Value GetConfig(void) override; private: int m_duration; diff --git a/src/playlist/PlaylistEntryCommand.h b/src/playlist/PlaylistEntryCommand.h index 6048318f3..887e599fa 100644 --- a/src/playlist/PlaylistEntryCommand.h +++ b/src/playlist/PlaylistEntryCommand.h @@ -27,17 +27,17 @@ class PlaylistEntryCommand : public PlaylistEntryBase { public: PlaylistEntryCommand(PlaylistEntryBase *parent = NULL); - ~PlaylistEntryCommand(); + virtual ~PlaylistEntryCommand(); - int Init(Json::Value &config); + virtual int Init(Json::Value &config) override; - int StartPlaying(void); - int Process(void); - int Stop(void); + virtual int StartPlaying(void) override; + virtual int Process(void) override; + virtual int Stop(void) override; - void Dump(void); + virtual void Dump(void) override; - Json::Value GetConfig(void); + virtual Json::Value GetConfig(void) override; private: std::string m_command; diff --git a/src/playlist/PlaylistEntryDynamic.h b/src/playlist/PlaylistEntryDynamic.h index 9dce15514..cae7cb18e 100644 --- a/src/playlist/PlaylistEntryDynamic.h +++ b/src/playlist/PlaylistEntryDynamic.h @@ -37,18 +37,18 @@ class PlaylistEntryDynamic : public PlaylistEntryBase { public: PlaylistEntryDynamic(PlaylistEntryBase *parent = NULL); - ~PlaylistEntryDynamic(); + virtual ~PlaylistEntryDynamic(); - int Init(Json::Value &config); + virtual int Init(Json::Value &config) override; - int StartPlaying(void); - int Prep(void); - int Process(void); - int Stop(void); + virtual int StartPlaying(void) override; + virtual int Prep(void) override; + virtual int Process(void) override; + virtual int Stop(void) override; - void Dump(void); + virtual void Dump(void) override; - Json::Value GetConfig(void); + virtual Json::Value GetConfig(void) override; private: int ReadFromCommand(void); diff --git a/src/playlist/PlaylistEntryEffect.h b/src/playlist/PlaylistEntryEffect.h index 884327cf4..67dc94d9e 100644 --- a/src/playlist/PlaylistEntryEffect.h +++ b/src/playlist/PlaylistEntryEffect.h @@ -33,17 +33,17 @@ class PlaylistEntryEffect : public PlaylistEntryBase { public: PlaylistEntryEffect(PlaylistEntryBase *parent = NULL); - ~PlaylistEntryEffect(); + virtual ~PlaylistEntryEffect(); - int Init(Json::Value &config); + virtual int Init(Json::Value &config) override; - int StartPlaying(void); - int Process(void); - int Stop(void); + virtual int StartPlaying(void) override; + virtual int Process(void) override; + virtual int Stop(void) override; - void Dump(void); + virtual void Dump(void) override; - Json::Value GetConfig(void); + virtual Json::Value GetConfig(void) override; private: std::string m_effectName; diff --git a/src/playlist/PlaylistEntryEvent.h b/src/playlist/PlaylistEntryEvent.h index 20ddf824c..e4768345e 100644 --- a/src/playlist/PlaylistEntryEvent.h +++ b/src/playlist/PlaylistEntryEvent.h @@ -33,17 +33,17 @@ class PlaylistEntryEvent : public PlaylistEntryBase { public: PlaylistEntryEvent(PlaylistEntryBase *parent = NULL); - ~PlaylistEntryEvent(); + virtual ~PlaylistEntryEvent(); - int Init(Json::Value &config); + virtual int Init(Json::Value &config) override; - int StartPlaying(void); - int Process(void); - int Stop(void); + virtual int StartPlaying(void) override; + virtual int Process(void) override; + virtual int Stop(void) override; - void Dump(void); + virtual void Dump(void) override; - Json::Value GetConfig(void); + virtual Json::Value GetConfig(void) override; private: int m_majorID; diff --git a/src/playlist/PlaylistEntryImage.h b/src/playlist/PlaylistEntryImage.h index 04dfc20eb..643c14486 100644 --- a/src/playlist/PlaylistEntryImage.h +++ b/src/playlist/PlaylistEntryImage.h @@ -43,17 +43,17 @@ using namespace Magick; class PlaylistEntryImage : public PlaylistEntryBase, public FrameBuffer { public: PlaylistEntryImage(PlaylistEntryBase *parent = NULL); - ~PlaylistEntryImage(); + virtual ~PlaylistEntryImage(); - int Init(Json::Value &config); + virtual int Init(Json::Value &config) override; - int StartPlaying(void); - int Process(void); - int Stop(void); + virtual int StartPlaying(void) override; + virtual int Process(void) override; + virtual int Stop(void) override; - void Dump(void); + virtual void Dump(void) override; - Json::Value GetConfig(void); + virtual Json::Value GetConfig(void) override; void PrepLoop(void); diff --git a/src/playlist/PlaylistEntryMQTT.h b/src/playlist/PlaylistEntryMQTT.h index 4f61050d6..385c8d474 100644 --- a/src/playlist/PlaylistEntryMQTT.h +++ b/src/playlist/PlaylistEntryMQTT.h @@ -33,15 +33,15 @@ class PlaylistEntryMQTT : public PlaylistEntryBase { public: PlaylistEntryMQTT(PlaylistEntryBase *parent = NULL); - ~PlaylistEntryMQTT(); + virtual ~PlaylistEntryMQTT(); - int Init(Json::Value &config); + virtual int Init(Json::Value &config) override; - int StartPlaying(void); + virtual int StartPlaying(void) override; - void Dump(void); + virtual void Dump(void) override; - Json::Value GetConfig(void); + virtual Json::Value GetConfig(void) override; private: std::string m_topic; diff --git a/src/playlist/PlaylistEntryMedia.h b/src/playlist/PlaylistEntryMedia.h index fc3633931..783bc3cea 100644 --- a/src/playlist/PlaylistEntryMedia.h +++ b/src/playlist/PlaylistEntryMedia.h @@ -34,21 +34,21 @@ class PlaylistEntryMedia : public PlaylistEntryBase { public: PlaylistEntryMedia(PlaylistEntryBase *parent = NULL); - ~PlaylistEntryMedia(); + virtual ~PlaylistEntryMedia(); - int Init(Json::Value &config); + virtual int Init(Json::Value &config) override; - int PreparePlay(); - int StartPlaying(void); - int Process(void); - int Stop(void); + virtual int PreparePlay(); + virtual int StartPlaying(void) override; + virtual int Process(void) override; + virtual int Stop(void) override; - int HandleSigChild(pid_t pid); + virtual int HandleSigChild(pid_t pid) override; - void Dump(void); + virtual void Dump(void) override; - Json::Value GetConfig(void); - Json::Value GetMqttStatus(void); + virtual Json::Value GetConfig(void) override; + virtual Json::Value GetMqttStatus(void) override; std::string GetMediaName(void) { return m_mediaFilename; } diff --git a/src/playlist/PlaylistEntryPause.h b/src/playlist/PlaylistEntryPause.h index 11e7e1098..d44dd1f28 100644 --- a/src/playlist/PlaylistEntryPause.h +++ b/src/playlist/PlaylistEntryPause.h @@ -35,15 +35,15 @@ class PlaylistEntryPause : public PlaylistEntryBase { PlaylistEntryPause(PlaylistEntryBase *parent = NULL); ~PlaylistEntryPause(); - int Init(Json::Value &config); + virtual int Init(Json::Value &config) override; - int StartPlaying(void); - int Process(void); - int Stop(void); + virtual int StartPlaying(void) override; + virtual int Process(void) override; + virtual int Stop(void) override; - void Dump(void); + virtual void Dump(void) override; - Json::Value GetConfig(void); + virtual Json::Value GetConfig(void) override; private: float m_duration; diff --git a/src/playlist/PlaylistEntryPlaylist.h b/src/playlist/PlaylistEntryPlaylist.h index 913e48a21..4a40a8412 100644 --- a/src/playlist/PlaylistEntryPlaylist.h +++ b/src/playlist/PlaylistEntryPlaylist.h @@ -32,16 +32,16 @@ class PlaylistEntryPlaylist : public PlaylistEntryBase { public: PlaylistEntryPlaylist(PlaylistEntryBase *parent = NULL); - ~PlaylistEntryPlaylist(); + virtual ~PlaylistEntryPlaylist(); - int Init(Json::Value &config); + virtual int Init(Json::Value &config) override; - int StartPlaying(void); - int Process(void); - int Stop(void); + virtual int StartPlaying(void) override; + virtual int Process(void) override; + virtual int Stop(void) override; - void Dump(void); - Json::Value GetConfig(void); + virtual void Dump(void) override; + virtual Json::Value GetConfig(void) override; private: std::string m_playlistName; diff --git a/src/playlist/PlaylistEntryPlugin.h b/src/playlist/PlaylistEntryPlugin.h index f192065fb..72c8038b9 100644 --- a/src/playlist/PlaylistEntryPlugin.h +++ b/src/playlist/PlaylistEntryPlugin.h @@ -33,7 +33,7 @@ class PlaylistEntryPlugin : public PlaylistEntryBase { public: PlaylistEntryPlugin(PlaylistEntryBase *parent = NULL); - ~PlaylistEntryPlugin(); + virtual ~PlaylistEntryPlugin(); private: std::string m_plugin; diff --git a/src/playlist/PlaylistEntryRemap.h b/src/playlist/PlaylistEntryRemap.h index d3a14ca70..5740d8f64 100644 --- a/src/playlist/PlaylistEntryRemap.h +++ b/src/playlist/PlaylistEntryRemap.h @@ -35,15 +35,15 @@ class RemapOutputProcessor; class PlaylistEntryRemap : public PlaylistEntryBase { public: PlaylistEntryRemap(PlaylistEntryBase *parent = NULL); - ~PlaylistEntryRemap(); + virtual ~PlaylistEntryRemap(); - int Init(Json::Value &config); + virtual int Init(Json::Value &config) override; - int StartPlaying(void); + virtual int StartPlaying(void) override; - void Dump(void); + virtual void Dump(void) override; - Json::Value GetConfig(void); + virtual Json::Value GetConfig(void) override; private: std::string m_action; diff --git a/src/playlist/PlaylistEntryScript.h b/src/playlist/PlaylistEntryScript.h index b4e95f296..dab513b47 100644 --- a/src/playlist/PlaylistEntryScript.h +++ b/src/playlist/PlaylistEntryScript.h @@ -35,18 +35,18 @@ class PlaylistEntryScript : public PlaylistEntryBase { PlaylistEntryScript(PlaylistEntryBase *parent = NULL); ~PlaylistEntryScript(); - int Init(Json::Value &config); + virtual int Init(Json::Value &config) override; - int StartPlaying(void); - int Process(void); - int Stop(void); + virtual int StartPlaying(void) override; + virtual int Process(void) override; + virtual int Stop(void) override; bool isChildRunning(); - void Dump(void); + virtual void Dump(void) override; - Json::Value GetConfig(void); - Json::Value GetMqttStatus(void); + virtual Json::Value GetConfig(void) override; + virtual Json::Value GetMqttStatus(void) override; std::string GetScriptName(void) { return m_scriptFilename; } private: diff --git a/src/playlist/PlaylistEntrySequence.h b/src/playlist/PlaylistEntrySequence.h index 699b7073b..e696baaaf 100644 --- a/src/playlist/PlaylistEntrySequence.h +++ b/src/playlist/PlaylistEntrySequence.h @@ -33,19 +33,19 @@ class PlaylistEntrySequence : public PlaylistEntryBase { public: PlaylistEntrySequence(PlaylistEntryBase *parent = NULL); - ~PlaylistEntrySequence(); + virtual ~PlaylistEntrySequence(); - int Init(Json::Value &config); + virtual int Init(Json::Value &config) override; int PreparePlay(); - int StartPlaying(void); - int Process(void); - int Stop(void); + virtual int StartPlaying(void) override; + virtual int Process(void) override; + virtual int Stop(void) override; - void Dump(void); + virtual void Dump(void) override; - Json::Value GetConfig(void); - Json::Value GetMqttStatus(void); + virtual Json::Value GetConfig(void) override; + virtual Json::Value GetMqttStatus(void) override; std::string GetSequenceName(void) { return m_sequenceName; } diff --git a/src/playlist/PlaylistEntryURL.h b/src/playlist/PlaylistEntryURL.h index 43651aed6..fd3159511 100644 --- a/src/playlist/PlaylistEntryURL.h +++ b/src/playlist/PlaylistEntryURL.h @@ -35,19 +35,19 @@ class PlaylistEntryURL : public PlaylistEntryBase { public: PlaylistEntryURL(PlaylistEntryBase *parent = NULL); - ~PlaylistEntryURL(); + virtual ~PlaylistEntryURL(); - int Init(Json::Value &config); + virtual int Init(Json::Value &config) override; - int StartPlaying(void); - int Process(void); - int Stop(void); + virtual int StartPlaying(void) override; + virtual int Process(void) override; + virtual int Stop(void) override; - std::string ReplaceMatches(std::string in); + virtual std::string ReplaceMatches(std::string in) override; - void Dump(void); + virtual void Dump(void) override; - Json::Value GetConfig(void); + Json::Value GetConfig(void) override; private: int ProcessData(void *buffer, size_t size, size_t nmemb); diff --git a/src/playlist/PlaylistEntryVolume.h b/src/playlist/PlaylistEntryVolume.h index 50a07ee6e..c81b7ecfb 100644 --- a/src/playlist/PlaylistEntryVolume.h +++ b/src/playlist/PlaylistEntryVolume.h @@ -33,15 +33,15 @@ class PlaylistEntryVolume : public PlaylistEntryBase { public: PlaylistEntryVolume(PlaylistEntryBase *parent = NULL); - ~PlaylistEntryVolume(); + virtual ~PlaylistEntryVolume(); - int Init(Json::Value &config); + virtual int Init(Json::Value &config) override; - int StartPlaying(void); + virtual int StartPlaying(void) override; - void Dump(void); + virtual void Dump(void) override; - Json::Value GetConfig(void); + Json::Value GetConfig(void) override; private: int m_volume; diff --git a/src/sensors/Sensors.cpp b/src/sensors/Sensors.cpp index 4134abf2a..71b43a599 100644 --- a/src/sensors/Sensors.cpp +++ b/src/sensors/Sensors.cpp @@ -42,8 +42,7 @@ static std::string exec(const std::string &cmd) { class Sensor { public: - Sensor(Json::Value &s) { - label = s["label"].asString(); + explicit Sensor(Json::Value &s) : label(s["label"].asString()) { if (s.isMember("prefix")) { prefix = s["prefix"].asString(); } @@ -58,6 +57,10 @@ class Sensor { } } virtual ~Sensor() {} + + Sensor(Sensor const &) = delete; + void operator=(Sensor const &x) = delete; + virtual double getValue() = 0; void report(Json::Value &s) { @@ -88,10 +91,9 @@ class Sensor { class I2CSensor : public Sensor { public: - I2CSensor(Json::Value &s) : Sensor(s) { - address = s["address"].asString(); - path = s["path"].asString(); - driver = s["driver"].asString(); + explicit I2CSensor(Json::Value &s) : Sensor(s), address(s["address"].asString()), + path(s["path"].asString()), driver(s["driver"].asString()), file(-1) { + if (s.isMember("multiplier")) { multiplier = s["multiplier"].asDouble(); } @@ -113,7 +115,6 @@ class I2CSensor : public Sensor { out.close(); } } - file = -1; int count = 0; while (count < 5 && !CheckForFile(path)) { std::this_thread::sleep_for(std::chrono::milliseconds(100)); @@ -203,16 +204,15 @@ class I2CSensor : public Sensor { class AINSensor : public Sensor { public: - AINSensor(Json::Value &s) : Sensor(s), errcount(0) { - address = s["address"].asString(); - path = s["path"].asString(); + explicit AINSensor(Json::Value &s) : Sensor(s), errcount(0), address(s["address"].asString()), + path(s["path"].asString()), file(-1) { + if (s.isMember("max")) { max = s["max"].asDouble(); } if (s.isMember("min")) { min = s["min"].asDouble(); } - file = -1; } virtual ~AINSensor() { close(file); @@ -259,8 +259,7 @@ class AINSensor : public Sensor { class ThermalSensor : public Sensor { public: - ThermalSensor(Json::Value &s) : Sensor(s) { - path = s["path"].asString(); + explicit ThermalSensor(Json::Value &s) : Sensor(s), path(s["path"].asString()) { file = open(path.c_str(), O_RDONLY); } virtual ~ThermalSensor() { @@ -291,7 +290,7 @@ Sensors Sensors::INSTANCE; void Sensors::Init() { int i = 0; - char path[256]; + char path[256] = {0}; sprintf(path, "/sys/class/thermal/thermal_zone%d/temp", i); while (FileExists(path)) { Json::Value v; diff --git a/src/settings.c b/src/settings.c index f597e4052..5f82c1a77 100644 --- a/src/settings.c +++ b/src/settings.c @@ -81,6 +81,9 @@ void initSettings(int argc, char **argv) char tmpDir[256]; char mediaDir[256]; + memset(tmpDir, 0, sizeof(tmpDir)); + memset(mediaDir, 0, sizeof(mediaDir)); + settings.binDirectory = strdup(dirname(argv[0])); if (strlen(settings.binDirectory) == 1 && settings.binDirectory[0] == '.') { getcwd(tmpDir, sizeof(tmpDir)); @@ -435,8 +438,8 @@ int loadSettings(const char *filename) if (file != NULL) { - char * line = NULL; - size_t len = 0; + char * line = (char*)calloc(256, 1); + size_t len = 256; ssize_t read; int sIndex = 0; diff --git a/src/util/BBBUtils.cpp b/src/util/BBBUtils.cpp index 3d3a30dd3..d648a7fda 100644 --- a/src/util/BBBUtils.cpp +++ b/src/util/BBBUtils.cpp @@ -371,7 +371,7 @@ int BBBPinCapabilities::getPWMRegisterAddress() const { class NullBBBPinCapabilities : public BBBPinCapabilities { public: NullBBBPinCapabilities() : BBBPinCapabilities("-none-", 0) {} - virtual const PinCapabilities *ptr() const { return nullptr; } + virtual const PinCapabilities *ptr() const override { return nullptr; } }; static NullBBBPinCapabilities NULL_BBB_INSTANCE; diff --git a/src/util/BBBUtils.h b/src/util/BBBUtils.h index 338cfe6cd..0261da9fe 100644 --- a/src/util/BBBUtils.h +++ b/src/util/BBBUtils.h @@ -27,17 +27,17 @@ class BBBPinCapabilities : public PinCapabilitiesFluent { virtual int configPin(const std::string& mode = "gpio", - bool directionOut = true) const; + bool directionOut = true) const override; - virtual bool getValue() const; - virtual void setValue(bool i) const; + virtual bool getValue() const override; + virtual void setValue(bool i) const override; virtual int openValueForPoll() const; - virtual bool setupPWM(int maxValueNS = 25500) const; - virtual void setPWMValue(int valueNS) const; - virtual int getPWMRegisterAddress() const; + virtual bool setupPWM(int maxValueNS = 25500) const override; + virtual void setPWMValue(int valueNS) const override; + virtual int getPWMRegisterAddress() const override; - virtual bool supportPWM() const; + virtual bool supportPWM() const override; static void Init(); static const BBBPinCapabilities &getPinByName(const std::string &name); diff --git a/src/util/GPIOUtils.cpp b/src/util/GPIOUtils.cpp index 0d445c136..89b198c64 100644 --- a/src/util/GPIOUtils.cpp +++ b/src/util/GPIOUtils.cpp @@ -26,16 +26,16 @@ class NoPinCapabilities : public PinCapabilitiesFluent { virtual int configPin(const std::string& mode = "gpio", - bool directionOut = true) const { return 0;} + bool directionOut = true) const override { return 0;} - virtual bool getValue() const { return false; } - virtual void setValue(bool i) const {} + virtual bool getValue() const override { return false; } + virtual void setValue(bool i) const override {} - virtual bool setupPWM(int maxValueNS = 25500) const {return false;} - virtual void setPWMValue(int valueNS) const {} + virtual bool setupPWM(int maxValueNS = 25500) const override {return false;} + virtual void setPWMValue(int valueNS) const override {} - virtual int getPWMRegisterAddress() const { return 0;}; - virtual bool supportPWM() const { return true; }; + virtual int getPWMRegisterAddress() const override { return 0;}; + virtual bool supportPWM() const override { return true; }; static void Init() {} static const NoPinCapabilities &getPinByName(const std::string &name); @@ -46,7 +46,7 @@ class NoPinCapabilities : public PinCapabilitiesFluent { class NullNoPinCapabilities : public NoPinCapabilities { public: NullNoPinCapabilities() : NoPinCapabilities("-none-", 0) {} - virtual const PinCapabilities *ptr() const { return nullptr; } + virtual const PinCapabilities *ptr() const override { return nullptr; } }; static NullNoPinCapabilities NULL_PIN_INSTANCE; diff --git a/src/util/MCP23x17Utils.cpp b/src/util/MCP23x17Utils.cpp index e6c5730f3..136939374 100644 --- a/src/util/MCP23x17Utils.cpp +++ b/src/util/MCP23x17Utils.cpp @@ -152,7 +152,7 @@ void MCP23x17PinCapabilities::setValue(bool i) const { class NullMCP23x17GPIOPinCapabilities : public MCP23x17PinCapabilities { public: NullMCP23x17GPIOPinCapabilities() : MCP23x17PinCapabilities("-none-", 0, 0) {} - virtual const PinCapabilities *ptr() const { return nullptr; } + virtual const PinCapabilities *ptr() const override { return nullptr; } }; static NullMCP23x17GPIOPinCapabilities NULL_WP_INSTANCE; diff --git a/src/util/MCP23x17Utils.h b/src/util/MCP23x17Utils.h index b28e45814..1e127b385 100644 --- a/src/util/MCP23x17Utils.h +++ b/src/util/MCP23x17Utils.h @@ -10,16 +10,16 @@ class MCP23x17PinCapabilities : public PinCapabilitiesFluentchannel = channel; file = channel; + speed = baud; + bitsPerWord = 8; if (wiringPiSPISetup (channel, 8000000) < 0) { file = -1; } diff --git a/src/util/WiringPiGPIO.cpp b/src/util/WiringPiGPIO.cpp index 3330d5aa6..b349e4ea9 100644 --- a/src/util/WiringPiGPIO.cpp +++ b/src/util/WiringPiGPIO.cpp @@ -46,7 +46,7 @@ void WPPinCapabilities::setPWMValue(int valueNS) const { class NullWPPinCapabilities : public WPPinCapabilities { public: NullWPPinCapabilities() : WPPinCapabilities("-none-", 0) {} - virtual const PinCapabilities *ptr() const { return nullptr; } + virtual const PinCapabilities *ptr() const override { return nullptr; } }; static NullWPPinCapabilities NULL_WP_INSTANCE; diff --git a/src/util/WiringPiGPIO.h b/src/util/WiringPiGPIO.h index 6382a923e..058440ef7 100644 --- a/src/util/WiringPiGPIO.h +++ b/src/util/WiringPiGPIO.h @@ -11,16 +11,16 @@ class WPPinCapabilities : public PinCapabilitiesFluent { virtual int configPin(const std::string& mode = "gpio", - bool directionOut = true) const; + bool directionOut = true) const override; - virtual bool getValue() const; - virtual void setValue(bool i) const; + virtual bool getValue() const override; + virtual void setValue(bool i) const override; - virtual bool setupPWM(int maxValueNS = 25500) const; - virtual void setPWMValue(int valueNS) const; + virtual bool setupPWM(int maxValueNS = 25500) const override; + virtual void setPWMValue(int valueNS) const override; - virtual int getPWMRegisterAddress() const { return 0;}; - virtual bool supportPWM() const { return true; }; + virtual int getPWMRegisterAddress() const override { return 0;}; + virtual bool supportPWM() const override { return true; }; static void Init(); static const WPPinCapabilities &getPinByName(const std::string &name); diff --git a/upgrade/58/upgrade.sh b/upgrade/58/upgrade.sh new file mode 100755 index 000000000..1479f9823 --- /dev/null +++ b/upgrade/58/upgrade.sh @@ -0,0 +1,15 @@ +#!/bin/bash +##################################### + +echo "Disabling HTTP/2 module" +a2dismod http2 + +# Copy new Apache site config into place +echo "Copying new Apache config into place" +sed -e "s#FPPDIR#${FPPDIR}#g" -e "s#FPPHOME#${FPPHOME}#g" < ${FPPDIR}/etc/apache2.site > /etc/apache2/sites-enabled/000-default.conf + +BINDIR=$(cd $(dirname $0) && pwd) +. ${BINDIR}/../../scripts/common +setSetting rebootFlag 1 +echo "A reboot will be required to get the new Apache config working working" + diff --git a/www/api/controllers/help.php b/www/api/controllers/help.php index a5ec1c10c..29a8c40c6 100644 --- a/www/api/controllers/help.php +++ b/www/api/controllers/help.php @@ -46,7 +46,7 @@ function help_help() [ 'PUT /overlays/model/:ModelName/state', 'Sets the state of the overlay model', '{"State": 1}', 'OK'], [ 'PUT /overlays/model/:ModelName/fill', 'Fills the entire overlay with the given color', '{"RGB": [255, 0, 0]}', 'OK'], [ 'PUT /overlays/model/:ModelName/pixel', 'Sets a specific pixel in the model to the given color', '{"X": 10, "Y": 12, "RGB": [255, 0, 0]}', 'OK'], - [ 'PUT /overlays/model/:ModelName/text', 'Displays text on the overlay model', '{"Message": "Hello", "Position": "L2R", "Font": "Helvetica", "FontSize": 12, "AntiAlias": false, "PixelsPerSecond": 5, "Color": "#FF000"}', 'OK'], + [ 'PUT /overlays/model/:ModelName/text', 'Displays text on the overlay model', '{"Message": "Hello", "Position": "L2R", "Font": "Helvetica", "FontSize": 12, "AntiAlias": false, "PixelsPerSecond": 5, "Color": "#FF000", "AutoEnable": false}', 'OK'], [ 'GET /fppd/log', 'Gets the current log mask', '', '{"log":{"level":"info","mask":"channelout,command,control,e131bridge"},"message":"","respCode":200,"status":"OK"}' ], [ 'GET /fppd/playlists', 'Get the current playing playlists', '', '{"message":"","playlists":["Test"],"respCode":200,"status":"OK"}'], [ 'GET /fppd/e131stats', 'Gets the current bridge mode input statistics', '', ''], diff --git a/www/api/controllers/sequence.php b/www/api/controllers/sequence.php index fa556035e..5f3c27366 100644 --- a/www/api/controllers/sequence.php +++ b/www/api/controllers/sequence.php @@ -47,11 +47,14 @@ function GetSequenceMetaData() { $file = $settings['sequenceDirectory'] . "/" . $sequence; if (substr( $file, -5 ) != ".fseq") { $file = $file . ".fseq"; - } - $cmd = "/opt/fpp/src/fsequtils -j $file 2>&1"; - exec( $cmd, $output); - $js = json_decode($output[0]); - return json($js); + } + if (file_exists($file)) { + $cmd = "/opt/fpp/src/fsequtils -j $file 2>&1"; + exec( $cmd, $output); + $js = json_decode($output[0]); + return json($js); + } + halt(404, "Not found"); } ///////////////////////////////////////////////////////////////////////////// diff --git a/www/multisync.php b/www/multisync.php index 486080bcd..ba6895565 100644 --- a/www/multisync.php +++ b/www/multisync.php @@ -169,6 +169,20 @@ function getFPPSystemStatus(ip, platform) { $('#' + rowID + '_status').html(status); $('#' + rowID + '_elapsed').html(elapsed); $('#' + rowID + '_files').html(files); + + if (data.warnings != null && data.warnings.length > 0) { + var result_style = document.getElementById(rowID + '_warnings').style; + result_style.display = 'table-row'; + var wHTML = ""; + for(var i = 0; i < data.warnings.length; i++) { + wHTML += "" + data.warnings[i] + "
"; + } + $('#' + rowID + '_warningCell').html(wHTML); + } else { + var result_style = document.getElementById(rowID + '_warnings').style; + result_style.display = 'none'; + } + //Expert View Rows if(advancedView === true && data.status_name !== 'unknown') { $('#' + rowID + '_platform').html(data.advancedView.Platform + "
" + data.advancedView.Variant + ""); @@ -300,6 +314,9 @@ function parseFPPSystems(data) { newRow = newRow + ""; $('#fppSystems tbody').append(newRow); + + newRow = ""; + $('#fppSystems tbody').append(newRow); getFPPSystemStatus(ip, data[i].Platform); getFPPSystemInfo(ip, data[i].Platform); diff --git a/www/testing.php b/www/testing.php index 9d4a2058c..cfc84f398 100644 --- a/www/testing.php +++ b/www/testing.php @@ -686,7 +686,7 @@ function StopSequence() Update Interval: 1000 ms

- Test Patterns

+Test Patterns:
Note: RGB patterns have NO knowledge of output setups, models, etc... "R" is the first channel, "G" is the second, etc... If channels do not line up, the colors displayed on pixels may not match.
RGB Patterns:
 Color Order: