spi: Improve use of PD API version 3
authorGerhard Sittig <gerhard.sittig@gmx.net>
Tue, 6 Jun 2017 20:55:52 +0000 (22:55 +0200)
committerGerhard Sittig <gerhard.sittig@gmx.net>
Tue, 6 Jun 2017 20:55:52 +0000 (22:55 +0200)
Eliminate more instances where Python code tracked signal changes instead
of having common library code do the work. Reduce the number of boundary
crossings between library and decoder code (Python vs C), by inspecting
fewer input edges. Yet cope with the CS signal's being optional. Emit
identical annotations to the previous implementation for CS changes,
including the initial change "from None to 0/1". Sort the checks for
optional input signals at the top of decode() into a more natural order.
Improve and update comments.

This commit results in a more appropriate use of the PD v3 API in the
SPI protocol decoder.

decoders/spi/pd.py

index 1252a6a07cb7f7728872d23e512249970cd4ff58..aec1fac4ec30e8614e3b0b9a405d3a8eafcf41bf 100644 (file)
@@ -125,7 +125,6 @@ class Decoder(srd.Decoder):
 
     def __init__(self):
         self.samplerate = None
-        self.oldclk = 1
         self.bitcount = 0
         self.misodata = self.mosidata = 0
         self.misobits = []
@@ -136,7 +135,6 @@ class Decoder(srd.Decoder):
         self.samplenum = -1
         self.ss_transfer = -1
         self.cs_was_deasserted = False
-        self.oldcs = None
         self.have_cs = self.have_miso = self.have_mosi = None
 
     def metadata(self, key, value):
@@ -263,12 +261,12 @@ class Decoder(srd.Decoder):
 
         self.reset_decoder_state()
 
-    def find_clk_edge(self, miso, mosi, clk, cs):
-        if self.have_cs and self.oldcs != cs:
+    def find_clk_edge(self, miso, mosi, clk, cs, first):
+        if self.have_cs and (first or self.matched[self.have_cs]):
             # Send all CS# pin value changes.
+            oldcs = None if first else 1 - cs
             self.put(self.samplenum, self.samplenum, self.out_python,
-                     ['CS-CHANGE', self.oldcs, cs])
-            self.oldcs = cs
+                     ['CS-CHANGE', oldcs, cs])
 
             if self.cs_asserted(cs):
                 self.ss_transfer = self.samplenum
@@ -286,11 +284,9 @@ class Decoder(srd.Decoder):
             return
 
         # Ignore sample if the clock pin hasn't changed.
-        if clk == self.oldclk:
+        if first or not self.matched[0]:
             return
 
-        self.oldclk = clk
-
         # Sample data on rising/falling clock edge (depends on mode).
         mode = spi_mode[self.options['cpol'], self.options['cpha']]
         if mode == 0 and clk == 0:   # Sample on rising clock edge
@@ -309,27 +305,37 @@ class Decoder(srd.Decoder):
         if not self.samplerate:
             raise SamplerateError('Cannot decode without samplerate.')
 
-        # Either MISO or MOSI can be omitted (but not both). CS# is optional.
+        # The CLK input is mandatory. Other signals are (individually)
+        # optional. Yet either MISO or MOSI (or both) must be provided.
+        # Tell stacked decoders when we don't have a CS# signal.
+        if not self.has_channel(0):
+            raise ChannelError('Either MISO or MOSI (or both) pins required.')
         self.have_miso = self.has_channel(1)
         self.have_mosi = self.has_channel(2)
-        self.have_cs = self.has_channel(3)
         if not self.have_miso and not self.have_mosi:
             raise ChannelError('Either MISO or MOSI (or both) pins required.')
-
-        # Tell stacked decoders that we don't have a CS# signal.
+        self.have_cs = self.has_channel(3)
         if not self.have_cs:
             self.put(0, 0, self.out_python, ['CS-CHANGE', None, None])
 
+        # We want all CLK changes. We want all CS changes if CS is used.
+        # Map 'have_cs' from boolean to an integer index. This simplifies
+        # evaluation in other locations.
+        wait_cond = [{0: 'e'}]
+        if self.have_cs:
+            self.have_cs = len(wait_cond)
+            wait_cond.append({3: 'e'})
+
         # "Pixel compatibility" with the v2 implementation. Grab and
         # process the very first sample before checking for edges. The
-        # previous implementation did this by seeding old values with None,
-        # which led to an immediate "change" in comparison.
+        # previous implementation did this by seeding old values with
+        # None, which led to an immediate "change" in comparison.
         pins = self.wait({})
         (clk, miso, mosi, cs) = pins
-        self.find_clk_edge(miso, mosi, clk, cs)
+        self.find_clk_edge(miso, mosi, clk, cs, True)
 
         while True:
             # Ignore identical samples early on (for performance reasons).
-            pins = self.wait([{0: 'e'}, {1: 'e'}, {2: 'e'}, {3: 'e'}])
+            pins = self.wait(wait_cond)
             (clk, miso, mosi, cs) = pins
-            self.find_clk_edge(miso, mosi, clk, cs)
+            self.find_clk_edge(miso, mosi, clk, cs, False)