From 9181cec46c4b402cfbba8c02d37f350c7857be16 Mon Sep 17 00:00:00 2001
From: Jeff Brown <jeff.brown@gmail.com>
Date: Tue, 13 Jan 2015 19:16:07 -0800
Subject: [PATCH] Support reverse mappings for Fadecandy strips.

Use negative count to map pixels in reverse order along
a strip.
---
 doc/fc_server_config.md |  5 ++++-
 server/src/fcdevice.cpp | 38 ++++++++++++++++++++++++++++----------
 2 files changed, 32 insertions(+), 11 deletions(-)

diff --git a/doc/fc_server_config.md b/doc/fc_server_config.md
index cca6eb1..ad7852d 100644
--- a/doc/fc_server_config.md
+++ b/doc/fc_server_config.md
@@ -102,6 +102,8 @@ Supported mapping objects for Fadecandy devices:
     * The "Color channels" must be a 3-letter string, where each letter corresponds to one of the WS2811 outputs.
     * Each letter can be "r", "g", or "b" to choose the red, green, or blue channel respectively, or "l" to use the average luminosity.
 
+If the pixel count is negative, the output pixels are mapped in reverse order starting at the first output pixel index and decrementing the index for each successive pixel up to the absolute value of the pixel count.
+
 Other settings for Fadecandy devices:
 
 Name         | Values               | Default | Description
@@ -110,7 +112,7 @@ led          | true / false / null  | null    | Is the LED on, off, or under aut
 dither       | true / false         | true    | Is dithering enabled?
 interpolate  | true / false         | true    | Is inter-frame interpolation enabled?
 
-The following example config file supports two Fadecandy devices with distinct serial numbers. They both receive data from OPC channel #0. The first 512 pixels map to the first Fadecandy device. The next 64 pixels map to the entire first strand of the second Fadecandy device, and the next 32 pixels map to the beginning of the third strand with the color channels in Blue, Green, Red order.
+The following example config file supports two Fadecandy devices with distinct serial numbers. They both receive data from OPC channel #0. The first 512 pixels map to the first Fadecandy device. The next 64 pixels map to the entire first strand of the second Fadecandy device, the next 32 pixels map to the beginning of the third strand with the color channels in Blue, Green, Red order, and the next 32 pixels map to the end of the third strand in reverse order.
 
     {
         "listen": ["127.0.0.1", 7890],
@@ -136,6 +138,7 @@ The following example config file supports two Fadecandy devices with distinct s
                 "map": [
                     [ 0, 512, 0, 64 ],
                     [ 0, 576, 128, 32, "bgr" ]
+                    [ 0, 608, 191, -32 ]
                 ]
             }
         ]
diff --git a/server/src/fcdevice.cpp b/server/src/fcdevice.cpp
index ee1956e..8347fa4 100644
--- a/server/src/fcdevice.cpp
+++ b/server/src/fcdevice.cpp
@@ -539,11 +539,19 @@ void FCDevice::opcMapPixelColors(const OPC::Message &msg, const Value &inst)
         const Value &vFirstOut = inst[2];
         const Value &vCount = inst[3];
 
-        if (vChannel.IsUint() && vFirstOPC.IsUint() && vFirstOut.IsUint() && vCount.IsUint()) {
+        if (vChannel.IsUint() && vFirstOPC.IsUint() && vFirstOut.IsUint() && vCount.IsInt()) {
             unsigned channel = vChannel.GetUint();
             unsigned firstOPC = vFirstOPC.GetUint();
             unsigned firstOut = vFirstOut.GetUint();
-            unsigned count = vCount.GetUint();
+            unsigned count;
+            int direction;
+            if (vCount.GetInt() >= 0) {
+                count = vCount.GetInt();
+                direction = 1;
+            } else {
+                count = -vCount.GetInt();
+                direction = -1;
+            }
 
             if (channel != msg.channel) {
                 return;
@@ -553,14 +561,15 @@ void FCDevice::opcMapPixelColors(const OPC::Message &msg, const Value &inst)
             firstOPC = std::min<unsigned>(firstOPC, msgPixelCount);
             firstOut = std::min<unsigned>(firstOut, unsigned(NUM_PIXELS));
             count = std::min<unsigned>(count, msgPixelCount - firstOPC);
-            count = std::min<unsigned>(count, NUM_PIXELS - firstOut);
+            count = std::min<unsigned>(count,
+                    direction > 0 ? NUM_PIXELS - firstOut : firstOut + 1);
 
             // Copy pixels
             const uint8_t *inPtr = msg.data + (firstOPC * 3);
             unsigned outIndex = firstOut;
-
             while (count--) {
-                uint8_t *outPtr = fbPixel(outIndex++);
+                uint8_t *outPtr = fbPixel(outIndex);
+                outIndex += direction;
                 outPtr[0] = inPtr[0];
                 outPtr[1] = inPtr[1];
                 outPtr[2] = inPtr[2];
@@ -580,13 +589,21 @@ void FCDevice::opcMapPixelColors(const OPC::Message &msg, const Value &inst)
         const Value &vCount = inst[3];
         const Value &vColorChannels = inst[4];
 
-        if (vChannel.IsUint() && vFirstOPC.IsUint() && vFirstOut.IsUint() && vCount.IsUint()
+        if (vChannel.IsUint() && vFirstOPC.IsUint() && vFirstOut.IsUint() && vCount.IsInt()
             && vColorChannels.IsString() && vColorChannels.GetStringLength() == 3) {
 
             unsigned channel = vChannel.GetUint();
             unsigned firstOPC = vFirstOPC.GetUint();
             unsigned firstOut = vFirstOut.GetUint();
-            unsigned count = vCount.GetUint();
+            unsigned count;
+            int direction;
+            if (vCount.GetInt() >= 0) {
+                count = vCount.GetInt();
+                direction = 1;
+            } else {
+                count = -vCount.GetInt();
+                direction = -1;
+            }
             const char *colorChannels = vColorChannels.GetString();
 
             if (channel != msg.channel) {
@@ -597,15 +614,16 @@ void FCDevice::opcMapPixelColors(const OPC::Message &msg, const Value &inst)
             firstOPC = std::min<unsigned>(firstOPC, msgPixelCount);
             firstOut = std::min<unsigned>(firstOut, unsigned(NUM_PIXELS));
             count = std::min<unsigned>(count, msgPixelCount - firstOPC);
-            count = std::min<unsigned>(count, NUM_PIXELS - firstOut);
+            count = std::min<unsigned>(count,
+                    direction > 0 ? NUM_PIXELS - firstOut : firstOut + 1);
 
             // Copy pixels
             const uint8_t *inPtr = msg.data + (firstOPC * 3);
             unsigned outIndex = firstOut;
             bool success = true;
-
             while (count--) {
-                uint8_t *outPtr = fbPixel(outIndex++);
+                uint8_t *outPtr = fbPixel(outIndex);
+                outIndex += direction;
 
                 for (int channel = 0; channel < 3; channel++) {
                     if (!OPC::pickColorChannel(outPtr[channel], colorChannels[channel], inPtr)) {
-- 
GitLab