fix: wait out a remote's long press across the millis() wrap

The 500 ms wait that tells a short press from a long one compared
now > await, so a press just before the wrap acted at once. It now
compares the wrap-safe difference. Reconcile Q21 in
SHADE_BEHAVIOUR_PLAN.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
cjkas 2026-10-16 22:41:48 +02:00
parent 4eff50645d
commit 7220f38fcd
3 changed files with 15 additions and 2 deletions

View file

@ -92,7 +92,7 @@ The decisions are the user's. Each question comes with a recommended answer, and
- ~~A group's SunFlag or Flag doesn't make other groups work their flags out again.~~ Fixed (Q20). - ~~A group's SunFlag or Flag doesn't make other groups work their flags out again.~~ Fixed (Q20).
- The self-echo (Q5) and merging group commands into the frame rule (Q8). - The self-echo (Q5) and merging group commands into the frame rule (Q8).
- `lastFrame` doing two jobs (the Q6 revisit). - `lastFrame` doing two jobs (the Q6 revisit).
- The 500 ms long-press deadline is compared as `now > await`, which isn't wrap-safe (not tested). - ~~The 500 ms long-press deadline isn't wrap-safe.~~ Fixed (Q21).
## Constraints ## Constraints

View file

@ -360,7 +360,8 @@ void ShadeBehaviour::onWaitingFrame(uint32_t now) {
return; return;
} }
if(this->lastFrame.processed) return; if(this->lastFrame.processed) return;
if(this->lastFrame.await > 0 && (now > this->lastFrame.await)) { // Wrap-safe: await is now + 500 when the press began.
if(this->lastFrame.await > 0 && static_cast<int32_t>(now - this->lastFrame.await) > 0) {
somfy_commands cmd = this->transformCommand(this->lastFrame.cmd); somfy_commands cmd = this->transformCommand(this->lastFrame.cmd);
switch(cmd) { switch(cmd) {
case somfy_commands::StepUp: case somfy_commands::StepUp:

View file

@ -324,6 +324,17 @@ static void test_remote_my_when_idle_goes_to_the_favorite_after_half_a_second()
r.wait(200); r.wait(200);
ASSERT_POS(60, r.st().target); ASSERT_POS(60, r.st().target);
} }
static void test_remote_my_waits_half_a_second_across_the_millis_wrap() {
Rig r;
r.b.restore(0, 0, 60, -1);
r.now = 0xFFFFFFFF - 200;
r.press(somfy_commands::My);
// The deadline is past the wrap; it still waits for it.
r.wait(300);
ASSERT_POS(0, r.st().target);
r.wait(300);
ASSERT_POS(60, r.st().target);
}
static void test_remote_my_held_sets_the_favorite() { static void test_remote_my_held_sets_the_favorite() {
Rig r; Rig r;
r.b.restore(30, 0, 60, -1); r.b.restore(30, 0, 60, -1);
@ -629,6 +640,7 @@ int main(int argc, char **argv) {
RUN_TEST(test_flipped_shade_sends_the_other_way); RUN_TEST(test_flipped_shade_sends_the_other_way);
RUN_TEST(test_remote_down_and_my_stop); RUN_TEST(test_remote_down_and_my_stop);
RUN_TEST(test_remote_my_when_idle_goes_to_the_favorite_after_half_a_second); RUN_TEST(test_remote_my_when_idle_goes_to_the_favorite_after_half_a_second);
RUN_TEST(test_remote_my_waits_half_a_second_across_the_millis_wrap);
RUN_TEST(test_remote_my_held_sets_the_favorite); RUN_TEST(test_remote_my_held_sets_the_favorite);
RUN_TEST(test_remote_held_up_on_a_tilt_motor_tilts); RUN_TEST(test_remote_held_up_on_a_tilt_motor_tilts);
RUN_TEST(test_remote_step_uses_the_frames_step_size); RUN_TEST(test_remote_step_uses_the_frames_step_size);