If we don't get a response from a command in a while, resend it. This doesn't
normally happen (it only happened during firmware development), but it makes
command sending more robust, so let's keep it. This also uses a single OVERLAPPED
for a whole command, which is simpler.
This also refactors the panel button code to rely less on WPF bindings.
They just get in the way for anything nontrivial. Doing it this way
lets us treat the panel buttons as an interface for setting colors, to
handle the different fields that are set for the panel colors and floor
color.
This could cause us to stop sending config updates, since we're still
waiting for the previous one to complete. This is probably the cause
of threshold changes, etc. not being applied.
GetFirstActivePadConfig returns a dummy config if nothing is connected, which
didn't have any of its arrays created. Fill in dummy arrays for enabledSensors,
etc. so refreshes don't throw exceptions if they're updated right when the
last controller disconnects. (This is a rare race condition and I've only
seen it while stepping in the debugger and disconnecting while stopped.)
This fixes the pad flickering when dragging the color slider, because it
could briefly use an out-of-date configuration (only really visible when
going between red and white on the left).
If this is used to play GIF animations on the pad, being able to have
it launch on startup is useful.
This is disabled by default and there's no UI to enable it yet.
This is the same as SMX_SetLights, but instead of taking one buffer with a
fixed size, it takes a separate buffer for each pad, and explicitly includes
the size of the buffer rather than assuming it's 864 bytes. SMX_SetLights
and SMX_SetLights2 call into the same underlying update.