From 48eee789a15ebd4c26d469a29dd79e7971f031fe Mon Sep 17 00:00:00 2001 From: Uwe Hermann Date: Thu, 28 Jun 2012 21:43:12 +0200 Subject: [PATCH 1/1] srd: i2cfilter: Output actual I2C packets. 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 | 8 +++- decoders/i2cfilter/__init__.py | 14 +++--- decoders/i2cfilter/i2cfilter.py | 78 +++++++++++++++++++-------------- 3 files changed, 59 insertions(+), 41 deletions(-) diff --git a/decoders/edid/edid.py b/decoders/edid/edid.py index 21ab008..a03fe67 100644 --- a/decoders/edid/edid.py +++ b/decoders/edid/edid.py @@ -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) diff --git a/decoders/i2cfilter/__init__.py b/decoders/i2cfilter/__init__.py index e9a9ab6..6443f5b 100644 --- a/decoders/i2cfilter/__init__.py +++ b/decoders/i2cfilter/__init__.py @@ -20,15 +20,15 @@ ''' 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. diff --git a/decoders/i2cfilter/i2cfilter.py b/decoders/i2cfilter/i2cfilter.py index 64010cb..9c9c43a 100644 --- a/decoders/i2cfilter/i2cfilter.py +++ b/decoders/i2cfilter/i2cfilter.py @@ -2,6 +2,7 @@ ## This file is part of the sigrok project. ## ## Copyright (C) 2012 Bert Vermeulen +## Copyright (C) 2012 Uwe Hermann ## ## 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. -- 2.30.2