Skip to content

Commit 6f26fbe

Browse files
committed
Some minor fixes based on futher review of recent commits
1 parent efaca5e commit 6f26fbe

5 files changed

Lines changed: 61 additions & 12 deletions

File tree

src/OutputMonitor.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -596,7 +596,9 @@ void OutputMonitor::RemovePortConfiguration(int port, const Json::Value& config)
596596
// fusePins is keyed by the interrupt pin's name -- erasing it here
597597
// is what lets a later AddPortConfiguration re-register the
598598
// callback; leaving it behind means fuse trips are silently
599-
// ignored after a config reload.
599+
// ignored after a config reload. getPinByName() matches on name
600+
// exactly (there are no aliases), so the name here is the same
601+
// string the add side keyed on.
600602
bool sharedInterrupt = false;
601603
for (auto other : portPins) {
602604
if (other && other != pi && other->eFuseInterruptPin == pi->eFuseInterruptPin) {
@@ -665,9 +667,14 @@ void OutputMonitor::AddPortConfiguration(int port, const Json::Value& pinConfig,
665667
if (pinConfig.isMember("eFusePin")) {
666668
if (pinConfig.isMember("eFuseInterruptPin")) {
667669
std::string eFuseInterruptPin = pinConfig.get("eFuseInterruptPin", "").asString();
668-
bool eFuseInterruptHigh = false;
670+
// A leading '!' is stripped but carries no meaning here, and there
671+
// is deliberately no inverted-interrupt flag to go with it: the
672+
// callback below ignores the edge value it is handed and re-reads
673+
// every affected port's eFusePin, so which edge announced the trip
674+
// cannot change the outcome. (The pin is registered for BOTH edges
675+
// anyway -- some i2c expanders mislabel a single-edge request -- so
676+
// a polarity flag would have nothing to act on.)
669677
if (eFuseInterruptPin[0] == '!') {
670-
eFuseInterruptHigh = true;
671678
eFuseInterruptPin = eFuseInterruptPin.substr(1);
672679
}
673680
std::string postFix = "";

src/Scheduler.cpp

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,16 @@ Scheduler::Scheduler() :
7575
}
7676

7777
m_lastProcTime = time(NULL);
78+
// Seed the FPP-command catch-up window to now rather than leaving it at the
79+
// epoch. CheckScheduledItems() fires any command whose second falls in
80+
// (m_lastCommandCheckTime, now], which exists so a second this process
81+
// MISSED -- a slow midnight reload, an NTP step -- still runs. A second
82+
// that passed before this process existed was never missed by it, and the
83+
// 60s catch-up cap is not a substitute: from 0 every start would replay the
84+
// preceding minute of commands, so a scheduled "Outputs Off" or a restart
85+
// would run a second time on every restart, and repeatedly in a restart
86+
// loop.
87+
m_lastCommandCheckTime = m_lastProcTime;
7888
LoadScheduleFromFile();
7989
}
8090

@@ -1472,11 +1482,20 @@ static bool ParseIntArg(const std::string& str, int& out) {
14721482
errno = 0;
14731483
long v = strtol(start, &end, 10);
14741484

1485+
// "Consumed nothing" has to be decided BEFORE the trailing-whitespace skip
1486+
// below moves `end`: strtol() skips leading whitespace itself, so an
1487+
// all-whitespace argument leaves end == start with v == 0, and skipping
1488+
// first walks end to the terminator and makes the test pass -- reporting a
1489+
// successful parse of 0 for an argument that held no number at all.
1490+
if (end == start) {
1491+
return false;
1492+
}
1493+
14751494
while ((*end == ' ') || (*end == '\t')) {
14761495
end++;
14771496
}
14781497

1479-
if ((end == start) || (*end != '\0') || (errno == ERANGE) ||
1498+
if ((*end != '\0') || (errno == ERANGE) ||
14801499
(v < INT_MIN) || (v > INT_MAX)) {
14811500
return false;
14821501
}

src/Sequence.cpp

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -504,17 +504,21 @@ void Sequence::queuePreset(const std::string& preset, std::map<std::string, std:
504504
// with no sequence locks held; a preset that re-enters the sequence (or
505505
// queues further presets) is therefore safe.
506506
Timers::INSTANCE.addTimer("SequencePresets", GetTimeMS(), [this]() {
507-
std::unique_lock<std::mutex> l(m_pendingPresetsLock);
508-
while (!m_pendingPresets.empty()) {
509-
auto p = std::move(m_pendingPresets.front());
510-
m_pendingPresets.pop_front();
511-
l.unlock();
512-
CommandManager::INSTANCE.TriggerPreset(p.first, p.second);
513-
l.lock();
514-
}
507+
drainPendingPresets();
515508
});
516509
}
517510

511+
void Sequence::drainPendingPresets() {
512+
std::unique_lock<std::mutex> l(m_pendingPresetsLock);
513+
while (!m_pendingPresets.empty()) {
514+
auto p = std::move(m_pendingPresets.front());
515+
m_pendingPresets.pop_front();
516+
l.unlock();
517+
CommandManager::INSTANCE.TriggerPreset(p.first, p.second);
518+
l.lock();
519+
}
520+
}
521+
518522
void Sequence::StartSequence() {
519523
// Callers reach this without m_sequenceLock (the command handler and the
520524
// playlist), so the name has to be snapshotted rather than read raw.

src/Sequence.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,14 @@ class Sequence {
7373
// freed buffer; copying under m_seqFilenameLock is the only safe read.
7474
std::string GetSeqFilenameCopy() const;
7575

76+
// Run every queued sequence preset now, on the calling thread. Normally
77+
// driven by the main-loop timer queuePreset() arms; called directly once
78+
// during shutdown, because a preset queued in the last loop iteration
79+
// (a sequence that ended, or a stop command, right as the loop exits) has
80+
// no later tick to fire on and would otherwise be dropped. MUST be called
81+
// with no sequence lock held -- presets run arbitrary commands.
82+
void drainPendingPresets();
83+
7684
int GetSeqStepTime() const { return m_seqStepTime; }
7785
void BlankSequenceData(bool clearBridge = false);
7886

src/fppd.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1122,6 +1122,17 @@ int main(int argc, char* argv[]) {
11221122
// incomplete and cause problems with summary
11231123
// PublishStatsForce("Shutdown"); // not background
11241124

1125+
// Sequence presets (SEQUENCE_STOPPED and the FSEQ frame-triggered commands)
1126+
// are queued for the main loop rather than run at their call site, which
1127+
// holds the sequence locks. A preset queued during the final loop
1128+
// iteration -- a sequence that ended, or a stop command, landing just as
1129+
// runMainFPPDLoop goes to 0 -- has no later tick to fire on. Drain it here
1130+
// instead: still before FPPD_STOPPED, so the ordering a user would expect
1131+
// between the two is preserved, and well before CommandManager::Cleanup().
1132+
if (sequence) {
1133+
sequence->drainPendingPresets();
1134+
}
1135+
11251136
if (CommandManager::INSTANCE.HasPreset("FPPD_STOPPED")) {
11261137
CommandManager::INSTANCE.TriggerPreset("FPPD_STOPPED");
11271138
}

0 commit comments

Comments
 (0)