From 3a6d5a2682b761b914d611e980a256202f1b1cf6 Mon Sep 17 00:00:00 2001
From: Daniel Friesel <derf@finalrewind.org>
Date: Sun, 9 Jan 2022 22:12:16 +0100
Subject: [PATCH] ws2812b dmap: use double buffering and more efficient RX ring
 buffer

---
 src/app/ws2812b_dmap/main.cc | 88 ++++++++++++++++++++++++++++++------
 1 file changed, 73 insertions(+), 15 deletions(-)

diff --git a/src/app/ws2812b_dmap/main.cc b/src/app/ws2812b_dmap/main.cc
index ed9b083..7e953e3 100644
--- a/src/app/ws2812b_dmap/main.cc
+++ b/src/app/ws2812b_dmap/main.cc
@@ -19,6 +19,7 @@
 
 #define BUF_SIZE 36
 #define BUF_MAX ((BUF_SIZE)-1)
+#define RINGBUF_SIZE ((BUF_SIZE)+2)
 
 #define NUM_PIXELS 256
 
@@ -27,21 +28,24 @@ Adafruit_NeoPixel np(NUM_PIXELS, GPIO::pb0, NEO_GRB+NEO_KHZ800);
 #define MYADDRESS (0x0006)
 
 volatile uint16_t address;
+volatile uint8_t ringbuf[RINGBUF_SIZE];
+volatile uint8_t ringbuf_byte = 0;
+volatile uint8_t ringbuf_bitmask = 0x80;
 volatile uint8_t buf[BUF_SIZE];
 volatile uint8_t done;
 
 void update()
 {
-	if (buf[35] > 100) {
-		buf[35] = 100;
+	if (buf[0] > 100) {
+		buf[0] = 100;
 	}
-	if (buf[32] + buf[33] + buf[34] > 50) {
-		buf[32] = 0;
-		buf[33] = 0;
-		buf[34] = 5;
+	if (buf[1] + buf[2] + buf[3] > 50) {
+		buf[1] = 5;
+		buf[2] = 0;
+		buf[3] = 0;
 	}
-	uint32_t color = np.Color(buf[34], buf[33], buf[32]);
-	uint8_t rgb = buf[35];
+	uint32_t color = np.Color(buf[1], buf[2], buf[3]);
+	uint8_t rgb = buf[0];
 	for (uint8_t col = 0; col < 32; col++) {
 		for (uint8_t row = 0; row < 8; row++) {
 			uint8_t pixel_index = col*8;
@@ -53,7 +57,7 @@ void update()
 			if (rgb) {
 				color = np.gamma32(np.ColorHSV(((uint16_t)col*8+row) * 255, 255, rgb));
 			}
-			if (buf[col] & _BV(row)) {
+			if (buf[31-col+4] & _BV(row)) {
 				np.setPixelColor(pixel_index, color);
 			} else {
 				np.setPixelColor(pixel_index, 0);
@@ -63,6 +67,40 @@ void update()
 	np.show();
 }
 
+void next_bit(uint8_t *byte, uint8_t *mask, uint8_t const size)
+{
+	if (*mask > 0x01) {
+		*mask >>= 1;
+	} else {
+		*byte = (*byte + 1) % size;
+		*mask = 0x80;
+	}
+}
+
+void ringbuf_to_buf(void)
+{
+	uint8_t read_byte = ringbuf_byte;
+	uint8_t read_bitmask = ringbuf_bitmask;
+
+	// byte[bitmask] is the next bit that would be written -- and, thanks to
+	// the buffer size, also the most significant bit of message byte 0.
+
+	for (uint8_t write_byte = 0; write_byte < BUF_SIZE; write_byte++) {
+		buf[write_byte] = 0;
+		for (uint8_t write_bitmask = 0x80; write_bitmask > 0; write_bitmask >>= 1) {
+			if (ringbuf[read_byte] & read_bitmask) {
+				buf[write_byte] |= write_bitmask;
+			}
+			if (read_bitmask > 0x01) {
+				read_bitmask >>= 1;
+			} else {
+				read_byte = (read_byte + 1) % RINGBUF_SIZE;
+				read_bitmask = 0x80;
+			}
+		}
+	}
+}
+
 int main(void)
 {
 
@@ -85,6 +123,21 @@ int main(void)
 	while (1) {
 		arch.idle();
 		if (done) {
+			/*
+			kout << dec << "done, byte=" << ringbuf_byte << hex << " bitmask=" << ringbuf_bitmask << "  ringbuf = " << hex;
+			for (uint8_t i = 0; i < RINGBUF_SIZE; i++) {
+				kout << ringbuf[i] << " ";
+			}
+			kout << endl;
+			*/
+			ringbuf_to_buf();
+			/*
+			kout << "update, buf = " << hex;
+			for (uint8_t i = 0; i < BUF_SIZE; i++) {
+				kout << buf[i] << " ";
+			}
+			kout << endl;
+			*/
 			update();
 			done = 0;
 		}
@@ -95,17 +148,22 @@ int main(void)
 
 ISR(INT1_vect)
 {
-	if (CLOCK_HI) {
-		for (uint8_t i = BUF_MAX; i > 0; i--) {
-			buf[i] = (buf[i] << 1) | (buf[i-1] >> 7);
-		}
-		buf[0] = (buf[0] << 1) | (address >> 15);
-		address = (address << 1) | DATA_BIT;
+	if (CLOCK_HI && !done) {
 		if (DATA_BIT) {
+			ringbuf[ringbuf_byte] |= ringbuf_bitmask;
+			address = (address << 1) | 1;
 			gpio.led_on(0);
 		} else {
+			ringbuf[ringbuf_byte] &= ~ringbuf_bitmask;
+			address = (address << 1) | 0;
 			gpio.led_off(0);
 		}
+		if (ringbuf_bitmask > 0x01) {
+			ringbuf_bitmask >>= 1;
+		} else {
+			ringbuf_byte = (ringbuf_byte + 1) % RINGBUF_SIZE;
+			ringbuf_bitmask = 0x80;
+		}
 	}
 	else if (DATA_HI && (address == MYADDRESS)) {
 		done = 1;
-- 
GitLab