]> sigrok.org Git - libsigrokdecode.git/blobdiff - decoders/sle44xx/pd.py
sle44xx: rephrase ss/es passing for annotation emission
[libsigrokdecode.git] / decoders / sle44xx / pd.py
index 25b1cc22e467e4bde3aaa2c6a501c9d22d81e1c3..866ebd56c168d54bb74e32e88970d83fbcd34467 100644 (file)
@@ -17,6 +17,7 @@
 ## along with this program; if not, see <http://www.gnu.org/licenses/>.
 ##
 
+from common.srdhelper import bitpack_lsb
 import sigrokdecode as srd
 
 class Pin:
@@ -28,14 +29,23 @@ class Ann:
 class Bin:
     SEND_DATA, = range(1)
 
-# CMD: [annotation class index, long annotation, short annotation]
+# CMD: [annotation class index, annotation texts for zoom levels]
 proto = {
-    'ATR':   [Ann.ATR,   'ATR',     'ATR'],
-    'CMD':   [Ann.CMD,   'Command', 'C'],
-    'DATA':  [Ann.DATA,  'Data',    'D'],
-    'RESET': [Ann.RESET, 'Reset',   'R'],
+    'BIT':   [Ann.BIT,   '{bit}',],
+    'ATR':   [Ann.ATR,   'Answer To Reset: {data:02x}', 'ATR: {data:02x}', '{data:02x}',],
+    'CMD':   [Ann.CMD,   'Command: {data:02x}', 'Cmd: {data:02x}', '{data:02x}',],
+    'DATA':  [Ann.DATA,  'Data: {data:02x}', '{data:02x}',],
+    'RESET': [Ann.RESET, 'Reset', 'R',],
 }
 
+def lookup_proto_ann_txt(cmd, variables):
+    ann = proto.get(cmd, None)
+    if ann is None:
+        return None, []
+    cls, texts = ann[0], ann[1:]
+    texts = [t.format(**variables) for t in texts]
+    return cls, texts
+
 class Decoder(srd.Decoder):
     api_version = 3
     id = 'sle44xx'
@@ -71,11 +81,8 @@ class Decoder(srd.Decoder):
         self.reset()
 
     def reset(self):
-        self.ss = self.es = self.ss_byte = -1
-        self.bitcount = 0
-        self.databyte = 0
         self.bits = []
-        self.cmd = 'RESET'
+        self.cmd = None
 
     def metadata(self, key, value):
         if key == srd.SRD_CONF_SAMPLERATE:
@@ -85,66 +92,67 @@ class Decoder(srd.Decoder):
         self.out_ann = self.register(srd.OUTPUT_ANN)
         self.out_binary = self.register(srd.OUTPUT_BINARY)
 
-    def putx(self, data):
-        self.put(self.ss, self.es, self.out_ann, data)
+    def putx(self, ss, es, cls, data):
+        self.put(ss, es, self.out_ann, [cls, data,])
 
-    def putb(self, data):
-        self.put(self.ss, self.es, self.out_binary, data)
+    def putb(self, ss, es, cls , data):
+        self.put(ss, es, self.out_binary, [cls, data,])
 
     def handle_reset(self, pins):
-        self.ss, self.es = self.samplenum, self.samplenum
-        cmd = 'RESET' # No need to set the global self.cmd as this command is atomic
-        self.putx([proto[cmd][0], proto[cmd][1:]])
-        self.bitcount = self.databyte = 0
+        self.cmd = 'RESET'
+        cls, texts = lookup_proto_ann_txt(self.cmd, {})
+        self.putx(self.samplenum, self.samplenum, cls, texts)
         self.bits = []
-        self.cmd = 'ATR' # Next data bytes will be ATR
+        # Next data bytes will be Answer To Reset.
+        self.cmd = 'ATR'
 
     def handle_command(self, pins):
         rst, clk, io = pins
-        self.ss, self.es = self.samplenum, self.samplenum
+        # XXX Is the comment inverted?
         # If I/O is rising -> command START
         # if I/O is falling -> command STOP and response data incoming
-        self.cmd = 'CMD' if (io == 0) else 'DATA'
-        self.bitcount = self.databyte = 0
+        self.cmd = 'CMD' if io == 0 else 'DATA'
         self.bits = []
 
     # Gather 8 bits of data
     def handle_data(self, pins):
         rst, clk, io = pins
 
-        # Data is transmitted LSB-first.
-        self.databyte |= (io << self.bitcount)
-
-        # Remember the start of the first data/address bit.
-        if self.bitcount == 0:
-            self.ss_byte = self.samplenum
-
-        # Store individual bits and their start/end samplenumbers.
-        # In the list, index 0 represents the LSB (SLE44xx transmits LSB-first).
-        self.bits.insert(0, [io, self.samplenum, self.samplenum])
-        if self.bitcount > 0:
-            self.bits[1][2] = self.samplenum
-        if self.bitcount == 7:
-            self.bitwidth = self.bits[1][2] - self.bits[2][2]
-            self.bits[0][2] += self.bitwidth
-
-        # Return if we haven't collected all 8 bits, yet.
-        if self.bitcount < 7:
-            self.bitcount += 1
+        # Remember the start of the first data/address bit. Collect
+        # bits in LSB first order. "Estimate" the bit's width at first,
+        # update end times as better data becomes available.
+        # TODO This estimation logic is imprecise and fragile. A single
+        # slightly stretched clock period throws off the following bit
+        # annotation. Better look for more reliable conditions. Available
+        # documentation suggests bit values are valid during high CLK.
+        bit_val = io
+        bit_ss = self.samplenum
+        bit_es = bit_ss # self.bitwidth is not known yet.
+        if self.bits:
+            self.bits[-1][2] = bit_ss
+        self.bits.append([bit_val, bit_ss, bit_es])
+        if len(self.bits) < 8:
             return
+        bitwidth = self.bits[-1][1] - self.bits[-2][1]
+        self.bits[-1][2] += bitwidth
 
-        self.ss, self.es = self.ss_byte, self.samplenum + self.bitwidth
+        # Get the data byte value, and byte's ss/es.
+        databyte = bitpack_lsb(self.bits, 0)
+        byte_ss = self.bits[0][1]
+        byte_es = self.bits[-1][2]
 
-        self.putb([Bin.SEND_DATA, bytes([self.databyte])])
+        self.putb(byte_ss, byte_es, Bin.SEND_DATA, bytes([databyte]))
 
-        for bit in self.bits:
-            self.put(bit[1], bit[2], self.out_ann, [Ann.BIT, ['%d' % bit[0]]])
+        # TODO Present bit values earlier. As soon as their es is known.
+        for bit_val, bit_ss, bit_es in self.bits:
+            cls, texts = lookup_proto_ann_txt('BIT', {'bit': bit_val})
+            self.putx(bit_ss, bit_es, cls, texts)
 
-        self.putx([proto[self.cmd][0], ['%s: %02X' % (proto[self.cmd][1], self.databyte),
-                   '%s: %02X' % (proto[self.cmd][2], self.databyte), '%02X' % self.databyte]])
+        cls, texts = lookup_proto_ann_txt(self.cmd, {'data': databyte})
+        if cls:
+            self.putx(byte_ss, byte_es, cls, texts)
 
         # Done with this packet.
-        self.bitcount = self.databyte = 0
         self.bits = []
 
     def decode(self):
@@ -152,6 +160,7 @@ class Decoder(srd.Decoder):
             # Signal conditions tracked by the protocol decoder:
             # - RESET condition (R): RST = rising
             # - Incoming data (D): RST = low, CLK = rising.
+            #   TODO Add "RST low, CLK fall" for "end of DATA" here?
             # - Command mode START: CLK = high, I/O = falling.
             # - Command mode STOP: CLK = high, I/O = rising.
             (COND_RESET, COND_DATA, COND_CMD_START, COND_CMD_STOP,) = range(4)