From bfc7f56c4dfea196fe496adb68f45c181b376f62 Mon Sep 17 00:00:00 2001 From: cschwinne Date: Sun, 30 May 2021 00:08:24 +0200 Subject: [PATCH] Accurate UDP sync for NTP enabled instances --- usermods/EleksTube_IPS/TFTs.h | 4 +++- wled00/FX.cpp | 30 ++++++++++++----------------- wled00/FX.h | 2 +- wled00/ntp.cpp | 7 ++++++- wled00/src/dependencies/toki/Toki.h | 17 ++++++++++++---- wled00/udp.cpp | 26 ++++++++++++++++++------- 6 files changed, 54 insertions(+), 32 deletions(-) diff --git a/usermods/EleksTube_IPS/TFTs.h b/usermods/EleksTube_IPS/TFTs.h index e9629904..ca2f4243 100644 --- a/usermods/EleksTube_IPS/TFTs.h +++ b/usermods/EleksTube_IPS/TFTs.h @@ -1,6 +1,7 @@ #ifndef TFTS_H #define TFTS_H +#include "wled.h" #include #include @@ -92,9 +93,10 @@ private: uint16_t padding = (4 - ((w * 3) & 3)) & 3; uint8_t lineBuffer[w * 3 + padding]; + uint8_t serviceStrip = (!realtimeMode || realtimeOverride) ? 7 : 0; // row is decremented as the BMP image is drawn bottom up for (row = h-1; row >= 0; row--) { - if (row & 0b00000111 == 7) strip.service(); //still refresh backlight to mitigate stutter every few rows + if ((row & 0b00000111) == serviceStrip) strip.service(); //still refresh backlight to mitigate stutter every few rows bmpFS.read(lineBuffer, sizeof(lineBuffer)); uint8_t* bptr = lineBuffer; diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 725f6b1d..9a399afd 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -42,30 +42,24 @@ uint16_t WS2812FX::mode_static(void) { * Blink/strobe function * Alternate between color1 and color2 * if(strobe == true) then create a strobe effect - * NOTE: Maybe re-rework without timer */ uint16_t WS2812FX::blink(uint32_t color1, uint32_t color2, bool strobe, bool do_palette) { - uint16_t stateTime = SEGENV.aux1; uint32_t cycleTime = (255 - SEGMENT.speed)*20; - uint32_t onTime = 0; - uint32_t offTime = cycleTime; - - if (!strobe) { - onTime = (cycleTime * SEGMENT.intensity) >> 8; - offTime = cycleTime - onTime; + uint32_t onTime = FRAMETIME; + if (!strobe) onTime += ((cycleTime * SEGMENT.intensity) >> 8); + cycleTime += FRAMETIME*2; + uint32_t it = now / cycleTime; + uint32_t rem = now % cycleTime; + + bool on = false; + if (it != SEGENV.step //new iteration, force on state for one frame, even if set time is too brief + || rem <= onTime) { + on = true; } - stateTime = ((SEGENV.aux0 & 1) == 0) ? onTime : offTime; - stateTime += 20; - - if (now - SEGENV.step > stateTime) - { - SEGENV.aux0++; - SEGENV.aux1 = stateTime; - SEGENV.step = now; - } + SEGENV.step = it; //save previous iteration - uint32_t color = ((SEGENV.aux0 & 1) == 0) ? color1 : color2; + uint32_t color = on ? color1 : color2; if (color == color1 && do_palette) { for(uint16_t i = 0; i < SEGLEN; i++) { diff --git a/wled00/FX.h b/wled00/FX.h index 12eb11f6..77638aed 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -75,7 +75,7 @@ #define SEGENV _segment_runtimes[_segment_index] #define SEGLEN _virtualSegmentLength #define SEGACT SEGMENT.stop -#define SPEED_FORMULA_L 5 + (50*(255 - SEGMENT.speed))/SEGLEN +#define SPEED_FORMULA_L 5U + (50U*(255U - SEGMENT.speed))/SEGLEN #define RESET_RUNTIME memset(_segment_runtimes, 0, sizeof(_segment_runtimes)) // some common colors diff --git a/wled00/ntp.cpp b/wled00/ntp.cpp index bedad668..4014e1fb 100644 --- a/wled00/ntp.cpp +++ b/wled00/ntp.cpp @@ -6,6 +6,7 @@ * Acquires time from NTP server */ //#define WLED_DEBUG_NTP +#define NTP_SYNC_INTERVAL 42000UL //Get fresh NTP time about twice per day Timezone* tz; @@ -143,6 +144,10 @@ void handleTime() { if (toki.isTick()) //true only in the first loop after a new second started { + #ifdef WLED_DEBUG_NTP + Serial.print(F("TICK! ")); + toki.printTime(toki.getTime()); + #endif updateLocalTime(); checkTimers(); checkCountdown(); @@ -152,7 +157,7 @@ void handleTime() { void handleNetworkTime() { - if (ntpEnabled && ntpConnected && millis() - ntpLastSyncTime > 50000000L && WLED_CONNECTED) + if (ntpEnabled && ntpConnected && millis() - ntpLastSyncTime > (1000*NTP_SYNC_INTERVAL) && WLED_CONNECTED) { if (millis() - ntpPacketSentTime > 10000) { diff --git a/wled00/src/dependencies/toki/Toki.h b/wled00/src/dependencies/toki/Toki.h index 8a6892f8..e7f12a45 100644 --- a/wled00/src/dependencies/toki/Toki.h +++ b/wled00/src/dependencies/toki/Toki.h @@ -103,16 +103,25 @@ class Toki { return unix; } - uint32_t msDifference(Time &t0, Time &t1) { + //gets the absolute difference between two timestamps in milliseconds + uint32_t msDifference(const Time &t0, const Time &t1) { bool t1BiggerSec = (t1.sec > t0.sec); uint32_t secDiff = (t1BiggerSec) ? t1.sec - t0.sec : t0.sec - t1.sec; uint32_t t0ms = t0.ms, t1ms = t1.ms; - if (t1BiggerSec) t1ms += secDiff; - else t0ms += secDiff; + if (t1BiggerSec) t1ms += secDiff*1000; + else t0ms += secDiff*1000; uint32_t msDiff = (t1ms > t0ms) ? t1ms - t0ms : t0ms - t1ms; return msDiff; } + //return true if t1 is later than t0 + bool isLater(const Time &t0, const Time &t1) { + if (t1.sec > t0.sec) return true; + if (t1.sec < t0.sec) return false; + if (t1.ms > t0.ms) return true; + return false; + } + void adjust(Time&t, int32_t offset) { int32_t secs = offset /1000; int32_t ms = offset - secs*1000; @@ -139,7 +148,7 @@ class Toki { } void resetTick() { - tick = TickT::inactive; + if (tick == TickT::active) tick = TickT::inactive; } bool isTick() { diff --git a/wled00/udp.cpp b/wled00/udp.cpp index e58bd714..ad6e727a 100644 --- a/wled00/udp.cpp +++ b/wled00/udp.cpp @@ -245,6 +245,7 @@ void handleNotifications() } } + bool timebaseUpdated = false; //apply effects from notification if (version < 200 && (receiveNotificationEffects || !someSel)) { @@ -258,21 +259,32 @@ void handleNotifications() t += PRESUMED_NETWORK_DELAY; //adjust trivially for network delay t -= millis(); strip.timebase = t; + timebaseUpdated = true; } } //adjust system time, but only if sender is more accurate than self - if (version > 7 && udpIn[29] > toki.getTimeSource()) + if (version > 7) { Toki::Time tm; tm.sec = (udpIn[30] << 24) | (udpIn[31] << 16) | (udpIn[32] << 8) | (udpIn[33]); tm.ms = (udpIn[34] << 8) | (udpIn[35]); - toki.adjust(tm, PRESUMED_NETWORK_DELAY); //adjust trivially for network delay - uint8_t ts = TOKI_TS_UDP; - if (udpIn[29] > 99) ts = TOKI_TS_UDP_NTP; - else if (udpIn[29] >= TOKI_TS_SEC) ts = TOKI_TS_UDP_SEC; - toki.setTime(tm, ts); - //TODO: even receive this if own time source is better, to offset network delay from timebase + if (udpIn[29] > toki.getTimeSource()) { //if sender's time source is more accurate + toki.adjust(tm, PRESUMED_NETWORK_DELAY); //adjust trivially for network delay + uint8_t ts = TOKI_TS_UDP; + if (udpIn[29] > 99) ts = TOKI_TS_UDP_NTP; + else if (udpIn[29] >= TOKI_TS_SEC) ts = TOKI_TS_UDP_SEC; + toki.setTime(tm, ts); + } else if (timebaseUpdated && toki.getTimeSource() > 99) { //if we both have good times, get a more accurate timebase + Toki::Time myTime = toki.getTime(); + uint32_t diff = toki.msDifference(tm, myTime); + strip.timebase -= PRESUMED_NETWORK_DELAY; //no need to presume, use difference between NTP times at send and receive points + if (toki.isLater(tm, myTime)) { + strip.timebase += diff; + } else { + strip.timebase -= diff; + } + } } if (version > 3)