Refactor SMXManager::SendLightUpdates to queue multiple lights commands if possible.

This also fixes a memory leak if lights are queued too quickly.
This commit is contained in:
Glenn Maynard 2019-06-09 21:34:55 -05:00
parent 0c19451d7d
commit 69b2239922
2 changed files with 37 additions and 16 deletions

View File

@ -486,26 +486,46 @@ void SMX::SMXManager::ReenableAutoLights()
void SMX::SMXManager::SendLightUpdates() void SMX::SMXManager::SendLightUpdates()
{ {
g_Lock.AssertLockedByCurrentThread(); g_Lock.AssertLockedByCurrentThread();
if(m_aPendingLightsCommands.empty())
// If previous lights commands are being sent, wait for them to complete before
// queueing more.
if(m_iLightsCommandsInProgress > 0)
return; return;
const PendingCommand &command = m_aPendingLightsCommands[0]; // If we have more than one command queued, we can queue several of them if we're
// before fTimeToSend. For the V4 pads that require more commands, this lets us queue
// See if it's time to send the next command. We only need to look at the first // the whole lights update at once. V3 pads require us to time commands, so we can't
// command, since these are always sorted. // spam both lights commands at once, which is handled by fTimeToSend.
if(command.fTimeToSend > GetMonotonicTime()) while( !m_aPendingLightsCommands.empty() )
return;
// Send the lights command for each pad. If either pad isn't connected, this won't do
// anything.
for(int iPad = 0; iPad < 2; ++iPad)
{ {
if(!command.sPadCommand[iPad].empty()) // Send the lights command for each pad. If either pad isn't connected, this won't do
m_pDevices[iPad]->SendCommandLocked(command.sPadCommand[iPad]); // anything.
} const PendingCommand &command = m_aPendingLightsCommands[0];
// Remove the command we've sent. // See if it's time to send this command.
m_aPendingLightsCommands.erase(m_aPendingLightsCommands.begin(), m_aPendingLightsCommands.begin()+1); if(command.fTimeToSend > GetMonotonicTime())
break;
for(int iPad = 0; iPad < 2; ++iPad)
{
if(!command.sPadCommand[iPad].empty())
{
// Count the number of commands we've queued. We won't send any more until
// this reaches 0 and all queued commands were sent.
m_iLightsCommandsInProgress++;
// The completion callback is guaranteed to always be called, even if the controller
// disconnects and the command wasn't sent.
m_pDevices[iPad]->SendCommandLocked(command.sPadCommand[iPad], [this, iPad](string response) {
g_Lock.AssertLockedByCurrentThread();
m_iLightsCommandsInProgress--;
});
}
}
// Remove the command we've sent.
m_aPendingLightsCommands.erase(m_aPendingLightsCommands.begin(), m_aPendingLightsCommands.begin()+1);
}
} }
void SMX::SMXManager::SetPanelTestMode(PanelTestMode mode) void SMX::SMXManager::SetPanelTestMode(PanelTestMode mode)

View File

@ -76,6 +76,7 @@ private:
string sPadCommand[2]; string sPadCommand[2];
}; };
vector<PendingCommand> m_aPendingLightsCommands; vector<PendingCommand> m_aPendingLightsCommands;
int m_iLightsCommandsInProgress = 0;
double m_fDelayLightCommandsUntil = 0; double m_fDelayLightCommandsUntil = 0;
// Panel test mode. This is separate from the sensor test mode (pressure display), // Panel test mode. This is separate from the sensor test mode (pressure display),