Accurate UDP sync for NTP enabled instances

This commit is contained in:
cschwinne 2021-05-30 00:08:24 +02:00
parent 7cbc9d21b5
commit bfc7f56c4d
6 changed files with 54 additions and 32 deletions

View File

@ -1,6 +1,7 @@
#ifndef TFTS_H
#define TFTS_H
#include "wled.h"
#include <FS.h>
#include <TFT_eSPI.h>
@ -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;

View File

@ -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++) {

View File

@ -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

View File

@ -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)
{

View File

@ -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() {

View File

@ -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)