From: Uwe Hermann Date: Thu, 12 Sep 2013 19:14:06 +0000 (+0200) Subject: spi: Refactor code, use a state machine. X-Git-Tag: libsigrokdecode-0.3.0~315 X-Git-Url: http://sigrok.org/gitweb/?a=commitdiff_plain;ds=sidebyside;h=191ec8c5b7b6bb6b348a2c43b851923181fd68d8;p=libsigrokdecode.git spi: Refactor code, use a state machine. --- diff --git a/decoders/spi/pd.py b/decoders/spi/pd.py index 47bbe32..bb486c8 100644 --- a/decoders/spi/pd.py +++ b/decoders/spi/pd.py @@ -77,6 +77,7 @@ class Decoder(srd.Decoder): self.cs_was_deasserted_during_data_word = 0 self.oldcs = -1 self.oldpins = None + self.state = 'IDLE' def start(self, metadata): self.out_proto = self.add(srd.OUTPUT_PROTO, 'spi') @@ -91,79 +92,90 @@ class Decoder(srd.Decoder): def putw(self, data): self.put(self.startsample, self.samplenum, self.out_ann, data) - def decode(self, ss, es, data): - # TODO: Either MISO or MOSI could be optional. CS# is optional. - for (self.samplenum, pins) in data: + def handle_bit(self, miso, mosi, sck, cs): + # If this is the first bit, save its sample number. + if self.bitcount == 0: + self.startsample = self.samplenum + active_low = (self.options['cs_polarity'] == 'active-low') + deasserted = cs if active_low else not cs + if deasserted: + self.cs_was_deasserted_during_data_word = 1 - # Ignore identical samples early on (for performance reasons). - if self.oldpins == pins: - continue - self.oldpins, (miso, mosi, sck, cs) = pins, pins + ws = self.options['wordsize'] - if self.oldcs != cs: - # Send all CS# pin value changes. - self.put(self.samplenum, self.samplenum, self.out_proto, - ['CS-CHANGE', self.oldcs, cs]) - self.oldcs = cs + # Receive MOSI bit into our shift register. + if self.options['bitorder'] == 'msb-first': + self.mosidata |= mosi << (ws - 1 - self.bitcount) + else: + self.mosidata |= mosi << self.bitcount - # Ignore sample if the clock pin hasn't changed. - if sck == self.oldsck: - continue + # Receive MISO bit into our shift register. + if self.options['bitorder'] == 'msb-first': + self.misodata |= miso << (ws - 1 - self.bitcount) + else: + self.misodata |= miso << self.bitcount - self.oldsck = sck - - # Sample data on rising/falling clock edge (depends on mode). - mode = spi_mode[self.options['cpol'], self.options['cpha']] - if mode == 0 and sck == 0: # Sample on rising clock edge - continue - elif mode == 1 and sck == 1: # Sample on falling clock edge - continue - elif mode == 2 and sck == 1: # Sample on falling clock edge - continue - elif mode == 3 and sck == 0: # Sample on rising clock edge - continue - - # If this is the first bit, save its sample number. - if self.bitcount == 0: - self.startsample = self.samplenum - active_low = (self.options['cs_polarity'] == 'active-low') - deasserted = cs if active_low else not cs - if deasserted: - self.cs_was_deasserted_during_data_word = 1 - - ws = self.options['wordsize'] - - # Receive MOSI bit into our shift register. - if self.options['bitorder'] == 'msb-first': - self.mosidata |= mosi << (ws - 1 - self.bitcount) - else: - self.mosidata |= mosi << self.bitcount + self.bitcount += 1 - # Receive MISO bit into our shift register. - if self.options['bitorder'] == 'msb-first': - self.misodata |= miso << (ws - 1 - self.bitcount) - else: - self.misodata |= miso << self.bitcount + # Continue to receive if not enough bits were received, yet. + if self.bitcount != ws: + return - self.bitcount += 1 + self.putpw(['DATA', self.mosidata, self.misodata]) + self.putw([0, ['%02X/%02X' % (self.mosidata, self.misodata)]]) + self.putw([1, ['%02X' % self.misodata]]) + self.putw([2, ['%02X' % self.mosidata]]) - # Continue to receive if not enough bits were received, yet. - if self.bitcount != ws: - continue + if self.cs_was_deasserted_during_data_word: + self.putw([3, ['CS# was deasserted during this data word!']]) + + # Reset decoder state. + self.mosidata = 0 + self.misodata = 0 + self.bitcount = 0 + + # Keep stats for summary. + self.bytesreceived += 1 + + def find_clk_edge(self, miso, mosi, sck, cs): + if self.oldcs != cs: + # Send all CS# pin value changes. + self.put(self.samplenum, self.samplenum, self.out_proto, + ['CS-CHANGE', self.oldcs, cs]) + self.oldcs = cs + + # Ignore sample if the clock pin hasn't changed. + if sck == self.oldsck: + return - self.putpw(['DATA', self.mosidata, self.misodata]) - self.putw([0, ['%02X/%02X' % (self.mosidata, self.misodata)]]) - self.putw([1, ['%02X' % self.misodata]]) - self.putw([2, ['%02X' % self.mosidata]]) + self.oldsck = sck - if self.cs_was_deasserted_during_data_word: - self.putw([3, ['CS# was deasserted during this data word!']]) + # Sample data on rising/falling clock edge (depends on mode). + mode = spi_mode[self.options['cpol'], self.options['cpha']] + if mode == 0 and sck == 0: # Sample on rising clock edge + return + elif mode == 1 and sck == 1: # Sample on falling clock edge + return + elif mode == 2 and sck == 1: # Sample on falling clock edge + return + elif mode == 3 and sck == 0: # Sample on rising clock edge + return + + # Found the correct clock edge, now get the SPI bit(s). + self.handle_bit(miso, mosi, sck, cs) + + def decode(self, ss, es, data): + # TODO: Either MISO or MOSI could be optional. CS# is optional. + for (self.samplenum, pins) in data: - # Reset decoder state. - self.mosidata = 0 - self.misodata = 0 - self.bitcount = 0 + # Ignore identical samples early on (for performance reasons). + if self.oldpins == pins: + continue + self.oldpins, (miso, mosi, sck, cs) = pins, pins - # Keep stats for summary. - self.bytesreceived += 1 + # State machine. + if self.state == 'IDLE': + self.find_clk_edge(miso, mosi, sck, cs) + else: + raise Exception('Invalid state: %s' % self.state)