]> sigrok.org Git - libsigrokdecode.git/commitdiff
srd: i2cfilter: Output actual I2C packets.
authorUwe Hermann <redacted>
Thu, 28 Jun 2012 19:43:12 +0000 (21:43 +0200)
committerUwe Hermann <redacted>
Tue, 3 Jul 2012 23:03:13 +0000 (01:03 +0200)
Change this PD from an I2C->databytes converter/filter to an actual
pure I2C filter in the sense that both input and output is a valid I2C
protocol stream.

Also, change the EDID decoder accordingly, to use the new i2cfilter
output.

decoders/edid/edid.py
decoders/i2cfilter/__init__.py
decoders/i2cfilter/i2cfilter.py

index 21ab0081d23de1848188924afdd518251a8b37ea..a03fe67c9644cbfbdf5b668eb7b4b4d403e89216 100644 (file)
@@ -105,8 +105,12 @@ class Decoder(srd.Decoder):
         pass
 
     def decode(self, ss, es, data):
-        if type(data) != int:
-            raise Exception('malformed ddc2 input: expected 1 byte')
+        cmd, data = data
+
+        # We only care about actual data bytes that are read (for now).
+        if cmd != 'DATA READ':
+            return
+
         self.cnt += 1
         self.sn.append([ss, es])
         self.cache.append(data)
index e9a9ab6028466134b1679751fe9e823c240df13d..6443f5b620d61093867dc80b631ca69775be51cc 100644 (file)
 '''
 Generic I2C filtering protocol decoder.
 
-Takes input from the I2C protocol decoder and filters out traffic from/to
-a single address on the I2C bus.
+Takes input from the I2C protocol decoder and removes all traffic
+except that from/to the specified slave address and/or direction.
 
-It then outputs the filtered data one byte at a time as OUTPUT_PROTO up the
-protocol decoder stack. No annotations are output.
+It then outputs the filtered data again as OUTPUT_PROTO of type/format 'i2c'
+(up the protocol decoder stack). No annotations are output.
 
-The I2C address to filter out should be passed in as an option 'address', as
-an integer. A specific read or write operation can be selected with the
-'direction' option, which should be 'read' or 'write'.
+The I2C slave address to filter out should be passed in as an option
+'address', as an integer. A specific read or write operation can be selected
+with the 'direction' option, which should be 'read', 'write', or 'both'.
 
 Both of these are optional; if no options are specified the entire payload
 of the I2C session will be output.
index 64010cb2a3f0404aba7e79031fa3b058f614144c..9c9c43aff8d5240994cfffd42331725e6f9b8183 100644 (file)
@@ -2,6 +2,7 @@
 ## This file is part of the sigrok project.
 ##
 ## Copyright (C) 2012 Bert Vermeulen <bert@biot.com>
+## Copyright (C) 2012 Uwe Hermann <uwe@hermann-uwe.de>
 ##
 ## This program is free software; you can redistribute it and/or modify
 ## it under the terms of the GNU General Public License as published by
@@ -19,6 +20,8 @@
 
 # Generic I2C filtering protocol decoder
 
+# TODO: Support for filtering out multiple slave/direction pairs?
+
 import sigrokdecode as srd
 
 class Decoder(srd.Decoder):
@@ -29,57 +32,68 @@ class Decoder(srd.Decoder):
     desc = 'Filter out addresses/directions in an I2C stream.'
     license = 'gplv3+'
     inputs = ['i2c']
-    outputs = []
+    outputs = ['i2c']
     probes = []
     optional_probes = []
     options = {
         'address': ['Address to filter out of the I2C stream', 0],
-        'direction': ['Direction to filter (read/write)', '']
+        'direction': ['Direction to filter (read/write/both)', 'both']
     }
     annotations = []
 
     def __init__(self, **kwargs):
         self.state = None
+        self.curslave = -1
+        self.curdirection = None
+        self.packets = [] # Local cache of I2C packets
 
     def start(self, metadata):
-        self.out_proto = self.add(srd.OUTPUT_PROTO, 'i2cdata')
-        if self.options['direction'] not in ('', 'read', 'write'):
-            raise Exception('Invalid direction: expected "read" or "write"')
+        self.out_proto = self.add(srd.OUTPUT_PROTO, 'i2c')
+        if self.options['address'] not in range(0, 127 + 1):
+            raise Exception('Invalid slave (must be 0..127).')
+        if self.options['direction'] not in ('both', 'read', 'write'):
+            raise Exception('Invalid direction (valid: read/write/both).')
 
     def report(self):
         pass
 
+    # Grab I2C packets into a local cache, until an I2C STOP condition
+    # packet comes along. At some point before that STOP condition, there
+    # will have been an ADDRESS READ or ADDRESS WRITE which contains the
+    # I2C address of the slave that the master wants to talk to.
+    # If that slave shall be filtered, output the cache (all packets from
+    # START to STOP) as proto 'i2c', otherwise drop it.
     def decode(self, ss, es, data):
-        try:
-            cmd, data = data
-        except Exception as e:
-            raise Exception('Malformed I2C input: %s' % str(e)) from e
 
-        # Whichever state we're in, these always reset the state machine.
-        # This should make it easier to deal with corrupt data etc.
-        if cmd in ('START', 'START REPEAT'):
-            self.state = 'start'
-            return
-        if cmd == 'STOP':
-            self.state = None
-            return
-        if cmd in ('ACK', 'NACK'):
-            # Don't care, we just want data.
-            return
+        cmd, databyte = data
+
+        # Add the I2C packet to our local cache.
+        self.packets.append([ss, es, data])
 
-        if self.state == 'start':
-            # Start of a transfer, see if we want this one.
-            if cmd == 'ADDRESS READ' and self.options['direction'] == 'write':
+        if cmd in ('ADDRESS READ', 'ADDRESS WRITE'):
+            self.curslave = databyte
+            self.curdirection = cmd[8:].lower()
+        elif cmd in ('STOP', 'START REPEAT'):
+            # If this chunk was not for the correct slave, drop it.
+            if self.options['address'] == 0:
+                pass
+            elif self.curslave != self.options['address']:
+                self.packets = []
                 return
-            elif cmd == 'ADDRESS WRITE' and self.options['direction'] == 'read':
+
+            # If this chunk was not in the right direction, drop it.
+            if self.options['direction'] == 'both':
+                pass
+            elif self.options['direction'] != self.curdirection:
+                self.packets = []
                 return
-            elif cmd in ('ADDRESS READ', 'ADDRESS WRITE'):
-                if self.options['address'] in (0, data):
-                    # We want this tranfer.
-                    self.state = 'transfer'
-        elif self.state == 'transfer':
-            if cmd in ('DATA READ', 'DATA WRITE'):
-                self.put(ss, es, self.out_proto, data)
+
+            # TODO: START->STOP chunks with both read and write (Repeat START)
+            # Otherwise, send out the whole chunk of I2C packets.
+            for p in self.packets:
+                self.put(p[0], p[1], self.out_proto, p[2])
+
+            self.packets = []
         else:
-            raise Exception('Invalid state: %s' % self.state)
+            pass # Do nothing, only add the I2C packet to our cache.