]> sigrok.org Git - libsigrokdecode.git/commitdiff
rgb_led_ws281x: support more colour component orders (wire, and text)
authorGerhard Sittig <redacted>
Sat, 29 Jul 2023 14:59:43 +0000 (16:59 +0200)
committerGerhard Sittig <redacted>
Sat, 29 Jul 2023 19:29:11 +0000 (21:29 +0200)
The 'type' option was not good enough. Replace it by 'wireorder' (order
of colour components on the wire, depends on the RGB LED chip type), and
'textorder' (presentation to users in annotations).

Support many more layouts of colour components on the wire. Cover all
permutations of R, G, and B. Support a few RGB plus W layouts that are
known to be in use. Adding more is just a matter of adding more choices
in the option, the implementation transparently follows.

Support a few text orders: Reflect the very order of bits on the wire.
Automatic support for RGB with optional White, or fixed RGB or RGB-W
variants (all are users' choices, default remains "RGB" for backwards
compatibility). Support arbitrary combinations of wire order and text
order in emitted annotations.

Keep support for the weird RGWB text format, which the previous decoder
implementation used for "all" RGBW types, and which is referenced by
existing test cases. It is uncertain which chip type is supposed to
generate this specific RGBW traffic. It is as uncertain why this text
order was chosen, which neither is the human readable RGBW format nor
matches the wire order. The previous implementation was introduced in
commit 47ff9910f7e1, but neither commented nor referenced literature or
external sources nor did the commit message contain any clues.

This current implementation needs more tests and reviews, but lends
itself better to maintenance, fixes and enhancements.

decoders/rgb_led_ws281x/pd.py

index 5f355942b392d3b751115ab76bf345bdf91fe125..7c8ead4375b8ffc7979937cd7e41a338451ff4a9 100644 (file)
@@ -23,6 +23,9 @@ from common.srdhelper import bitpack_msb
 class SamplerateError(Exception):
     pass
 
+class DecoderError(Exception):
+    pass
+
 ( ANN_BIT, ANN_RESET, ANN_RGB, ) = range(3)
 
 class Decoder(srd.Decoder):
@@ -48,8 +51,11 @@ class Decoder(srd.Decoder):
         ('rgb-vals', 'RGB values', (ANN_RGB,)),
     )
     options = (
-        {'id': 'type', 'desc': 'RGB or RGBW', 'default': 'RGB',
-         'values': ('RGB', 'RGBW')},
+        {'id': 'wireorder', 'desc': 'colour components order (wire)',
+         'default': 'GRB',
+         'values': ('BGR', 'BRG', 'GBR', 'GRB', 'RBG', 'RGB', 'RWBG', 'RGBW')},
+        {'id': 'textorder', 'desc': 'components output order (text)',
+         'default': 'RGB', 'values': ('wire', 'RGB[W]', 'RGB', 'RGBW', 'RGWB')},
     )
 
     def __init__(self):
@@ -72,15 +78,32 @@ class Decoder(srd.Decoder):
     def handle_bits(self):
         if len(self.bits) < self.need_bits:
             return
-        grb = bitpack_msb(self.bits, 0)
-        if self.options['type'] == 'RGB':
-            rgb = (grb & 0xff0000) >> 8 | (grb & 0x00ff00) << 8 | (grb & 0x0000ff)
-            text = '#{:06x}'.format(rgb)
-        else:
-            rgb = (grb & 0xff0000) >> 8 | (grb & 0x00ff00) << 8 | (grb & 0xff0000ff)
-            text = '#{:08x}'.format(rgb)
         ss_packet, es_packet = self.bits[0][1], self.bits[-1][2]
-        self.putg(ss_packet, es_packet, ANN_RGB, [text])
+        r, g, b, w = 0, 0, 0, None
+        comps = []
+        for i, c in enumerate(self.wireformat):
+            first_idx, after_idx = 8 * i, 8 * i + 8
+            comp_bits = self.bits[first_idx:after_idx]
+            comp_ss, comp_es = comp_bits[0][1], comp_bits[-1][2]
+            comp_value = bitpack_msb(comp_bits, 0)
+            comp_item = (comp_ss, comp_es, comp_value)
+            comps.append(comp_item)
+            if c.lower() == 'r':
+                r = comp_value
+            elif c.lower() == 'g':
+                g = comp_value
+            elif c.lower() == 'b':
+                b = comp_value
+            elif c.lower() == 'w':
+                w = comp_value
+        wt = '' if w is None else '{:02x}'.format(w)
+        if self.textformat == 'wire':
+            rgb_text = ['{:02x}'.format(c[-1]) for c in comps]
+            rgb_text = '#' + ''.join(rgb_text)
+        else:
+            rgb_text = self.textformat.format(r = r, g = g, b = b, w = w, wt = wt)
+        if rgb_text:
+            self.putg(ss_packet, es_packet, ANN_RGB, [rgb_text])
         self.bits.clear()
 
     def handle_bit(self, ss, es, value, ann_late = False):
@@ -97,7 +120,34 @@ class Decoder(srd.Decoder):
     def decode(self):
         if not self.samplerate:
             raise SamplerateError('Cannot decode without samplerate.')
-        self.need_bits = len(self.options['type']) * 8
+
+        # Preprocess options here, to simplify logic which executes
+        # much later in loops while settings have the same values.
+        wireorder = self.options['wireorder'].lower()
+        self.wireformat = [c for c in wireorder if c in 'rgbw']
+        self.need_bits = len(self.wireformat) * 8
+        textorder = self.options['textorder'].lower()
+        if textorder == 'wire':
+            self.textformat = 'wire'
+        elif textorder == 'rgb[w]':
+            self.textformat = '#{r:02x}{g:02x}{b:02x}{wt:s}'
+        else:
+            self.textformat = {
+                # "Obvious" permutations of R/G/B.
+                'bgr': '#{b:02x}{g:02x}{r:02x}',
+                'brg': '#{b:02x}{r:02x}{g:02x}',
+                'gbr': '#{g:02x}{b:02x}{r:02x}',
+                'grb': '#{g:02x}{r:02x}{b:02x}',
+                'rbg': '#{r:02x}{b:02x}{g:02x}',
+                'rgb': '#{r:02x}{g:02x}{b:02x}',
+                # RGB plus White. Only one of them useful?
+                'rgbw': '#{r:02x}{g:02x}{b:02x}{w:02x}',
+                # Weird RGBW permutation for compatibility to test case.
+                # Neither used RGBW nor the 'wire' order. Obsolete now?
+                'rgwb': '#{r:02x}{g:02x}{w:02x}{b:02x}',
+            }.get(textorder, None)
+            if self.textformat is None:
+                raise DecoderError('Unsupported text output format.')
 
         # Either check for edges which communicate bit values, or for
         # long periods of idle level which represent a reset pulse.