`Transceiver::sendFrame` bit-bangs each symbol with `delayMicroseconds`
from the loop task, which runs at FreeRTOS priority 1. On single-core
parts like the ESP32-C3, the WiFi and lwIP tasks run at higher priority
on the same core, so they preempt the loop task when a packet arrives.
That can delay an edge by several hundred microseconds. This firmware's
own decoder only accepts a 640us half-symbol within 30%, so the motor
probably can't decode the frame either. Because RTS is one-way, the
firmware still updates the shade position, and the UI shows the shade
moving even though the motor never got a valid frame.
I measured this with an instrumented build on a C3, sending commands to
a shade that isn't paired to any motor. When commands went out one at a
time, 38% of frames had an edge more than 200us late. With other
traffic (three commands at once, background HTTP requests, or position
updates streaming during a move), 56-71% did, and the worst edge was
2ms late. The shade was set to 2 repeats (three frames per command),
and 8 of the 33 commands sent under load had a late edge in every
frame.
Raise the loop task's priority above the network tasks from the first
hardware sync pulse through the last data bit, then restore it so lwIP
and WiFi can catch up between frames. With the change, out of 738 test
frames, no edge was more than 9us late, and HTTP latency under load was
unchanged. My shades seem more responsive now, but the failures were
intermittent enough that I'm not confident about it. I've only tested
this with 56-bit shades.
* Fixed issue with my position setting out of order when the flip position bit is set.
* Fixed issue with changes to the my labels when a tilt type changes.
* Fixed issue with isAtPosition method to accommodate both tilt and lift capabilities.
* Ensure target position is always the end position during movement checks. Previously, this was only an approximation.