From c36382ba4fe37f29cb2faab2afc9df8b8d64c08e Mon Sep 17 00:00:00 2001
From: Micah Elizabeth Scott <micah@scanlime.org>
Date: Tue, 23 Jul 2013 17:07:19 -0700
Subject: [PATCH] Simple timed interpolation

---
 examples/usb-basic.py  |  2 +-
 firmware/fadecandy.cpp | 28 +++++++++++++++++++++++++---
 firmware/fc_usb.cpp    |  1 +
 firmware/fc_usb.h      |  1 +
 4 files changed, 28 insertions(+), 4 deletions(-)

diff --git a/examples/usb-basic.py b/examples/usb-basic.py
index 30bd077..42f2b5a 100755
--- a/examples/usb-basic.py
+++ b/examples/usb-basic.py
@@ -59,5 +59,5 @@ while True:
 		#time.sleep(0.1)
 
 	print
-	time.sleep(2)
+	time.sleep(0.1)
 
diff --git a/firmware/fadecandy.cpp b/firmware/fadecandy.cpp
index f29414f..5ad420d 100644
--- a/firmware/fadecandy.cpp
+++ b/firmware/fadecandy.cpp
@@ -39,6 +39,29 @@ static OctoWS2811z leds(LEDS_PER_STRIP, ledBuffer, WS2811_800kHz);
 static int8_t residual[CHANNELS_TOTAL];
 
 
+static uint32_t calculateInterpCoefficient()
+{
+    /*
+     * Calculate our interpolation coefficient. This is a value between
+     * 0x0000 and 0x10000, representing some point in between fbPrev and fbNext.
+     *
+     * We timestamp each frame at the moment its final packet has been received.
+     * In other words, fbNew has no valid timestamp yet, and fbPrev/fbNext both
+     * have timestamps in the recent past.
+     *
+     * fbNext's timestamp indicates when both fbPrev and fbNext entered their current
+     * position in the keyframe queue. The difference between fbPrev and fbNext indicate
+     * how long the interpolation between those keyframes should take.
+     */
+
+    uint32_t now = millis();
+    uint32_t tsPrev = buffers.fbPrev->timestamp;
+    uint32_t tsNext = buffers.fbNext->timestamp;
+
+    uint32_t scaled = ((now - tsNext) << 16) / (tsNext - tsPrev);
+    return std::min<uint32_t>(scaled, 0x10000);
+}
+
 ALWAYS_INLINE static inline uint32_t lutInterpolate(const uint16_t *lut, uint32_t arg)
 {
     /*
@@ -54,7 +77,7 @@ ALWAYS_INLINE static inline uint32_t lutInterpolate(const uint16_t *lut, uint32_
     return (lut[index] * invAlpha + lut[index + 1] * alpha) >> 8;
 }
 
-static inline uint32_t updatePixel(uint32_t icPrev, uint32_t icNext,
+static uint32_t updatePixel(uint32_t icPrev, uint32_t icNext,
     const uint8_t *pixelPrev, const uint8_t *pixelNext,
     const uint16_t *lut, int8_t *pResidual)
 {
@@ -416,8 +439,7 @@ extern "C" int main()
 
     while (1) {
         buffers.handleUSB();
-
-        updateDrawBuffer((millis() << 4) & 0xFFFF);
+        updateDrawBuffer(calculateInterpCoefficient());
         leds.show();
 
         // Optionally disable dithering by clearing our residual buffer every frame.
diff --git a/firmware/fc_usb.cpp b/firmware/fc_usb.cpp
index de1ec1f..3642239 100644
--- a/firmware/fc_usb.cpp
+++ b/firmware/fc_usb.cpp
@@ -86,6 +86,7 @@ void fcBuffers::handleUSB()
 void fcBuffers::finalizeFramebuffer()
 {
     fcFramebuffer *recycle = fbPrev;
+    fbNew->timestamp = millis();
     fbPrev = fbNext;
     fbNext = fbNew;
     fbNew = recycle;
diff --git a/firmware/fc_usb.h b/firmware/fc_usb.h
index e975cde..5d69081 100644
--- a/firmware/fc_usb.h
+++ b/firmware/fc_usb.h
@@ -36,6 +36,7 @@ template <unsigned tSize>
 struct fcPacketBuffer
 {
     usb_packet_t *packets[tSize];
+    uint32_t timestamp;
 
     fcPacketBuffer()
     {
-- 
GitLab