]> sigrok.org Git - libsigrokdecode.git/commitdiff
All PDs: Name the files pd.py consistently.
authorUwe Hermann <redacted>
Wed, 21 Nov 2012 21:43:02 +0000 (22:43 +0100)
committerUwe Hermann <redacted>
Sat, 24 Nov 2012 19:21:19 +0000 (20:21 +0100)
The Python module name is determined by the directory name (e.g. dcf77),
the *.py file names in that directory don't matter and can be kept
consistent.

100 files changed:
decoders/dcf77/Makefile.am
decoders/dcf77/__init__.py
decoders/dcf77/dcf77.py [deleted file]
decoders/dcf77/pd.py [new file with mode: 0644]
decoders/edid/Makefile.am
decoders/edid/__init__.py
decoders/edid/edid.py [deleted file]
decoders/edid/pd.py [new file with mode: 0644]
decoders/i2c/Makefile.am
decoders/i2c/__init__.py
decoders/i2c/i2c.py [deleted file]
decoders/i2c/pd.py [new file with mode: 0644]
decoders/i2cdemux/Makefile.am
decoders/i2cdemux/__init__.py
decoders/i2cdemux/i2cdemux.py [deleted file]
decoders/i2cdemux/pd.py [new file with mode: 0644]
decoders/i2cfilter/Makefile.am
decoders/i2cfilter/__init__.py
decoders/i2cfilter/i2cfilter.py [deleted file]
decoders/i2cfilter/pd.py [new file with mode: 0644]
decoders/i2s/Makefile.am
decoders/i2s/__init__.py
decoders/i2s/i2s.py [deleted file]
decoders/i2s/pd.py [new file with mode: 0644]
decoders/jtag/Makefile.am
decoders/jtag/__init__.py
decoders/jtag/jtag.py [deleted file]
decoders/jtag/pd.py [new file with mode: 0644]
decoders/jtag_stm32/Makefile.am
decoders/jtag_stm32/__init__.py
decoders/jtag_stm32/jtag_stm32.py [deleted file]
decoders/jtag_stm32/pd.py [new file with mode: 0644]
decoders/lm75/Makefile.am
decoders/lm75/__init__.py
decoders/lm75/lm75.py [deleted file]
decoders/lm75/pd.py [new file with mode: 0644]
decoders/lpc/Makefile.am
decoders/lpc/__init__.py
decoders/lpc/lpc.py [deleted file]
decoders/lpc/pd.py [new file with mode: 0644]
decoders/maxim_ds28ea00/Makefile.am
decoders/maxim_ds28ea00/__init__.py
decoders/maxim_ds28ea00/maxim_ds28ea00.py [deleted file]
decoders/maxim_ds28ea00/pd.py [new file with mode: 0644]
decoders/mlx90614/Makefile.am
decoders/mlx90614/__init__.py
decoders/mlx90614/mlx90614.py [deleted file]
decoders/mlx90614/pd.py [new file with mode: 0644]
decoders/mx25lxx05d/Makefile.am
decoders/mx25lxx05d/__init__.py
decoders/mx25lxx05d/mx25lxx05d.py [deleted file]
decoders/mx25lxx05d/pd.py [new file with mode: 0644]
decoders/mxc6225xu/Makefile.am
decoders/mxc6225xu/__init__.py
decoders/mxc6225xu/mxc6225xu.py [deleted file]
decoders/mxc6225xu/pd.py [new file with mode: 0644]
decoders/nunchuk/Makefile.am
decoders/nunchuk/__init__.py
decoders/nunchuk/nunchuk.py [deleted file]
decoders/nunchuk/pd.py [new file with mode: 0644]
decoders/onewire_link/Makefile.am
decoders/onewire_link/__init__.py
decoders/onewire_link/onewire_link.py [deleted file]
decoders/onewire_link/pd.py [new file with mode: 0644]
decoders/onewire_network/Makefile.am
decoders/onewire_network/__init__.py
decoders/onewire_network/onewire_network.py [deleted file]
decoders/onewire_network/pd.py [new file with mode: 0644]
decoders/pan1321/Makefile.am
decoders/pan1321/__init__.py
decoders/pan1321/pan1321.py [deleted file]
decoders/pan1321/pd.py [new file with mode: 0644]
decoders/rtc8564/Makefile.am
decoders/rtc8564/__init__.py
decoders/rtc8564/pd.py [new file with mode: 0644]
decoders/rtc8564/rtc8564.py [deleted file]
decoders/spi/Makefile.am
decoders/spi/__init__.py
decoders/spi/pd.py [new file with mode: 0644]
decoders/spi/spi.py [deleted file]
decoders/transitioncounter/Makefile.am
decoders/transitioncounter/__init__.py
decoders/transitioncounter/pd.py [new file with mode: 0644]
decoders/transitioncounter/transitioncounter.py [deleted file]
decoders/uart/Makefile.am
decoders/uart/__init__.py
decoders/uart/pd.py [new file with mode: 0644]
decoders/uart/uart.py [deleted file]
decoders/uart_dump/Makefile.am
decoders/uart_dump/__init__.py
decoders/uart_dump/pd.py [new file with mode: 0644]
decoders/uart_dump/uart_dump.py [deleted file]
decoders/usb_protocol/Makefile.am
decoders/usb_protocol/__init__.py
decoders/usb_protocol/pd.py [new file with mode: 0644]
decoders/usb_protocol/usb_protocol.py [deleted file]
decoders/usb_signalling/Makefile.am
decoders/usb_signalling/__init__.py
decoders/usb_signalling/pd.py [new file with mode: 0644]
decoders/usb_signalling/usb_signalling.py [deleted file]

index c55f0b7933654a449bedb0d0de364f15ff2f2a53..33ea1c77e749360a8d8738f54646bb8cedca33a9 100644 (file)
@@ -20,7 +20,7 @@
 
 pkgdatadir = $(DECODERS_DIR)/dcf77
 
-dist_pkgdata_DATA = __init__.py dcf77.py
+dist_pkgdata_DATA = __init__.py pd.py
 
 CLEANFILES = *.pyc
 
index bef505b926c6ab0e896600b7ec03f1f0cd692d02..e2ed26bf19ef5814f792f6e91d8c10c909b67db7 100644 (file)
@@ -25,5 +25,5 @@ Details:
 http://en.wikipedia.org/wiki/DCF77
 '''
 
-from .dcf77 import *
+from .pd import *
 
diff --git a/decoders/dcf77/dcf77.py b/decoders/dcf77/dcf77.py
deleted file mode 100644 (file)
index c4132e9..0000000
+++ /dev/null
@@ -1,288 +0,0 @@
-##
-## This file is part of the sigrok project.
-##
-## 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
-## the Free Software Foundation; either version 2 of the License, or
-## (at your option) any later version.
-##
-## This program is distributed in the hope that it will be useful,
-## but WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-## GNU General Public License for more details.
-##
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, write to the Free Software
-## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
-##
-
-# DCF77 protocol decoder
-
-import sigrokdecode as srd
-import calendar
-
-# Return the specified BCD number (max. 8 bits) as integer.
-def bcd2int(b):
-    return (b & 0x0f) + ((b >> 4) * 10)
-
-class Decoder(srd.Decoder):
-    api_version = 1
-    id = 'dcf77'
-    name = 'DCF77'
-    longname = 'DCF77 time protocol'
-    desc = 'European longwave time signal (77.5kHz carrier signal).'
-    license = 'gplv2+'
-    inputs = ['logic']
-    outputs = ['dcf77']
-    probes = [
-        {'id': 'data', 'name': 'DATA', 'desc': 'DATA line'},
-    ]
-    optional_probes = [
-        {'id': 'pon', 'name': 'PON', 'desc': 'Power on'},
-    ]
-    options = {}
-    annotations = [
-        ['Text', 'Human-readable text'],
-        ['Warnings', 'Human-readable warnings'],
-    ]
-
-    def __init__(self, **kwargs):
-        self.state = 'WAIT FOR RISING EDGE'
-        self.oldpins = None
-        self.oldval = None
-        self.oldpon = None
-        self.samplenum = 0
-        self.bit_start = 0
-        self.bit_start_old = 0
-        self.bitcount = 0 # Counter for the DCF77 bits (0..58)
-        self.dcf77_bitnumber_is_known = 0
-
-    def start(self, metadata):
-        self.samplerate = metadata['samplerate']
-        # self.out_proto = self.add(srd.OUTPUT_PROTO, 'dcf77')
-        self.out_ann = self.add(srd.OUTPUT_ANN, 'dcf77')
-
-    def report(self):
-        pass
-
-    # TODO: Which range to use? Only the 100ms/200ms or full second?
-    def handle_dcf77_bit(self, bit):
-        c = self.bitcount
-        a = self.out_ann
-        ss = es = 0 # FIXME
-
-        # Create one annotation for each DCF77 bit (containing the 0/1 value).
-        # Use 'Unknown DCF77 bit x: val' if we're not sure yet which of the
-        # 0..58 bits it is (because we haven't seen a 'new minute' marker yet).
-        # Otherwise, use 'DCF77 bit x: val'.
-        s = '' if self.dcf77_bitnumber_is_known else 'Unknown '
-        self.put(ss, es, a, [0, ['%sDCF77 bit %d: %d' % (s, c, bit)]])
-
-        # If we're not sure yet which of the 0..58 DCF77 bits we have, return.
-        # We don't want to decode bogus data.
-        if not self.dcf77_bitnumber_is_known:
-            return
-
-        # Output specific "decoded" annotations for the respective DCF77 bits.
-        if c == 0:
-            # Start of minute: DCF bit 0.
-            if bit == 0:
-                self.put(ss, es, a, [0, ['Start of minute (always 0)']])
-            else:
-                self.put(ss, es, a, [0, ['ERROR: Start of minute != 0']])
-        elif c in range(1, 14 + 1):
-            # Special bits (civil warnings, weather forecast): DCF77 bits 1-14.
-            if c == 1:
-                self.tmp = bit
-            else:
-                self.tmp |= (bit << (c - 1))
-            if c == 14:
-                self.put(ss, es, a, [0, ['Special bits: %s' % bin(self.tmp)]])
-        elif c == 15:
-            s = '' if (bit == 1) else 'not '
-            self.put(ss, es, a, [0, ['Call bit is %sset' % s]])
-            # TODO: Previously this bit indicated use of the backup antenna.
-        elif c == 16:
-            s = '' if (bit == 1) else 'not '
-            self.put(ss, es, a, [0, ['Summer time announcement %sactive' % s]])
-        elif c == 17:
-            s = '' if (bit == 1) else 'not '
-            self.put(ss, es, a, [0, ['CEST is %sin effect' % s]])
-        elif c == 18:
-            s = '' if (bit == 1) else 'not '
-            self.put(ss, es, a, [0, ['CET is %sin effect' % s]])
-        elif c == 19:
-            s = '' if (bit == 1) else 'not '
-            self.put(ss, es, a, [0, ['Leap second announcement %sactive' % s]])
-        elif c == 20:
-            # Start of encoded time: DCF bit 20.
-            if bit == 1:
-                self.put(ss, es, a, [0, ['Start of encoded time (always 1)']])
-            else:
-                self.put(ss, es, a,
-                         [0, ['ERROR: Start of encoded time != 1']])
-        elif c in range(21, 27 + 1):
-            # Minutes (0-59): DCF77 bits 21-27 (BCD format).
-            if c == 21:
-                self.tmp = bit
-            else:
-                self.tmp |= (bit << (c - 21))
-            if c == 27:
-                self.put(ss, es, a, [0, ['Minutes: %d' % bcd2int(self.tmp)]])
-        elif c == 28:
-            # Even parity over minute bits (21-28): DCF77 bit 28.
-            self.tmp |= (bit << (c - 21))
-            parity = bin(self.tmp).count('1')
-            s = 'OK' if ((parity % 2) == 0) else 'INVALID!'
-            self.put(ss, es, a, [0, ['Minute parity: %s' % s]])
-        elif c in range(29, 34 + 1):
-            # Hours (0-23): DCF77 bits 29-34 (BCD format).
-            if c == 29:
-                self.tmp = bit
-            else:
-                self.tmp |= (bit << (c - 29))
-            if c == 34:
-                self.put(ss, es, a, [0, ['Hours: %d' % bcd2int(self.tmp)]])
-        elif c == 35:
-            # Even parity over hour bits (29-35): DCF77 bit 35.
-            self.tmp |= (bit << (c - 29))
-            parity = bin(self.tmp).count('1')
-            s = 'OK' if ((parity % 2) == 0) else 'INVALID!'
-            self.put(ss, es, a, [0, ['Hour parity: %s' % s]])
-        elif c in range(36, 41 + 1):
-            # Day of month (1-31): DCF77 bits 36-41 (BCD format).
-            if c == 36:
-                self.tmp = bit
-            else:
-                self.tmp |= (bit << (c - 36))
-            if c == 41:
-                self.put(ss, es, a, [0, ['Day: %d' % bcd2int(self.tmp)]])
-        elif c in range(42, 44 + 1):
-            # Day of week (1-7): DCF77 bits 42-44 (BCD format).
-            # A value of 1 means Monday, 7 means Sunday.
-            if c == 42:
-                self.tmp = bit
-            else:
-                self.tmp |= (bit << (c - 42))
-            if c == 44:
-                d = bcd2int(self.tmp)
-                dn = calendar.day_name[d - 1] # day_name[0] == Monday
-                self.put(ss, es, a, [0, ['Day of week: %d (%s)' % (d, dn)]])
-        elif c in range(45, 49 + 1):
-            # Month (1-12): DCF77 bits 45-49 (BCD format).
-            if c == 45:
-                self.tmp = bit
-            else:
-                self.tmp |= (bit << (c - 45))
-            if c == 49:
-                m = bcd2int(self.tmp)
-                mn = calendar.month_name[m] # month_name[1] == January
-                self.put(ss, es, a, [0, ['Month: %d (%s)' % (m, mn)]])
-        elif c in range(50, 57 + 1):
-            # Year (0-99): DCF77 bits 50-57 (BCD format).
-            if c == 50:
-                self.tmp = bit
-            else:
-                self.tmp |= (bit << (c - 50))
-            if c == 57:
-                self.put(ss, es, a, [0, ['Year: %d' % bcd2int(self.tmp)]])
-        elif c == 58:
-            # Even parity over date bits (36-58): DCF77 bit 58.
-            self.tmp |= (bit << (c - 50))
-            parity = bin(self.tmp).count('1')
-            s = 'OK' if ((parity % 2) == 0) else 'INVALID!'
-            self.put(ss, es, a, [0, ['Date parity: %s' % s]])
-        else:
-            raise Exception('Invalid DCF77 bit: %d' % c)
-
-    def decode(self, ss, es, data):
-        for (self.samplenum, pins) in data:
-
-            # Ignore identical samples early on (for performance reasons).
-            if self.oldpins == pins:
-                continue
-            self.oldpins, (val, pon) = pins, pins
-
-            # Always remember the old PON state.
-            if self.oldpon != pon:
-                self.oldpon = pon
-
-            # Warn if PON goes low.
-            if self.oldpon == 1 and pon == 0:
-                self.pon_ss = self.samplenum
-                self.put(self.samplenum, self.samplenum, self.out_ann,
-                         [1, ['Warning: PON goes low, DCF77 reception '
-                         'no longer possible']])
-            elif self.oldpon == 0 and pon == 1:
-                self.put(self.samplenum, self.samplenum, self.out_ann,
-                         [0, ['PON goes high, DCF77 reception now possible']])
-                self.put(self.pon_ss, self.samplenum, self.out_ann,
-                         [1, ['Warning: PON low, DCF77 reception disabled']])
-
-            # Ignore samples where PON == 0, they can't contain DCF77 signals.
-            if pon == 0:
-                continue
-
-            if self.state == 'WAIT FOR RISING EDGE':
-                # Wait until the next rising edge occurs.
-                if not (self.oldval == 0 and val == 1):
-                    self.oldval = val
-                    continue
-
-                # Save the sample number where the DCF77 bit begins.
-                self.bit_start = self.samplenum
-
-                # Calculate the length (in ms) between two rising edges.
-                len_edges = self.bit_start - self.bit_start_old
-                len_edges_ms = int((len_edges / self.samplerate) * 1000)
-
-                # The time between two rising edges is usually around 1000ms.
-                # For DCF77 bit 59, there is no rising edge at all, i.e. the
-                # time between DCF77 bit 59 and DCF77 bit 0 (of the next
-                # minute) is around 2000ms. Thus, if we see an edge with a
-                # 2000ms distance to the last one, this edge marks the
-                # beginning of a new minute (and DCF77 bit 0 of that minute).
-                if len_edges_ms in range(1600, 2400 + 1):
-                    self.put(ss, es, self.out_ann, [0, ['New minute starts']])
-                    self.bitcount = 0
-                    self.bit_start_old = self.bit_start
-                    self.dcf77_bitnumber_is_known = 1
-                    # Don't switch to 'GET BIT' state this time.
-                    continue
-
-                self.bit_start_old = self.bit_start
-                self.state = 'GET BIT'
-
-            elif self.state == 'GET BIT':
-                # Wait until the next falling edge occurs.
-                if not (self.oldval == 1 and val == 0):
-                    self.oldval = val
-                    continue
-
-                # Calculate the length (in ms) of the current high period.
-                len_high = self.samplenum - self.bit_start
-                len_high_ms = int((len_high / self.samplerate) * 1000)
-
-                # If the high signal was 100ms long, that encodes a 0 bit.
-                # If it was 200ms long, that encodes a 1 bit.
-                if len_high_ms in range(40, 160 + 1):
-                    bit = 0
-                elif len_high_ms in range(161, 260 + 1):
-                    bit = 1
-                else:
-                    bit = -1 # TODO: Error?
-
-                # There's no bit 59, make sure none is decoded.
-                if bit in (0, 1) and self.bitcount in range(0, 58 + 1):
-                    self.handle_dcf77_bit(bit)
-                    self.bitcount += 1
-
-                self.state = 'WAIT FOR RISING EDGE'
-
-            else:
-                raise Exception('Invalid state: %d' % self.state)
-
-            self.oldval = val
-
diff --git a/decoders/dcf77/pd.py b/decoders/dcf77/pd.py
new file mode 100644 (file)
index 0000000..c4132e9
--- /dev/null
@@ -0,0 +1,288 @@
+##
+## This file is part of the sigrok project.
+##
+## 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
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+##
+
+# DCF77 protocol decoder
+
+import sigrokdecode as srd
+import calendar
+
+# Return the specified BCD number (max. 8 bits) as integer.
+def bcd2int(b):
+    return (b & 0x0f) + ((b >> 4) * 10)
+
+class Decoder(srd.Decoder):
+    api_version = 1
+    id = 'dcf77'
+    name = 'DCF77'
+    longname = 'DCF77 time protocol'
+    desc = 'European longwave time signal (77.5kHz carrier signal).'
+    license = 'gplv2+'
+    inputs = ['logic']
+    outputs = ['dcf77']
+    probes = [
+        {'id': 'data', 'name': 'DATA', 'desc': 'DATA line'},
+    ]
+    optional_probes = [
+        {'id': 'pon', 'name': 'PON', 'desc': 'Power on'},
+    ]
+    options = {}
+    annotations = [
+        ['Text', 'Human-readable text'],
+        ['Warnings', 'Human-readable warnings'],
+    ]
+
+    def __init__(self, **kwargs):
+        self.state = 'WAIT FOR RISING EDGE'
+        self.oldpins = None
+        self.oldval = None
+        self.oldpon = None
+        self.samplenum = 0
+        self.bit_start = 0
+        self.bit_start_old = 0
+        self.bitcount = 0 # Counter for the DCF77 bits (0..58)
+        self.dcf77_bitnumber_is_known = 0
+
+    def start(self, metadata):
+        self.samplerate = metadata['samplerate']
+        # self.out_proto = self.add(srd.OUTPUT_PROTO, 'dcf77')
+        self.out_ann = self.add(srd.OUTPUT_ANN, 'dcf77')
+
+    def report(self):
+        pass
+
+    # TODO: Which range to use? Only the 100ms/200ms or full second?
+    def handle_dcf77_bit(self, bit):
+        c = self.bitcount
+        a = self.out_ann
+        ss = es = 0 # FIXME
+
+        # Create one annotation for each DCF77 bit (containing the 0/1 value).
+        # Use 'Unknown DCF77 bit x: val' if we're not sure yet which of the
+        # 0..58 bits it is (because we haven't seen a 'new minute' marker yet).
+        # Otherwise, use 'DCF77 bit x: val'.
+        s = '' if self.dcf77_bitnumber_is_known else 'Unknown '
+        self.put(ss, es, a, [0, ['%sDCF77 bit %d: %d' % (s, c, bit)]])
+
+        # If we're not sure yet which of the 0..58 DCF77 bits we have, return.
+        # We don't want to decode bogus data.
+        if not self.dcf77_bitnumber_is_known:
+            return
+
+        # Output specific "decoded" annotations for the respective DCF77 bits.
+        if c == 0:
+            # Start of minute: DCF bit 0.
+            if bit == 0:
+                self.put(ss, es, a, [0, ['Start of minute (always 0)']])
+            else:
+                self.put(ss, es, a, [0, ['ERROR: Start of minute != 0']])
+        elif c in range(1, 14 + 1):
+            # Special bits (civil warnings, weather forecast): DCF77 bits 1-14.
+            if c == 1:
+                self.tmp = bit
+            else:
+                self.tmp |= (bit << (c - 1))
+            if c == 14:
+                self.put(ss, es, a, [0, ['Special bits: %s' % bin(self.tmp)]])
+        elif c == 15:
+            s = '' if (bit == 1) else 'not '
+            self.put(ss, es, a, [0, ['Call bit is %sset' % s]])
+            # TODO: Previously this bit indicated use of the backup antenna.
+        elif c == 16:
+            s = '' if (bit == 1) else 'not '
+            self.put(ss, es, a, [0, ['Summer time announcement %sactive' % s]])
+        elif c == 17:
+            s = '' if (bit == 1) else 'not '
+            self.put(ss, es, a, [0, ['CEST is %sin effect' % s]])
+        elif c == 18:
+            s = '' if (bit == 1) else 'not '
+            self.put(ss, es, a, [0, ['CET is %sin effect' % s]])
+        elif c == 19:
+            s = '' if (bit == 1) else 'not '
+            self.put(ss, es, a, [0, ['Leap second announcement %sactive' % s]])
+        elif c == 20:
+            # Start of encoded time: DCF bit 20.
+            if bit == 1:
+                self.put(ss, es, a, [0, ['Start of encoded time (always 1)']])
+            else:
+                self.put(ss, es, a,
+                         [0, ['ERROR: Start of encoded time != 1']])
+        elif c in range(21, 27 + 1):
+            # Minutes (0-59): DCF77 bits 21-27 (BCD format).
+            if c == 21:
+                self.tmp = bit
+            else:
+                self.tmp |= (bit << (c - 21))
+            if c == 27:
+                self.put(ss, es, a, [0, ['Minutes: %d' % bcd2int(self.tmp)]])
+        elif c == 28:
+            # Even parity over minute bits (21-28): DCF77 bit 28.
+            self.tmp |= (bit << (c - 21))
+            parity = bin(self.tmp).count('1')
+            s = 'OK' if ((parity % 2) == 0) else 'INVALID!'
+            self.put(ss, es, a, [0, ['Minute parity: %s' % s]])
+        elif c in range(29, 34 + 1):
+            # Hours (0-23): DCF77 bits 29-34 (BCD format).
+            if c == 29:
+                self.tmp = bit
+            else:
+                self.tmp |= (bit << (c - 29))
+            if c == 34:
+                self.put(ss, es, a, [0, ['Hours: %d' % bcd2int(self.tmp)]])
+        elif c == 35:
+            # Even parity over hour bits (29-35): DCF77 bit 35.
+            self.tmp |= (bit << (c - 29))
+            parity = bin(self.tmp).count('1')
+            s = 'OK' if ((parity % 2) == 0) else 'INVALID!'
+            self.put(ss, es, a, [0, ['Hour parity: %s' % s]])
+        elif c in range(36, 41 + 1):
+            # Day of month (1-31): DCF77 bits 36-41 (BCD format).
+            if c == 36:
+                self.tmp = bit
+            else:
+                self.tmp |= (bit << (c - 36))
+            if c == 41:
+                self.put(ss, es, a, [0, ['Day: %d' % bcd2int(self.tmp)]])
+        elif c in range(42, 44 + 1):
+            # Day of week (1-7): DCF77 bits 42-44 (BCD format).
+            # A value of 1 means Monday, 7 means Sunday.
+            if c == 42:
+                self.tmp = bit
+            else:
+                self.tmp |= (bit << (c - 42))
+            if c == 44:
+                d = bcd2int(self.tmp)
+                dn = calendar.day_name[d - 1] # day_name[0] == Monday
+                self.put(ss, es, a, [0, ['Day of week: %d (%s)' % (d, dn)]])
+        elif c in range(45, 49 + 1):
+            # Month (1-12): DCF77 bits 45-49 (BCD format).
+            if c == 45:
+                self.tmp = bit
+            else:
+                self.tmp |= (bit << (c - 45))
+            if c == 49:
+                m = bcd2int(self.tmp)
+                mn = calendar.month_name[m] # month_name[1] == January
+                self.put(ss, es, a, [0, ['Month: %d (%s)' % (m, mn)]])
+        elif c in range(50, 57 + 1):
+            # Year (0-99): DCF77 bits 50-57 (BCD format).
+            if c == 50:
+                self.tmp = bit
+            else:
+                self.tmp |= (bit << (c - 50))
+            if c == 57:
+                self.put(ss, es, a, [0, ['Year: %d' % bcd2int(self.tmp)]])
+        elif c == 58:
+            # Even parity over date bits (36-58): DCF77 bit 58.
+            self.tmp |= (bit << (c - 50))
+            parity = bin(self.tmp).count('1')
+            s = 'OK' if ((parity % 2) == 0) else 'INVALID!'
+            self.put(ss, es, a, [0, ['Date parity: %s' % s]])
+        else:
+            raise Exception('Invalid DCF77 bit: %d' % c)
+
+    def decode(self, ss, es, data):
+        for (self.samplenum, pins) in data:
+
+            # Ignore identical samples early on (for performance reasons).
+            if self.oldpins == pins:
+                continue
+            self.oldpins, (val, pon) = pins, pins
+
+            # Always remember the old PON state.
+            if self.oldpon != pon:
+                self.oldpon = pon
+
+            # Warn if PON goes low.
+            if self.oldpon == 1 and pon == 0:
+                self.pon_ss = self.samplenum
+                self.put(self.samplenum, self.samplenum, self.out_ann,
+                         [1, ['Warning: PON goes low, DCF77 reception '
+                         'no longer possible']])
+            elif self.oldpon == 0 and pon == 1:
+                self.put(self.samplenum, self.samplenum, self.out_ann,
+                         [0, ['PON goes high, DCF77 reception now possible']])
+                self.put(self.pon_ss, self.samplenum, self.out_ann,
+                         [1, ['Warning: PON low, DCF77 reception disabled']])
+
+            # Ignore samples where PON == 0, they can't contain DCF77 signals.
+            if pon == 0:
+                continue
+
+            if self.state == 'WAIT FOR RISING EDGE':
+                # Wait until the next rising edge occurs.
+                if not (self.oldval == 0 and val == 1):
+                    self.oldval = val
+                    continue
+
+                # Save the sample number where the DCF77 bit begins.
+                self.bit_start = self.samplenum
+
+                # Calculate the length (in ms) between two rising edges.
+                len_edges = self.bit_start - self.bit_start_old
+                len_edges_ms = int((len_edges / self.samplerate) * 1000)
+
+                # The time between two rising edges is usually around 1000ms.
+                # For DCF77 bit 59, there is no rising edge at all, i.e. the
+                # time between DCF77 bit 59 and DCF77 bit 0 (of the next
+                # minute) is around 2000ms. Thus, if we see an edge with a
+                # 2000ms distance to the last one, this edge marks the
+                # beginning of a new minute (and DCF77 bit 0 of that minute).
+                if len_edges_ms in range(1600, 2400 + 1):
+                    self.put(ss, es, self.out_ann, [0, ['New minute starts']])
+                    self.bitcount = 0
+                    self.bit_start_old = self.bit_start
+                    self.dcf77_bitnumber_is_known = 1
+                    # Don't switch to 'GET BIT' state this time.
+                    continue
+
+                self.bit_start_old = self.bit_start
+                self.state = 'GET BIT'
+
+            elif self.state == 'GET BIT':
+                # Wait until the next falling edge occurs.
+                if not (self.oldval == 1 and val == 0):
+                    self.oldval = val
+                    continue
+
+                # Calculate the length (in ms) of the current high period.
+                len_high = self.samplenum - self.bit_start
+                len_high_ms = int((len_high / self.samplerate) * 1000)
+
+                # If the high signal was 100ms long, that encodes a 0 bit.
+                # If it was 200ms long, that encodes a 1 bit.
+                if len_high_ms in range(40, 160 + 1):
+                    bit = 0
+                elif len_high_ms in range(161, 260 + 1):
+                    bit = 1
+                else:
+                    bit = -1 # TODO: Error?
+
+                # There's no bit 59, make sure none is decoded.
+                if bit in (0, 1) and self.bitcount in range(0, 58 + 1):
+                    self.handle_dcf77_bit(bit)
+                    self.bitcount += 1
+
+                self.state = 'WAIT FOR RISING EDGE'
+
+            else:
+                raise Exception('Invalid state: %d' % self.state)
+
+            self.oldval = val
+
index 2ec1715cfdf1d0540f27cd90e68f227ae9614673..8381dcca4778080840cd5493a8d35a76f820c5c5 100644 (file)
@@ -20,7 +20,7 @@
 
 pkgdatadir = $(DECODERS_DIR)/edid
 
-dist_pkgdata_DATA = __init__.py edid.py pnpids.txt
+dist_pkgdata_DATA = __init__.py pd.py pnpids.txt
 
 CLEANFILES = *.pyc
 
index 0987d1780ee6f7d7b82912529538564c704e7352..baa268161b58baabd879ced7c3a2b920c2b3bf9b 100644 (file)
@@ -36,5 +36,5 @@ More information on EDID is available here:
  https://en.wikipedia.org/wiki/Extended_display_identification_data
 '''
 
-from .edid import *
+from .pd import *
 
diff --git a/decoders/edid/edid.py b/decoders/edid/edid.py
deleted file mode 100644 (file)
index a03fe67..0000000
+++ /dev/null
@@ -1,474 +0,0 @@
-##
-## This file is part of the sigrok project.
-##
-## Copyright (C) 2012 Bert Vermeulen <bert@biot.com>
-##
-## 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
-## the Free Software Foundation; either version 3 of the License, or
-## (at your option) any later version.
-##
-## This program is distributed in the hope that it will be useful,
-## but WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-## GNU General Public License for more details.
-##
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, see <http://www.gnu.org/licenses/>.
-##
-
-# EDID protocol decoder
-
-# TODO:
-#    - EDID < 1.3
-#    - add short annotations
-#    - Signal level standard field in basic display parameters block
-#    - Additional color point descriptors
-#    - Additional standard timing descriptors
-#    - Extensions
-
-import sigrokdecode as srd
-import os
-
-EDID_HEADER = [0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00]
-OFF_VENDOR = 8
-OFF_VERSION = 18
-OFF_BASIC = 20
-OFF_CHROM = 25
-OFF_EST_TIMING = 35
-OFF_STD_TIMING = 38
-OFF_DET_TIMING = 54
-OFF_NUM_EXT = 126
-OFF_CHECKSUM = 127
-
-# Pre-EDID established timing modes
-est_modes = [
-    '720x400@70Hz',
-    '720x400@88Hz',
-    '640x480@60Hz',
-    '640x480@67Hz',
-    '640x480@72Hz',
-    '640x480@75Hz',
-    '800x600@56Hz',
-    '800x600@60Hz',
-    '800x600@72Hz',
-    '800x600@75Hz',
-    '832x624@75Hz',
-    '1024x768@87Hz(i)',
-    '1024x768@60Hz',
-    '1024x768@70Hz',
-    '1024x768@75Hz',
-    '1280x1024@75Hz',
-    '1152x870@75Hz',
-]
-
-# X:Y display aspect ratios, as used in standard timing modes
-xy_ratio = [
-    (16, 10),
-    (4, 3),
-    (5, 4),
-    (16, 9),
-]
-
-# Annotation types
-ANN_FIELDS = 0
-ANN_SECTIONS = 1
-
-class Decoder(srd.Decoder):
-    api_version = 1
-    id = 'edid'
-    name = 'EDID'
-    longname = 'Extended Display Identification Data'
-    desc = 'Data structure describing display device capabilities.'
-    license = 'gplv3+'
-    inputs = ['ddc2']
-    outputs = ['edid']
-    options = {}
-    annotations = [
-        ['EDID fields', 'EDID structure fields'],
-        ['EDID sections', 'EDID structure sections'],
-    ]
-
-    def __init__(self, **kwargs):
-        self.state = None
-        # Received data items, used as an index into samplenum/data
-        self.cnt = 0
-        # Start/end sample numbers per data item
-        self.sn = []
-        # Received data
-        self.cache = []
-
-    def start(self, metadata):
-        self.out_ann = self.add(srd.OUTPUT_ANN, 'edid')
-
-    def report(self):
-        pass
-
-    def decode(self, ss, es, data):
-        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)
-        # debug
-#        self.put(ss, es, self.out_ann, [0, ['%d: [%.2x]' % (self.cnt, data)]])
-
-        if self.state is None:
-            # Wait for the EDID header
-            if self.cnt >= OFF_VENDOR:
-                if self.cache[-8:] == EDID_HEADER:
-                    # Throw away any garbage before the header
-                    self.sn = self.sn[-8:]
-                    self.cache = self.cache[-8:]
-                    self.cnt = 8
-                    self.state = 'edid'
-                    self.put(ss, es, self.out_ann, [0, ['EDID header']])
-        elif self.state == 'edid':
-            if self.cnt == OFF_VERSION:
-                self.decode_vid(-10)
-                self.decode_pid(-8)
-                self.decode_serial(-6)
-                self.decode_mfrdate(-2)
-            elif self.cnt == OFF_BASIC:
-                version = 'EDID version: %d.%d' % (self.cache[-2], self.cache[-1])
-                self.put(ss, es, self.out_ann, [0, [version]])
-            elif self.cnt == OFF_CHROM:
-                self.decode_basicdisplay(-5)
-            elif self.cnt == OFF_EST_TIMING:
-                self.decode_chromaticity(-10)
-            elif self.cnt == OFF_STD_TIMING:
-                self.decode_est_timing(-3)
-            elif self.cnt == OFF_DET_TIMING:
-                self.decode_std_timing(-16)
-            elif self.cnt == OFF_NUM_EXT:
-                self.decode_descriptors(-72)
-            elif self.cnt == OFF_CHECKSUM:
-                self.put(ss, es, self.out_ann,
-                    [0, ['Extensions present: %d' % self.cache[self.cnt-1]]])
-            elif self.cnt == OFF_CHECKSUM+1:
-                checksum = 0
-                for i in range(128):
-                    checksum += self.cache[i]
-                if checksum % 256 == 0:
-                    csstr = 'OK'
-                else:
-                    csstr = 'WRONG!'
-                self.put(ss, es, self.out_ann, [0, ['Checksum: %d (%s)' % (
-                         self.cache[self.cnt-1], csstr)]])
-                self.state = 'extensions'
-        elif self.state == 'extensions':
-            pass
-
-    def ann_field(self, start, end, annotation):
-        self.put(self.sn[start][0], self.sn[end][1],
-                 self.out_ann, [ANN_FIELDS, [annotation]])
-
-    def lookup_pnpid(self, pnpid):
-        pnpid_file = os.path.join(os.path.dirname(__file__), 'pnpids.txt')
-        if os.path.exists(pnpid_file):
-            for line in open(pnpid_file).readlines():
-                if line.find(pnpid + ';') == 0:
-                    return line[4:].strip()
-        return ''
-
-    def decode_vid(self, offset):
-        pnpid = chr(64 + ((self.cache[offset] & 0x7c) >> 2))
-        pnpid += chr(64 + (((self.cache[offset] & 0x03) << 3)
-                           | ((self.cache[offset+1] & 0xe0) >> 5)))
-        pnpid += chr(64 + (self.cache[offset+1] & 0x1f))
-        vendor = self.lookup_pnpid(pnpid)
-        if vendor:
-            pnpid += ' (%s)' % vendor
-        self.ann_field(offset, offset+1, pnpid)
-
-    def decode_pid(self, offset):
-        pidstr = 'Product 0x%.2x%.2x' % (self.cache[offset+1], self.cache[offset])
-        self.ann_field(offset, offset+1, pidstr)
-
-    def decode_serial(self, offset):
-        serialnum = (self.cache[offset+3] << 24) \
-                + (self.cache[offset+2] << 16) \
-                + (self.cache[offset+1] << 8) \
-                + self.cache[offset]
-        serialstr = ''
-        is_alnum = True
-        for i in range(4):
-            if not chr(self.cache[offset+3-i]).isalnum():
-                is_alnum = False
-                break
-            serialstr += chr(self.cache[offset+3-i])
-        serial = serialstr if is_alnum else str(serialnum)
-        self.ann_field(offset, offset+3, 'Serial ' + serial)
-
-    def decode_mfrdate(self, offset):
-        datestr = ''
-        if self.cache[offset]:
-            datestr += 'week %d, ' % self.cache[offset]
-        datestr += str(1990 + self.cache[offset+1])
-        if datestr:
-            self.ann_field(offset, offset+1, 'Manufactured ' + datestr)
-
-    def decode_basicdisplay(self, offset):
-        # Video input definition
-        vid = self.cache[offset]
-        if vid & 0x80:
-            # Digital
-            self.ann_field(offset, offset, 'Video input: VESA DFP 1.')
-        else:
-            # Analog
-            sls = (vid & 60) >> 5
-            self.ann_field(offset, offset, 'Signal level standard: %.2x' % sls)
-            if vid & 0x10:
-                self.ann_field(offset, offset, 'Blank-to-black setup expected')
-            syncs = ''
-            if vid & 0x08:
-                syncs += 'separate syncs, '
-            if vid & 0x04:
-                syncs += 'composite syncs, '
-            if vid & 0x02:
-                syncs += 'sync on green, '
-            if vid & 0x01:
-                syncs += 'Vsync serration required, '
-            if syncs:
-                self.ann_field(offset, offset, 'Supported syncs: %s' % syncs[:-2])
-        # Max horizontal/vertical image size
-        if self.cache[offset+1] != 0 and self.cache[offset+2] != 0:
-            # Projectors have this set to 0
-            sizestr = '%dx%dcm' % (self.cache[offset+1], self.cache[offset+2])
-            self.ann_field(offset+1, offset+2, 'Physical size: ' + sizestr)
-        # Display transfer characteristic (gamma)
-        if self.cache[offset+3] != 0xff:
-            gamma = (self.cache[offset+3] + 100) / 100
-            self.ann_field(offset+3, offset+3, 'Gamma: %1.2f' % gamma)
-        # Feature support
-        fs = self.cache[offset+4]
-        dpms = ''
-        if fs & 0x80:
-            dpms += 'standby, '
-        if fs & 0x40:
-            dpms += 'suspend, '
-        if fs & 0x20:
-            dpms += 'active off, '
-        if dpms:
-            self.ann_field(offset+4, offset+4, 'DPMS support: %s' % dpms[:-2])
-        dt = (fs & 0x18) >> 3
-        dtstr = ''
-        if dt == 0:
-            dtstr = 'Monochrome'
-        elif dt == 1:
-            dtstr = 'RGB color'
-        elif dt == 2:
-            dtstr = 'non-RGB multicolor'
-        if dtstr:
-            self.ann_field(offset+4, offset+4, 'Display type: %s' % dtstr)
-        if fs & 0x04:
-            self.ann_field(offset+4, offset+4, 'Color space: standard sRGB')
-        # Save this for when we decode the first detailed timing descriptor
-        self.have_preferred_timing = (fs & 0x02) == 0x02
-        if fs & 0x01:
-            gft = ''
-        else:
-            gft = 'not '
-        self.ann_field(offset+4, offset+4,
-                       'Generalized timing formula: %ssupported' % gft)
-
-    def convert_color(self, value):
-        # Convert from 10-bit packet format to float
-        outval = 0.0
-        for i in range(10):
-            if value & 0x01:
-                outval += 2 ** -(10-i)
-            value >>= 1
-        return outval
-
-    def decode_chromaticity(self, offset):
-        redx = (self.cache[offset+2] << 2) + ((self.cache[offset] & 0xc0) >> 6)
-        redy = (self.cache[offset+3] << 2) + ((self.cache[offset] & 0x30) >> 4)
-        self.ann_field(offset, offset+9, 'Chromacity red: X %1.3f, Y %1.3f' % (
-                       self.convert_color(redx), self.convert_color(redy)))
-
-        greenx = (self.cache[offset+4] << 2) + ((self.cache[offset] & 0x0c) >> 6)
-        greeny = (self.cache[offset+5] << 2) + ((self.cache[offset] & 0x03) >> 4)
-        self.ann_field(offset, offset+9, 'Chromacity green: X %1.3f, Y %1.3f' % (
-                       self.convert_color(greenx), self.convert_color(greeny)))
-
-        bluex = (self.cache[offset+6] << 2) + ((self.cache[offset+1] & 0xc0) >> 6)
-        bluey = (self.cache[offset+7] << 2) + ((self.cache[offset+1] & 0x30) >> 4)
-        self.ann_field(offset, offset+9, 'Chromacity blue: X %1.3f, Y %1.3f' % (
-                       self.convert_color(bluex), self.convert_color(bluey)))
-
-        whitex = (self.cache[offset+8] << 2) + ((self.cache[offset+1] & 0x0c) >> 6)
-        whitey = (self.cache[offset+9] << 2) + ((self.cache[offset+1] & 0x03) >> 4)
-        self.ann_field(offset, offset+9, 'Chromacity white: X %1.3f, Y %1.3f' % (
-                       self.convert_color(whitex), self.convert_color(whitey)))
-
-    def decode_est_timing(self, offset):
-        # Pre-EDID modes
-        bitmap = (self.cache[offset] << 9) \
-            + (self.cache[offset+1] << 1) \
-            + ((self.cache[offset+2] & 0x80) >> 7)
-        modestr = ''
-        for i in range(17):
-                if bitmap & (1 << (16-i)):
-                    modestr += est_modes[i] + ', '
-        if modestr:
-            self.ann_field(offset, offset+2,
-                           'Supported establised modes: %s' % modestr[:-2])
-
-    def decode_std_timing(self, offset):
-        modestr = ''
-        for i in range(0, 16, 2):
-            if self.cache[offset+i] == 0x01 and self.cache[offset+i+1] == 0x01:
-                # Unused field
-                continue
-            x = (self.cache[offset+i] + 31) * 8
-            ratio = (self.cache[offset+i+1] & 0xc0) >> 6
-            ratio_x, ratio_y = xy_ratio[ratio]
-            y = x / ratio_x * ratio_y
-            refresh = (self.cache[offset+i+1] & 0x3f) + 60
-            modestr += '%dx%d@%dHz, ' % (x, y, refresh)
-        if modestr:
-            self.ann_field(offset, offset+2,
-                           'Supported standard modes: %s' % modestr[:-2])
-
-    def decode_detailed_timing(self, offset):
-        if offset == -72 and self.have_preferred_timing:
-            # Only on first detailed timing descriptor
-            section = 'Preferred'
-        else:
-            section = 'Detailed'
-        section += ' timing descriptor'
-        self.put(self.sn[offset][0], self.sn[offset+18][1],
-             self.out_ann, [ANN_SECTIONS, [section]])
-
-        pixclock = float((self.cache[offset+1] << 8) + self.cache[offset]) / 100
-        self.ann_field(offset, offset+1, 'Pixel clock: %.2f MHz' % pixclock)
-
-        horiz_active = ((self.cache[offset+4] & 0xf0) << 4) + self.cache[offset+2]
-        self.ann_field(offset+2, offset+4, 'Horizontal active: %d' % horiz_active)
-
-        horiz_blank = ((self.cache[offset+4] & 0x0f) << 8) + self.cache[offset+3]
-        self.ann_field(offset+3, offset+4, 'Horizontal blanking: %d' % horiz_blank)
-
-        vert_active = ((self.cache[offset+7] & 0xf0) << 4) + self.cache[offset+5]
-        self.ann_field(offset+5, offset+7, 'Vertical active: %d' % vert_active)
-
-        vert_blank = ((self.cache[offset+7] & 0x0f) << 8) + self.cache[offset+6]
-        self.ann_field(offset+6, offset+7, 'Vertical blanking: %d' % vert_blank)
-
-        horiz_sync_off = ((self.cache[offset+11] & 0xc0) << 2) + self.cache[offset+8]
-        self.ann_field(offset+8, offset+11, 'Horizontal sync offset: %d' % horiz_sync_off)
-
-        horiz_sync_pw = ((self.cache[offset+11] & 0x30) << 4) + self.cache[offset+9]
-        self.ann_field(offset+9, offset+11, 'Horizontal sync pulse width: %d' % horiz_sync_pw)
-
-        vert_sync_off = ((self.cache[offset+11] & 0x0c) << 2) \
-                    + ((self.cache[offset+10] & 0xf0) >> 4)
-        self.ann_field(offset+10, offset+11, 'Vertical sync offset: %d' % vert_sync_off)
-
-        vert_sync_pw = ((self.cache[offset+11] & 0x03) << 4) \
-                    + (self.cache[offset+10] & 0x0f)
-        self.ann_field(offset+10, offset+11, 'Vertical sync pulse width: %d' % vert_sync_pw)
-
-        horiz_size = ((self.cache[offset+14] & 0xf0) << 4) + self.cache[offset+12]
-        vert_size = ((self.cache[offset+14] & 0x0f) << 8) + self.cache[offset+13]
-        self.ann_field(offset+12, offset+14, 'Physical size: %dx%dmm' % (horiz_size, vert_size))
-
-        horiz_border = self.cache[offset+15]
-        if horiz_border:
-            self.ann_field(offset+15, offset+15, 'Horizontal border: %d pixels' % horiz_border)
-        vert_border = self.cache[offset+16]
-        if vert_border:
-            self.ann_field(offset+16, offset+16, 'Vertical border: %d lines' % vert_border)
-
-        features = 'Flags: '
-        if self.cache[offset+17] & 0x80:
-            features += 'interlaced, '
-        stereo = (self.cache[offset+17] & 0x60) >> 5
-        if stereo:
-            if self.cache[offset+17] & 0x01:
-                features += '2-way interleaved stereo ('
-                features += ['right image on even lines',
-                             'left image on even lines',
-                             'side-by-side'][stereo-1]
-                features += '), '
-            else:
-                features += 'field sequential stereo ('
-                features += ['right image on sync=1', 'left image on sync=1',
-                             '4-way interleaved'][stereo-1]
-                features += '), '
-        sync = (self.cache[offset+17] & 0x18) >> 3
-        sync2 = (self.cache[offset+17] & 0x06) >> 1
-        posneg = ['negative', 'positive']
-        features += 'sync type '
-        if sync == 0x00:
-            features += 'analog composite (serrate on RGB)'
-        elif sync == 0x01:
-            features += 'bipolar analog composite (serrate on RGB)'
-        elif sync == 0x02:
-            features += 'digital composite (serrate on composite polarity ' \
-                        + (posneg[sync2 & 0x01]) + ')'
-        elif sync == 0x03:
-            features += 'digital separate ('
-            features += 'Vsync polarity ' + (posneg[(sync2 & 0x02) >> 1])
-            features += ', Hsync polarity ' + (posneg[sync2 & 0x01])
-            features += ')'
-        features += ', '
-        self.ann_field(offset+17, offset+17, features[:-2])
-
-    def decode_descriptor(self, offset):
-        tag = self.cache[offset+3]
-        if tag == 0xff:
-            # Monitor serial number
-            text = bytes(self.cache[offset+5:][:13]).decode(encoding='cp437', errors='replace')
-            self.ann_field(offset, offset+17, 'Serial number: %s' % text.strip())
-        elif tag == 0xfe:
-            # Text
-            text = bytes(self.cache[offset+5:][:13]).decode(encoding='cp437', errors='replace')
-            self.ann_field(offset, offset+17, 'Info: %s' % text.strip())
-        elif tag == 0xfc:
-            # Monitor name
-            text = bytes(self.cache[offset+5:][:13]).decode(encoding='cp437', errors='replace')
-            self.ann_field(offset, offset+17, 'Model name: %s' % text.strip())
-        elif tag == 0xfd:
-            # Monitor range limits
-            self.put(self.sn[offset][0], self.sn[offset+17][1], self.out_ann,
-                     [ANN_SECTIONS, ['Monitor range limits']])
-            self.ann_field(offset+5, offset+5, 'Minimum vertical rate: %dHz' %
-                           self.cache[offset+5])
-            self.ann_field(offset+6, offset+6, 'Maximum vertical rate: %dHz' %
-                           self.cache[offset+6])
-            self.ann_field(offset+7, offset+7, 'Minimum horizontal rate: %dkHz' %
-                           self.cache[offset+7])
-            self.ann_field(offset+8, offset+8, 'Maximum horizontal rate: %dkHz' %
-                           self.cache[offset+8])
-            self.ann_field(offset+9, offset+9, 'Maximum pixel clock: %dMHz' %
-                           (self.cache[offset+9] * 10))
-            if self.cache[offset+10] == 0x02:
-                # Secondary GTF curve supported
-                self.ann_field(offset+10, offset+17, 'Secondary timing formula supported')
-        elif tag == 0xfb:
-            # Additional color point data
-            self.put(self.sn[offset][0], self.sn[offset+17][1], self.out_ann,
-                     [ANN_SECTIONS, ['Additional color point data']])
-        elif tag == 0xfa:
-            # Additional standard timing definitions
-            self.put(self.sn[offset][0], self.sn[offset+17][1], self.out_ann,
-                     [ANN_SECTIONS, ['Additional standard timing definitions']])
-        else:
-            self.put(self.sn[offset][0], self.sn[offset+17][1], self.out_ann,
-                     [ANN_SECTIONS, ['Unknown descriptor']])
-
-    def decode_descriptors(self, offset):
-        # 4 consecutive 18-byte descriptor blocks
-        for i in range(offset, 0, 18):
-            if self.cache[i] != 0 and self.cache[i+1] != 0:
-                self.decode_detailed_timing(i)
-            else:
-                if self.cache[i+2] == 0 or self.cache[i+4] == 0:
-                    self.decode_descriptor(i)
-
diff --git a/decoders/edid/pd.py b/decoders/edid/pd.py
new file mode 100644 (file)
index 0000000..a03fe67
--- /dev/null
@@ -0,0 +1,474 @@
+##
+## This file is part of the sigrok project.
+##
+## Copyright (C) 2012 Bert Vermeulen <bert@biot.com>
+##
+## 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
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, see <http://www.gnu.org/licenses/>.
+##
+
+# EDID protocol decoder
+
+# TODO:
+#    - EDID < 1.3
+#    - add short annotations
+#    - Signal level standard field in basic display parameters block
+#    - Additional color point descriptors
+#    - Additional standard timing descriptors
+#    - Extensions
+
+import sigrokdecode as srd
+import os
+
+EDID_HEADER = [0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00]
+OFF_VENDOR = 8
+OFF_VERSION = 18
+OFF_BASIC = 20
+OFF_CHROM = 25
+OFF_EST_TIMING = 35
+OFF_STD_TIMING = 38
+OFF_DET_TIMING = 54
+OFF_NUM_EXT = 126
+OFF_CHECKSUM = 127
+
+# Pre-EDID established timing modes
+est_modes = [
+    '720x400@70Hz',
+    '720x400@88Hz',
+    '640x480@60Hz',
+    '640x480@67Hz',
+    '640x480@72Hz',
+    '640x480@75Hz',
+    '800x600@56Hz',
+    '800x600@60Hz',
+    '800x600@72Hz',
+    '800x600@75Hz',
+    '832x624@75Hz',
+    '1024x768@87Hz(i)',
+    '1024x768@60Hz',
+    '1024x768@70Hz',
+    '1024x768@75Hz',
+    '1280x1024@75Hz',
+    '1152x870@75Hz',
+]
+
+# X:Y display aspect ratios, as used in standard timing modes
+xy_ratio = [
+    (16, 10),
+    (4, 3),
+    (5, 4),
+    (16, 9),
+]
+
+# Annotation types
+ANN_FIELDS = 0
+ANN_SECTIONS = 1
+
+class Decoder(srd.Decoder):
+    api_version = 1
+    id = 'edid'
+    name = 'EDID'
+    longname = 'Extended Display Identification Data'
+    desc = 'Data structure describing display device capabilities.'
+    license = 'gplv3+'
+    inputs = ['ddc2']
+    outputs = ['edid']
+    options = {}
+    annotations = [
+        ['EDID fields', 'EDID structure fields'],
+        ['EDID sections', 'EDID structure sections'],
+    ]
+
+    def __init__(self, **kwargs):
+        self.state = None
+        # Received data items, used as an index into samplenum/data
+        self.cnt = 0
+        # Start/end sample numbers per data item
+        self.sn = []
+        # Received data
+        self.cache = []
+
+    def start(self, metadata):
+        self.out_ann = self.add(srd.OUTPUT_ANN, 'edid')
+
+    def report(self):
+        pass
+
+    def decode(self, ss, es, data):
+        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)
+        # debug
+#        self.put(ss, es, self.out_ann, [0, ['%d: [%.2x]' % (self.cnt, data)]])
+
+        if self.state is None:
+            # Wait for the EDID header
+            if self.cnt >= OFF_VENDOR:
+                if self.cache[-8:] == EDID_HEADER:
+                    # Throw away any garbage before the header
+                    self.sn = self.sn[-8:]
+                    self.cache = self.cache[-8:]
+                    self.cnt = 8
+                    self.state = 'edid'
+                    self.put(ss, es, self.out_ann, [0, ['EDID header']])
+        elif self.state == 'edid':
+            if self.cnt == OFF_VERSION:
+                self.decode_vid(-10)
+                self.decode_pid(-8)
+                self.decode_serial(-6)
+                self.decode_mfrdate(-2)
+            elif self.cnt == OFF_BASIC:
+                version = 'EDID version: %d.%d' % (self.cache[-2], self.cache[-1])
+                self.put(ss, es, self.out_ann, [0, [version]])
+            elif self.cnt == OFF_CHROM:
+                self.decode_basicdisplay(-5)
+            elif self.cnt == OFF_EST_TIMING:
+                self.decode_chromaticity(-10)
+            elif self.cnt == OFF_STD_TIMING:
+                self.decode_est_timing(-3)
+            elif self.cnt == OFF_DET_TIMING:
+                self.decode_std_timing(-16)
+            elif self.cnt == OFF_NUM_EXT:
+                self.decode_descriptors(-72)
+            elif self.cnt == OFF_CHECKSUM:
+                self.put(ss, es, self.out_ann,
+                    [0, ['Extensions present: %d' % self.cache[self.cnt-1]]])
+            elif self.cnt == OFF_CHECKSUM+1:
+                checksum = 0
+                for i in range(128):
+                    checksum += self.cache[i]
+                if checksum % 256 == 0:
+                    csstr = 'OK'
+                else:
+                    csstr = 'WRONG!'
+                self.put(ss, es, self.out_ann, [0, ['Checksum: %d (%s)' % (
+                         self.cache[self.cnt-1], csstr)]])
+                self.state = 'extensions'
+        elif self.state == 'extensions':
+            pass
+
+    def ann_field(self, start, end, annotation):
+        self.put(self.sn[start][0], self.sn[end][1],
+                 self.out_ann, [ANN_FIELDS, [annotation]])
+
+    def lookup_pnpid(self, pnpid):
+        pnpid_file = os.path.join(os.path.dirname(__file__), 'pnpids.txt')
+        if os.path.exists(pnpid_file):
+            for line in open(pnpid_file).readlines():
+                if line.find(pnpid + ';') == 0:
+                    return line[4:].strip()
+        return ''
+
+    def decode_vid(self, offset):
+        pnpid = chr(64 + ((self.cache[offset] & 0x7c) >> 2))
+        pnpid += chr(64 + (((self.cache[offset] & 0x03) << 3)
+                           | ((self.cache[offset+1] & 0xe0) >> 5)))
+        pnpid += chr(64 + (self.cache[offset+1] & 0x1f))
+        vendor = self.lookup_pnpid(pnpid)
+        if vendor:
+            pnpid += ' (%s)' % vendor
+        self.ann_field(offset, offset+1, pnpid)
+
+    def decode_pid(self, offset):
+        pidstr = 'Product 0x%.2x%.2x' % (self.cache[offset+1], self.cache[offset])
+        self.ann_field(offset, offset+1, pidstr)
+
+    def decode_serial(self, offset):
+        serialnum = (self.cache[offset+3] << 24) \
+                + (self.cache[offset+2] << 16) \
+                + (self.cache[offset+1] << 8) \
+                + self.cache[offset]
+        serialstr = ''
+        is_alnum = True
+        for i in range(4):
+            if not chr(self.cache[offset+3-i]).isalnum():
+                is_alnum = False
+                break
+            serialstr += chr(self.cache[offset+3-i])
+        serial = serialstr if is_alnum else str(serialnum)
+        self.ann_field(offset, offset+3, 'Serial ' + serial)
+
+    def decode_mfrdate(self, offset):
+        datestr = ''
+        if self.cache[offset]:
+            datestr += 'week %d, ' % self.cache[offset]
+        datestr += str(1990 + self.cache[offset+1])
+        if datestr:
+            self.ann_field(offset, offset+1, 'Manufactured ' + datestr)
+
+    def decode_basicdisplay(self, offset):
+        # Video input definition
+        vid = self.cache[offset]
+        if vid & 0x80:
+            # Digital
+            self.ann_field(offset, offset, 'Video input: VESA DFP 1.')
+        else:
+            # Analog
+            sls = (vid & 60) >> 5
+            self.ann_field(offset, offset, 'Signal level standard: %.2x' % sls)
+            if vid & 0x10:
+                self.ann_field(offset, offset, 'Blank-to-black setup expected')
+            syncs = ''
+            if vid & 0x08:
+                syncs += 'separate syncs, '
+            if vid & 0x04:
+                syncs += 'composite syncs, '
+            if vid & 0x02:
+                syncs += 'sync on green, '
+            if vid & 0x01:
+                syncs += 'Vsync serration required, '
+            if syncs:
+                self.ann_field(offset, offset, 'Supported syncs: %s' % syncs[:-2])
+        # Max horizontal/vertical image size
+        if self.cache[offset+1] != 0 and self.cache[offset+2] != 0:
+            # Projectors have this set to 0
+            sizestr = '%dx%dcm' % (self.cache[offset+1], self.cache[offset+2])
+            self.ann_field(offset+1, offset+2, 'Physical size: ' + sizestr)
+        # Display transfer characteristic (gamma)
+        if self.cache[offset+3] != 0xff:
+            gamma = (self.cache[offset+3] + 100) / 100
+            self.ann_field(offset+3, offset+3, 'Gamma: %1.2f' % gamma)
+        # Feature support
+        fs = self.cache[offset+4]
+        dpms = ''
+        if fs & 0x80:
+            dpms += 'standby, '
+        if fs & 0x40:
+            dpms += 'suspend, '
+        if fs & 0x20:
+            dpms += 'active off, '
+        if dpms:
+            self.ann_field(offset+4, offset+4, 'DPMS support: %s' % dpms[:-2])
+        dt = (fs & 0x18) >> 3
+        dtstr = ''
+        if dt == 0:
+            dtstr = 'Monochrome'
+        elif dt == 1:
+            dtstr = 'RGB color'
+        elif dt == 2:
+            dtstr = 'non-RGB multicolor'
+        if dtstr:
+            self.ann_field(offset+4, offset+4, 'Display type: %s' % dtstr)
+        if fs & 0x04:
+            self.ann_field(offset+4, offset+4, 'Color space: standard sRGB')
+        # Save this for when we decode the first detailed timing descriptor
+        self.have_preferred_timing = (fs & 0x02) == 0x02
+        if fs & 0x01:
+            gft = ''
+        else:
+            gft = 'not '
+        self.ann_field(offset+4, offset+4,
+                       'Generalized timing formula: %ssupported' % gft)
+
+    def convert_color(self, value):
+        # Convert from 10-bit packet format to float
+        outval = 0.0
+        for i in range(10):
+            if value & 0x01:
+                outval += 2 ** -(10-i)
+            value >>= 1
+        return outval
+
+    def decode_chromaticity(self, offset):
+        redx = (self.cache[offset+2] << 2) + ((self.cache[offset] & 0xc0) >> 6)
+        redy = (self.cache[offset+3] << 2) + ((self.cache[offset] & 0x30) >> 4)
+        self.ann_field(offset, offset+9, 'Chromacity red: X %1.3f, Y %1.3f' % (
+                       self.convert_color(redx), self.convert_color(redy)))
+
+        greenx = (self.cache[offset+4] << 2) + ((self.cache[offset] & 0x0c) >> 6)
+        greeny = (self.cache[offset+5] << 2) + ((self.cache[offset] & 0x03) >> 4)
+        self.ann_field(offset, offset+9, 'Chromacity green: X %1.3f, Y %1.3f' % (
+                       self.convert_color(greenx), self.convert_color(greeny)))
+
+        bluex = (self.cache[offset+6] << 2) + ((self.cache[offset+1] & 0xc0) >> 6)
+        bluey = (self.cache[offset+7] << 2) + ((self.cache[offset+1] & 0x30) >> 4)
+        self.ann_field(offset, offset+9, 'Chromacity blue: X %1.3f, Y %1.3f' % (
+                       self.convert_color(bluex), self.convert_color(bluey)))
+
+        whitex = (self.cache[offset+8] << 2) + ((self.cache[offset+1] & 0x0c) >> 6)
+        whitey = (self.cache[offset+9] << 2) + ((self.cache[offset+1] & 0x03) >> 4)
+        self.ann_field(offset, offset+9, 'Chromacity white: X %1.3f, Y %1.3f' % (
+                       self.convert_color(whitex), self.convert_color(whitey)))
+
+    def decode_est_timing(self, offset):
+        # Pre-EDID modes
+        bitmap = (self.cache[offset] << 9) \
+            + (self.cache[offset+1] << 1) \
+            + ((self.cache[offset+2] & 0x80) >> 7)
+        modestr = ''
+        for i in range(17):
+                if bitmap & (1 << (16-i)):
+                    modestr += est_modes[i] + ', '
+        if modestr:
+            self.ann_field(offset, offset+2,
+                           'Supported establised modes: %s' % modestr[:-2])
+
+    def decode_std_timing(self, offset):
+        modestr = ''
+        for i in range(0, 16, 2):
+            if self.cache[offset+i] == 0x01 and self.cache[offset+i+1] == 0x01:
+                # Unused field
+                continue
+            x = (self.cache[offset+i] + 31) * 8
+            ratio = (self.cache[offset+i+1] & 0xc0) >> 6
+            ratio_x, ratio_y = xy_ratio[ratio]
+            y = x / ratio_x * ratio_y
+            refresh = (self.cache[offset+i+1] & 0x3f) + 60
+            modestr += '%dx%d@%dHz, ' % (x, y, refresh)
+        if modestr:
+            self.ann_field(offset, offset+2,
+                           'Supported standard modes: %s' % modestr[:-2])
+
+    def decode_detailed_timing(self, offset):
+        if offset == -72 and self.have_preferred_timing:
+            # Only on first detailed timing descriptor
+            section = 'Preferred'
+        else:
+            section = 'Detailed'
+        section += ' timing descriptor'
+        self.put(self.sn[offset][0], self.sn[offset+18][1],
+             self.out_ann, [ANN_SECTIONS, [section]])
+
+        pixclock = float((self.cache[offset+1] << 8) + self.cache[offset]) / 100
+        self.ann_field(offset, offset+1, 'Pixel clock: %.2f MHz' % pixclock)
+
+        horiz_active = ((self.cache[offset+4] & 0xf0) << 4) + self.cache[offset+2]
+        self.ann_field(offset+2, offset+4, 'Horizontal active: %d' % horiz_active)
+
+        horiz_blank = ((self.cache[offset+4] & 0x0f) << 8) + self.cache[offset+3]
+        self.ann_field(offset+3, offset+4, 'Horizontal blanking: %d' % horiz_blank)
+
+        vert_active = ((self.cache[offset+7] & 0xf0) << 4) + self.cache[offset+5]
+        self.ann_field(offset+5, offset+7, 'Vertical active: %d' % vert_active)
+
+        vert_blank = ((self.cache[offset+7] & 0x0f) << 8) + self.cache[offset+6]
+        self.ann_field(offset+6, offset+7, 'Vertical blanking: %d' % vert_blank)
+
+        horiz_sync_off = ((self.cache[offset+11] & 0xc0) << 2) + self.cache[offset+8]
+        self.ann_field(offset+8, offset+11, 'Horizontal sync offset: %d' % horiz_sync_off)
+
+        horiz_sync_pw = ((self.cache[offset+11] & 0x30) << 4) + self.cache[offset+9]
+        self.ann_field(offset+9, offset+11, 'Horizontal sync pulse width: %d' % horiz_sync_pw)
+
+        vert_sync_off = ((self.cache[offset+11] & 0x0c) << 2) \
+                    + ((self.cache[offset+10] & 0xf0) >> 4)
+        self.ann_field(offset+10, offset+11, 'Vertical sync offset: %d' % vert_sync_off)
+
+        vert_sync_pw = ((self.cache[offset+11] & 0x03) << 4) \
+                    + (self.cache[offset+10] & 0x0f)
+        self.ann_field(offset+10, offset+11, 'Vertical sync pulse width: %d' % vert_sync_pw)
+
+        horiz_size = ((self.cache[offset+14] & 0xf0) << 4) + self.cache[offset+12]
+        vert_size = ((self.cache[offset+14] & 0x0f) << 8) + self.cache[offset+13]
+        self.ann_field(offset+12, offset+14, 'Physical size: %dx%dmm' % (horiz_size, vert_size))
+
+        horiz_border = self.cache[offset+15]
+        if horiz_border:
+            self.ann_field(offset+15, offset+15, 'Horizontal border: %d pixels' % horiz_border)
+        vert_border = self.cache[offset+16]
+        if vert_border:
+            self.ann_field(offset+16, offset+16, 'Vertical border: %d lines' % vert_border)
+
+        features = 'Flags: '
+        if self.cache[offset+17] & 0x80:
+            features += 'interlaced, '
+        stereo = (self.cache[offset+17] & 0x60) >> 5
+        if stereo:
+            if self.cache[offset+17] & 0x01:
+                features += '2-way interleaved stereo ('
+                features += ['right image on even lines',
+                             'left image on even lines',
+                             'side-by-side'][stereo-1]
+                features += '), '
+            else:
+                features += 'field sequential stereo ('
+                features += ['right image on sync=1', 'left image on sync=1',
+                             '4-way interleaved'][stereo-1]
+                features += '), '
+        sync = (self.cache[offset+17] & 0x18) >> 3
+        sync2 = (self.cache[offset+17] & 0x06) >> 1
+        posneg = ['negative', 'positive']
+        features += 'sync type '
+        if sync == 0x00:
+            features += 'analog composite (serrate on RGB)'
+        elif sync == 0x01:
+            features += 'bipolar analog composite (serrate on RGB)'
+        elif sync == 0x02:
+            features += 'digital composite (serrate on composite polarity ' \
+                        + (posneg[sync2 & 0x01]) + ')'
+        elif sync == 0x03:
+            features += 'digital separate ('
+            features += 'Vsync polarity ' + (posneg[(sync2 & 0x02) >> 1])
+            features += ', Hsync polarity ' + (posneg[sync2 & 0x01])
+            features += ')'
+        features += ', '
+        self.ann_field(offset+17, offset+17, features[:-2])
+
+    def decode_descriptor(self, offset):
+        tag = self.cache[offset+3]
+        if tag == 0xff:
+            # Monitor serial number
+            text = bytes(self.cache[offset+5:][:13]).decode(encoding='cp437', errors='replace')
+            self.ann_field(offset, offset+17, 'Serial number: %s' % text.strip())
+        elif tag == 0xfe:
+            # Text
+            text = bytes(self.cache[offset+5:][:13]).decode(encoding='cp437', errors='replace')
+            self.ann_field(offset, offset+17, 'Info: %s' % text.strip())
+        elif tag == 0xfc:
+            # Monitor name
+            text = bytes(self.cache[offset+5:][:13]).decode(encoding='cp437', errors='replace')
+            self.ann_field(offset, offset+17, 'Model name: %s' % text.strip())
+        elif tag == 0xfd:
+            # Monitor range limits
+            self.put(self.sn[offset][0], self.sn[offset+17][1], self.out_ann,
+                     [ANN_SECTIONS, ['Monitor range limits']])
+            self.ann_field(offset+5, offset+5, 'Minimum vertical rate: %dHz' %
+                           self.cache[offset+5])
+            self.ann_field(offset+6, offset+6, 'Maximum vertical rate: %dHz' %
+                           self.cache[offset+6])
+            self.ann_field(offset+7, offset+7, 'Minimum horizontal rate: %dkHz' %
+                           self.cache[offset+7])
+            self.ann_field(offset+8, offset+8, 'Maximum horizontal rate: %dkHz' %
+                           self.cache[offset+8])
+            self.ann_field(offset+9, offset+9, 'Maximum pixel clock: %dMHz' %
+                           (self.cache[offset+9] * 10))
+            if self.cache[offset+10] == 0x02:
+                # Secondary GTF curve supported
+                self.ann_field(offset+10, offset+17, 'Secondary timing formula supported')
+        elif tag == 0xfb:
+            # Additional color point data
+            self.put(self.sn[offset][0], self.sn[offset+17][1], self.out_ann,
+                     [ANN_SECTIONS, ['Additional color point data']])
+        elif tag == 0xfa:
+            # Additional standard timing definitions
+            self.put(self.sn[offset][0], self.sn[offset+17][1], self.out_ann,
+                     [ANN_SECTIONS, ['Additional standard timing definitions']])
+        else:
+            self.put(self.sn[offset][0], self.sn[offset+17][1], self.out_ann,
+                     [ANN_SECTIONS, ['Unknown descriptor']])
+
+    def decode_descriptors(self, offset):
+        # 4 consecutive 18-byte descriptor blocks
+        for i in range(offset, 0, 18):
+            if self.cache[i] != 0 and self.cache[i+1] != 0:
+                self.decode_detailed_timing(i)
+            else:
+                if self.cache[i+2] == 0 or self.cache[i+4] == 0:
+                    self.decode_descriptor(i)
+
index 75a53eb499d0af0f39085712439152b91e549f7f..c25393f7371267d2953c7477d167437d47c46cc1 100644 (file)
@@ -20,7 +20,7 @@
 
 pkgdatadir = $(DECODERS_DIR)/i2c
 
-dist_pkgdata_DATA = __init__.py i2c.py
+dist_pkgdata_DATA = __init__.py pd.py
 
 CLEANFILES = *.pyc
 
index 14262d18e9177a1f8860801e2b9d2df3199019c8..6c7dafe7d75e7cf20f4c62c219db307aadb81a33 100644 (file)
@@ -79,5 +79,5 @@ For 'START', 'START REPEAT', 'STOP', 'ACK', and 'NACK' <data> is None.
 
 '''
 
-from .i2c import *
+from .pd import *
 
diff --git a/decoders/i2c/i2c.py b/decoders/i2c/i2c.py
deleted file mode 100644 (file)
index 53321eb..0000000
+++ /dev/null
@@ -1,240 +0,0 @@
-##
-## This file is part of the sigrok project.
-##
-## Copyright (C) 2010-2011 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
-## the Free Software Foundation; either version 2 of the License, or
-## (at your option) any later version.
-##
-## This program is distributed in the hope that it will be useful,
-## but WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-## GNU General Public License for more details.
-##
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, write to the Free Software
-## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
-##
-
-# I2C protocol decoder
-
-# TODO: Look into arbitration, collision detection, clock synchronisation, etc.
-# TODO: Handle clock stretching.
-# TODO: Handle combined messages / repeated START.
-# TODO: Implement support for 7bit and 10bit slave addresses.
-# TODO: Implement support for inverting SDA/SCL levels (0->1 and 1->0).
-# TODO: Implement support for detecting various bus errors.
-# TODO: I2C address of slaves.
-# TODO: Handle multiple different I2C devices on same bus
-#       -> we need to decode multiple protocols at the same time.
-
-import sigrokdecode as srd
-
-# Annotation feed formats
-ANN_SHIFTED = 0
-ANN_SHIFTED_SHORT = 1
-ANN_RAW = 2
-
-# Values are verbose and short annotation, respectively.
-proto = {
-    'START':           ['START',         'S'],
-    'START REPEAT':    ['START REPEAT',  'Sr'],
-    'STOP':            ['STOP',          'P'],
-    'ACK':             ['ACK',           'A'],
-    'NACK':            ['NACK',          'N'],
-    'ADDRESS READ':    ['ADDRESS READ',  'AR'],
-    'ADDRESS WRITE':   ['ADDRESS WRITE', 'AW'],
-    'DATA READ':       ['DATA READ',     'DR'],
-    'DATA WRITE':      ['DATA WRITE',    'DW'],
-}
-
-class Decoder(srd.Decoder):
-    api_version = 1
-    id = 'i2c'
-    name = 'I2C'
-    longname = 'Inter-Integrated Circuit'
-    desc = 'Two-wire, multi-master, serial bus.'
-    license = 'gplv2+'
-    inputs = ['logic']
-    outputs = ['i2c']
-    probes = [
-        {'id': 'scl', 'name': 'SCL', 'desc': 'Serial clock line'},
-        {'id': 'sda', 'name': 'SDA', 'desc': 'Serial data line'},
-    ]
-    optional_probes = []
-    options = {
-        'addressing': ['Slave addressing (in bits)', 7], # 7 or 10
-    }
-    annotations = [
-        # ANN_SHIFTED
-        ['7-bit shifted hex',
-         'Read/write bit shifted out from the 8-bit I2C slave address'],
-        # ANN_SHIFTED_SHORT
-        ['7-bit shifted hex (short)',
-         'Read/write bit shifted out from the 8-bit I2C slave address'],
-        # ANN_RAW
-        ['Raw hex', 'Unaltered raw data'],
-    ]
-
-    def __init__(self, **kwargs):
-        self.startsample = -1
-        self.samplenum = None
-        self.bitcount = 0
-        self.databyte = 0
-        self.wr = -1
-        self.is_repeat_start = 0
-        self.state = 'FIND START'
-        self.oldscl = None
-        self.oldsda = None
-        self.oldpins = None
-
-    def start(self, metadata):
-        self.out_proto = self.add(srd.OUTPUT_PROTO, 'i2c')
-        self.out_ann = self.add(srd.OUTPUT_ANN, 'i2c')
-
-    def report(self):
-        pass
-
-    def is_start_condition(self, scl, sda):
-        # START condition (S): SDA = falling, SCL = high
-        if (self.oldsda == 1 and sda == 0) and scl == 1:
-            return True
-        return False
-
-    def is_data_bit(self, scl, sda):
-        # Data sampling of receiver: SCL = rising
-        if self.oldscl == 0 and scl == 1:
-            return True
-        return False
-
-    def is_stop_condition(self, scl, sda):
-        # STOP condition (P): SDA = rising, SCL = high
-        if (self.oldsda == 0 and sda == 1) and scl == 1:
-            return True
-        return False
-
-    def found_start(self, scl, sda):
-        self.startsample = self.samplenum
-
-        cmd = 'START REPEAT' if (self.is_repeat_start == 1) else 'START'
-        self.put(self.out_proto, [cmd, None])
-        self.put(self.out_ann, [ANN_SHIFTED, [proto[cmd][0]]])
-        self.put(self.out_ann, [ANN_SHIFTED_SHORT, [proto[cmd][1]]])
-
-        self.state = 'FIND ADDRESS'
-        self.bitcount = self.databyte = 0
-        self.is_repeat_start = 1
-        self.wr = -1
-
-    # Gather 8 bits of data plus the ACK/NACK bit.
-    def found_address_or_data(self, scl, sda):
-        # Address and data are transmitted MSB-first.
-        self.databyte <<= 1
-        self.databyte |= sda
-
-        if self.bitcount == 0:
-            self.startsample = self.samplenum
-
-        # Return if we haven't collected all 8 + 1 bits, yet.
-        self.bitcount += 1
-        if self.bitcount != 8:
-            return
-
-        # We triggered on the ACK/NACK bit, but won't report that until later.
-        self.startsample -= 1
-
-        # Send raw output annotation before we start shifting out
-        # read/write and ACK/NACK bits.
-        self.put(self.out_ann, [ANN_RAW, ['0x%.2x' % self.databyte]])
-
-        if self.state == 'FIND ADDRESS':
-            # The READ/WRITE bit is only in address bytes, not data bytes.
-            self.wr = 0 if (self.databyte & 1) else 1
-            d = self.databyte >> 1
-        elif self.state == 'FIND DATA':
-            d = self.databyte
-
-        if self.state == 'FIND ADDRESS' and self.wr == 1:
-            cmd = 'ADDRESS WRITE'
-        elif self.state == 'FIND ADDRESS' and self.wr == 0:
-            cmd = 'ADDRESS READ'
-        elif self.state == 'FIND DATA' and self.wr == 1:
-            cmd = 'DATA WRITE'
-        elif self.state == 'FIND DATA' and self.wr == 0:
-            cmd = 'DATA READ'
-
-        self.put(self.out_proto, [cmd, d])
-        self.put(self.out_ann, [ANN_SHIFTED, [proto[cmd][0], '0x%02x' % d]])
-        self.put(self.out_ann, [ANN_SHIFTED_SHORT, [proto[cmd][1], '0x%02x' % d]])
-
-        # Done with this packet.
-        self.startsample = -1
-        self.bitcount = self.databyte = 0
-        self.state = 'FIND ACK'
-
-    def get_ack(self, scl, sda):
-        self.startsample = self.samplenum
-        ack_bit = 'NACK' if (sda == 1) else 'ACK'
-        self.put(self.out_proto, [ack_bit, None])
-        self.put(self.out_ann, [ANN_SHIFTED, [proto[ack_bit][0]]])
-        self.put(self.out_ann, [ANN_SHIFTED_SHORT, [proto[ack_bit][1]]])
-        # There could be multiple data bytes in a row, so either find
-        # another data byte or a STOP condition next.
-        self.state = 'FIND DATA'
-
-    def found_stop(self, scl, sda):
-        self.startsample = self.samplenum
-        self.put(self.out_proto, ['STOP', None])
-        self.put(self.out_ann, [ANN_SHIFTED, [proto['STOP'][0]]])
-        self.put(self.out_ann, [ANN_SHIFTED_SHORT, [proto['STOP'][1]]])
-
-        self.state = 'FIND START'
-        self.is_repeat_start = 0
-        self.wr = -1
-
-    def put(self, output_id, data):
-        # Inject sample range into the call up to sigrok.
-        super(Decoder, self).put(self.startsample, self.samplenum, output_id, data)
-
-    def decode(self, ss, es, data):
-        for (self.samplenum, pins) in data:
-
-            # Ignore identical samples early on (for performance reasons).
-            if self.oldpins == pins:
-                continue
-            self.oldpins, (scl, sda) = pins, pins
-
-            # First sample: Save SCL/SDA value.
-            if self.oldscl == None:
-                self.oldscl = scl
-                self.oldsda = sda
-                continue
-
-            # TODO: Wait until the bus is idle (SDA = SCL = 1) first?
-
-            # State machine.
-            if self.state == 'FIND START':
-                if self.is_start_condition(scl, sda):
-                    self.found_start(scl, sda)
-            elif self.state == 'FIND ADDRESS':
-                if self.is_data_bit(scl, sda):
-                    self.found_address_or_data(scl, sda)
-            elif self.state == 'FIND DATA':
-                if self.is_data_bit(scl, sda):
-                    self.found_address_or_data(scl, sda)
-                elif self.is_start_condition(scl, sda):
-                    self.found_start(scl, sda)
-                elif self.is_stop_condition(scl, sda):
-                    self.found_stop(scl, sda)
-            elif self.state == 'FIND ACK':
-                if self.is_data_bit(scl, sda):
-                    self.get_ack(scl, sda)
-            else:
-                raise Exception('Invalid state %d' % self.STATE)
-
-            # Save current SDA/SCL values for the next round.
-            self.oldscl = scl
-            self.oldsda = sda
-
diff --git a/decoders/i2c/pd.py b/decoders/i2c/pd.py
new file mode 100644 (file)
index 0000000..53321eb
--- /dev/null
@@ -0,0 +1,240 @@
+##
+## This file is part of the sigrok project.
+##
+## Copyright (C) 2010-2011 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
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+##
+
+# I2C protocol decoder
+
+# TODO: Look into arbitration, collision detection, clock synchronisation, etc.
+# TODO: Handle clock stretching.
+# TODO: Handle combined messages / repeated START.
+# TODO: Implement support for 7bit and 10bit slave addresses.
+# TODO: Implement support for inverting SDA/SCL levels (0->1 and 1->0).
+# TODO: Implement support for detecting various bus errors.
+# TODO: I2C address of slaves.
+# TODO: Handle multiple different I2C devices on same bus
+#       -> we need to decode multiple protocols at the same time.
+
+import sigrokdecode as srd
+
+# Annotation feed formats
+ANN_SHIFTED = 0
+ANN_SHIFTED_SHORT = 1
+ANN_RAW = 2
+
+# Values are verbose and short annotation, respectively.
+proto = {
+    'START':           ['START',         'S'],
+    'START REPEAT':    ['START REPEAT',  'Sr'],
+    'STOP':            ['STOP',          'P'],
+    'ACK':             ['ACK',           'A'],
+    'NACK':            ['NACK',          'N'],
+    'ADDRESS READ':    ['ADDRESS READ',  'AR'],
+    'ADDRESS WRITE':   ['ADDRESS WRITE', 'AW'],
+    'DATA READ':       ['DATA READ',     'DR'],
+    'DATA WRITE':      ['DATA WRITE',    'DW'],
+}
+
+class Decoder(srd.Decoder):
+    api_version = 1
+    id = 'i2c'
+    name = 'I2C'
+    longname = 'Inter-Integrated Circuit'
+    desc = 'Two-wire, multi-master, serial bus.'
+    license = 'gplv2+'
+    inputs = ['logic']
+    outputs = ['i2c']
+    probes = [
+        {'id': 'scl', 'name': 'SCL', 'desc': 'Serial clock line'},
+        {'id': 'sda', 'name': 'SDA', 'desc': 'Serial data line'},
+    ]
+    optional_probes = []
+    options = {
+        'addressing': ['Slave addressing (in bits)', 7], # 7 or 10
+    }
+    annotations = [
+        # ANN_SHIFTED
+        ['7-bit shifted hex',
+         'Read/write bit shifted out from the 8-bit I2C slave address'],
+        # ANN_SHIFTED_SHORT
+        ['7-bit shifted hex (short)',
+         'Read/write bit shifted out from the 8-bit I2C slave address'],
+        # ANN_RAW
+        ['Raw hex', 'Unaltered raw data'],
+    ]
+
+    def __init__(self, **kwargs):
+        self.startsample = -1
+        self.samplenum = None
+        self.bitcount = 0
+        self.databyte = 0
+        self.wr = -1
+        self.is_repeat_start = 0
+        self.state = 'FIND START'
+        self.oldscl = None
+        self.oldsda = None
+        self.oldpins = None
+
+    def start(self, metadata):
+        self.out_proto = self.add(srd.OUTPUT_PROTO, 'i2c')
+        self.out_ann = self.add(srd.OUTPUT_ANN, 'i2c')
+
+    def report(self):
+        pass
+
+    def is_start_condition(self, scl, sda):
+        # START condition (S): SDA = falling, SCL = high
+        if (self.oldsda == 1 and sda == 0) and scl == 1:
+            return True
+        return False
+
+    def is_data_bit(self, scl, sda):
+        # Data sampling of receiver: SCL = rising
+        if self.oldscl == 0 and scl == 1:
+            return True
+        return False
+
+    def is_stop_condition(self, scl, sda):
+        # STOP condition (P): SDA = rising, SCL = high
+        if (self.oldsda == 0 and sda == 1) and scl == 1:
+            return True
+        return False
+
+    def found_start(self, scl, sda):
+        self.startsample = self.samplenum
+
+        cmd = 'START REPEAT' if (self.is_repeat_start == 1) else 'START'
+        self.put(self.out_proto, [cmd, None])
+        self.put(self.out_ann, [ANN_SHIFTED, [proto[cmd][0]]])
+        self.put(self.out_ann, [ANN_SHIFTED_SHORT, [proto[cmd][1]]])
+
+        self.state = 'FIND ADDRESS'
+        self.bitcount = self.databyte = 0
+        self.is_repeat_start = 1
+        self.wr = -1
+
+    # Gather 8 bits of data plus the ACK/NACK bit.
+    def found_address_or_data(self, scl, sda):
+        # Address and data are transmitted MSB-first.
+        self.databyte <<= 1
+        self.databyte |= sda
+
+        if self.bitcount == 0:
+            self.startsample = self.samplenum
+
+        # Return if we haven't collected all 8 + 1 bits, yet.
+        self.bitcount += 1
+        if self.bitcount != 8:
+            return
+
+        # We triggered on the ACK/NACK bit, but won't report that until later.
+        self.startsample -= 1
+
+        # Send raw output annotation before we start shifting out
+        # read/write and ACK/NACK bits.
+        self.put(self.out_ann, [ANN_RAW, ['0x%.2x' % self.databyte]])
+
+        if self.state == 'FIND ADDRESS':
+            # The READ/WRITE bit is only in address bytes, not data bytes.
+            self.wr = 0 if (self.databyte & 1) else 1
+            d = self.databyte >> 1
+        elif self.state == 'FIND DATA':
+            d = self.databyte
+
+        if self.state == 'FIND ADDRESS' and self.wr == 1:
+            cmd = 'ADDRESS WRITE'
+        elif self.state == 'FIND ADDRESS' and self.wr == 0:
+            cmd = 'ADDRESS READ'
+        elif self.state == 'FIND DATA' and self.wr == 1:
+            cmd = 'DATA WRITE'
+        elif self.state == 'FIND DATA' and self.wr == 0:
+            cmd = 'DATA READ'
+
+        self.put(self.out_proto, [cmd, d])
+        self.put(self.out_ann, [ANN_SHIFTED, [proto[cmd][0], '0x%02x' % d]])
+        self.put(self.out_ann, [ANN_SHIFTED_SHORT, [proto[cmd][1], '0x%02x' % d]])
+
+        # Done with this packet.
+        self.startsample = -1
+        self.bitcount = self.databyte = 0
+        self.state = 'FIND ACK'
+
+    def get_ack(self, scl, sda):
+        self.startsample = self.samplenum
+        ack_bit = 'NACK' if (sda == 1) else 'ACK'
+        self.put(self.out_proto, [ack_bit, None])
+        self.put(self.out_ann, [ANN_SHIFTED, [proto[ack_bit][0]]])
+        self.put(self.out_ann, [ANN_SHIFTED_SHORT, [proto[ack_bit][1]]])
+        # There could be multiple data bytes in a row, so either find
+        # another data byte or a STOP condition next.
+        self.state = 'FIND DATA'
+
+    def found_stop(self, scl, sda):
+        self.startsample = self.samplenum
+        self.put(self.out_proto, ['STOP', None])
+        self.put(self.out_ann, [ANN_SHIFTED, [proto['STOP'][0]]])
+        self.put(self.out_ann, [ANN_SHIFTED_SHORT, [proto['STOP'][1]]])
+
+        self.state = 'FIND START'
+        self.is_repeat_start = 0
+        self.wr = -1
+
+    def put(self, output_id, data):
+        # Inject sample range into the call up to sigrok.
+        super(Decoder, self).put(self.startsample, self.samplenum, output_id, data)
+
+    def decode(self, ss, es, data):
+        for (self.samplenum, pins) in data:
+
+            # Ignore identical samples early on (for performance reasons).
+            if self.oldpins == pins:
+                continue
+            self.oldpins, (scl, sda) = pins, pins
+
+            # First sample: Save SCL/SDA value.
+            if self.oldscl == None:
+                self.oldscl = scl
+                self.oldsda = sda
+                continue
+
+            # TODO: Wait until the bus is idle (SDA = SCL = 1) first?
+
+            # State machine.
+            if self.state == 'FIND START':
+                if self.is_start_condition(scl, sda):
+                    self.found_start(scl, sda)
+            elif self.state == 'FIND ADDRESS':
+                if self.is_data_bit(scl, sda):
+                    self.found_address_or_data(scl, sda)
+            elif self.state == 'FIND DATA':
+                if self.is_data_bit(scl, sda):
+                    self.found_address_or_data(scl, sda)
+                elif self.is_start_condition(scl, sda):
+                    self.found_start(scl, sda)
+                elif self.is_stop_condition(scl, sda):
+                    self.found_stop(scl, sda)
+            elif self.state == 'FIND ACK':
+                if self.is_data_bit(scl, sda):
+                    self.get_ack(scl, sda)
+            else:
+                raise Exception('Invalid state %d' % self.STATE)
+
+            # Save current SDA/SCL values for the next round.
+            self.oldscl = scl
+            self.oldsda = sda
+
index d305394ce93eddf413513f0b0cdf591d7b8dcaf4..bc45d02b7fc6fd4c38825c82c2ba691ff733e257 100644 (file)
@@ -20,7 +20,7 @@
 
 pkgdatadir = $(DECODERS_DIR)/i2cdemux
 
-dist_pkgdata_DATA = __init__.py i2cdemux.py
+dist_pkgdata_DATA = __init__.py pd.py
 
 CLEANFILES = *.pyc
 
index 445a88e501fa2183328934ab2703f86e6a8a8643..1e5afbd11b4c88fb7b6aa5f376267bf72b5c8051 100644 (file)
@@ -25,5 +25,5 @@ Takes an I2C stream as input and outputs multiple I2C streams, each stream
 containing only I2C packets for one specific I2C slave.
 '''
 
-from .i2cdemux import *
+from .pd import *
 
diff --git a/decoders/i2cdemux/i2cdemux.py b/decoders/i2cdemux/i2cdemux.py
deleted file mode 100644 (file)
index bb47f23..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-##
-## This file is part of the sigrok project.
-##
-## 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
-## the Free Software Foundation; either version 2 of the License, or
-## (at your option) any later version.
-##
-## This program is distributed in the hope that it will be useful,
-## but WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-## GNU General Public License for more details.
-##
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, write to the Free Software
-## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
-##
-
-# Generic I2C demultiplexing protocol decoder
-
-import sigrokdecode as srd
-
-class Decoder(srd.Decoder):
-    api_version = 1
-    id = 'i2cdemux'
-    name = 'I2C demux'
-    longname = 'I2C demultiplexer'
-    desc = 'Demux I2C packets into per-slave-address streams.'
-    license = 'gplv2+'
-    inputs = ['i2c']
-    outputs = [] # TODO: Only known at run-time.
-    probes = []
-    optional_probes = []
-    options = {}
-    annotations = []
-
-    def __init__(self, **kwargs):
-        self.packets = [] # Local cache of I2C packets
-        self.slaves = [] # List of known slave addresses
-        self.stream = -1 # Current output stream
-        self.streamcount = 0 # Number of created output streams
-
-    def start(self, metadata):
-        self.out_proto = []
-
-    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.
-    # We use this slave address to figure out which output stream should
-    # get the whole chunk of packets (from START to STOP).
-    def decode(self, ss, es, data):
-
-        cmd, databyte = data
-
-        # Add the I2C packet to our local cache.
-        self.packets.append([ss, es, data])
-
-        if cmd in ('ADDRESS READ', 'ADDRESS WRITE'):
-            if databyte in self.slaves:
-                self.stream = self.slaves.index(databyte)
-                return
-
-            # We're never seen this slave, add a new stream.
-            self.slaves.append(databyte)
-            self.out_proto.append(self.add(srd.OUTPUT_PROTO,
-                                  'i2c-%s' % hex(databyte)))
-            self.stream = self.streamcount
-            self.streamcount += 1
-        elif cmd == 'STOP':
-            if self.stream == -1:
-                raise Exception('Invalid stream!') # FIXME?
-
-            # Send the whole chunk of I2C packets to the correct stream.
-            for p in self.packets:
-                self.put(p[0], p[1], self.out_proto[self.stream], p[2])
-
-            self.packets = []
-            self.stream = -1
-        else:
-            pass # Do nothing, only add the I2C packet to our cache.
-
diff --git a/decoders/i2cdemux/pd.py b/decoders/i2cdemux/pd.py
new file mode 100644 (file)
index 0000000..bb47f23
--- /dev/null
@@ -0,0 +1,87 @@
+##
+## This file is part of the sigrok project.
+##
+## 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
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+##
+
+# Generic I2C demultiplexing protocol decoder
+
+import sigrokdecode as srd
+
+class Decoder(srd.Decoder):
+    api_version = 1
+    id = 'i2cdemux'
+    name = 'I2C demux'
+    longname = 'I2C demultiplexer'
+    desc = 'Demux I2C packets into per-slave-address streams.'
+    license = 'gplv2+'
+    inputs = ['i2c']
+    outputs = [] # TODO: Only known at run-time.
+    probes = []
+    optional_probes = []
+    options = {}
+    annotations = []
+
+    def __init__(self, **kwargs):
+        self.packets = [] # Local cache of I2C packets
+        self.slaves = [] # List of known slave addresses
+        self.stream = -1 # Current output stream
+        self.streamcount = 0 # Number of created output streams
+
+    def start(self, metadata):
+        self.out_proto = []
+
+    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.
+    # We use this slave address to figure out which output stream should
+    # get the whole chunk of packets (from START to STOP).
+    def decode(self, ss, es, data):
+
+        cmd, databyte = data
+
+        # Add the I2C packet to our local cache.
+        self.packets.append([ss, es, data])
+
+        if cmd in ('ADDRESS READ', 'ADDRESS WRITE'):
+            if databyte in self.slaves:
+                self.stream = self.slaves.index(databyte)
+                return
+
+            # We're never seen this slave, add a new stream.
+            self.slaves.append(databyte)
+            self.out_proto.append(self.add(srd.OUTPUT_PROTO,
+                                  'i2c-%s' % hex(databyte)))
+            self.stream = self.streamcount
+            self.streamcount += 1
+        elif cmd == 'STOP':
+            if self.stream == -1:
+                raise Exception('Invalid stream!') # FIXME?
+
+            # Send the whole chunk of I2C packets to the correct stream.
+            for p in self.packets:
+                self.put(p[0], p[1], self.out_proto[self.stream], p[2])
+
+            self.packets = []
+            self.stream = -1
+        else:
+            pass # Do nothing, only add the I2C packet to our cache.
+
index 5b90489a08a93f7f9eb822c46e088b1d0d72b618..ff7abc4ac5cb7e832e24c9b5d1067f79f993aa79 100644 (file)
@@ -19,7 +19,7 @@
 
 pkgdatadir = $(DECODERS_DIR)/i2cfilter
 
-dist_pkgdata_DATA = __init__.py i2cfilter.py
+dist_pkgdata_DATA = __init__.py pd.py
 
 CLEANFILES = *.pyc
 
index 6443f5b620d61093867dc80b631ca69775be51cc..9a0b256756941c91d62427cfd8a27ffcbbf59505 100644 (file)
@@ -34,5 +34,5 @@ Both of these are optional; if no options are specified the entire payload
 of the I2C session will be output.
 '''
 
-from .i2cfilter import *
+from .pd import *
 
diff --git a/decoders/i2cfilter/i2cfilter.py b/decoders/i2cfilter/i2cfilter.py
deleted file mode 100644 (file)
index 9c9c43a..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-##
-## 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
-## the Free Software Foundation; either version 3 of the License, or
-## (at your option) any later version.
-##
-## This program is distributed in the hope that it will be useful,
-## but WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-## GNU General Public License for more details.
-##
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, see <http://www.gnu.org/licenses/>.
-##
-
-# Generic I2C filtering protocol decoder
-
-# TODO: Support for filtering out multiple slave/direction pairs?
-
-import sigrokdecode as srd
-
-class Decoder(srd.Decoder):
-    api_version = 1
-    id = 'i2cfilter'
-    name = 'I2C filter'
-    longname = 'I2C filter'
-    desc = 'Filter out addresses/directions in an I2C stream.'
-    license = 'gplv3+'
-    inputs = ['i2c']
-    outputs = ['i2c']
-    probes = []
-    optional_probes = []
-    options = {
-        'address': ['Address to filter out of the I2C stream', 0],
-        '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, '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):
-
-        cmd, databyte = data
-
-        # Add the I2C packet to our local cache.
-        self.packets.append([ss, es, data])
-
-        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
-
-            # 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
-
-            # 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:
-            pass # Do nothing, only add the I2C packet to our cache.
-
diff --git a/decoders/i2cfilter/pd.py b/decoders/i2cfilter/pd.py
new file mode 100644 (file)
index 0000000..9c9c43a
--- /dev/null
@@ -0,0 +1,99 @@
+##
+## 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
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, see <http://www.gnu.org/licenses/>.
+##
+
+# Generic I2C filtering protocol decoder
+
+# TODO: Support for filtering out multiple slave/direction pairs?
+
+import sigrokdecode as srd
+
+class Decoder(srd.Decoder):
+    api_version = 1
+    id = 'i2cfilter'
+    name = 'I2C filter'
+    longname = 'I2C filter'
+    desc = 'Filter out addresses/directions in an I2C stream.'
+    license = 'gplv3+'
+    inputs = ['i2c']
+    outputs = ['i2c']
+    probes = []
+    optional_probes = []
+    options = {
+        'address': ['Address to filter out of the I2C stream', 0],
+        '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, '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):
+
+        cmd, databyte = data
+
+        # Add the I2C packet to our local cache.
+        self.packets.append([ss, es, data])
+
+        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
+
+            # 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
+
+            # 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:
+            pass # Do nothing, only add the I2C packet to our cache.
+
index ff669023fe7ce7d9c90d1093150b3bd4d4e1a0ab..1fcafcecef7d7307fdee2dbcacf3cd7a948d3341 100644 (file)
@@ -20,7 +20,7 @@
 
 pkgdatadir = $(DECODERS_DIR)/i2s
 
-dist_pkgdata_DATA = __init__.py i2s.py
+dist_pkgdata_DATA = __init__.py pd.py
 
 CLEANFILES = *.pyc
 
index 81b785baca0192f94ef4768f5af1a3144072fe6d..f48e94fce91b372b249ecfa56d88965ca2963d9f 100644 (file)
@@ -26,5 +26,5 @@ http://www.nxp.com/acrobat_download/various/I2SBUS.pdf
 http://en.wikipedia.org/wiki/I2s
 '''
 
-from .i2s import *
+from .pd import *
 
diff --git a/decoders/i2s/i2s.py b/decoders/i2s/i2s.py
deleted file mode 100644 (file)
index b921011..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-##
-## This file is part of the sigrok project.
-##
-## Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
-##
-## 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
-## the Free Software Foundation; either version 2 of the License, or
-## (at your option) any later version.
-##
-## This program is distributed in the hope that it will be useful,
-## but WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-## GNU General Public License for more details.
-##
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, write to the Free Software
-## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
-##
-
-# I2S protocol decoder
-
-import sigrokdecode as srd
-
-# Annotation formats
-ANN_HEX = 0
-
-class Decoder(srd.Decoder):
-    api_version = 1
-    id = 'i2s'
-    name = 'I2S'
-    longname = 'Integrated Interchip Sound'
-    desc = 'Serial bus for connecting digital audio devices.'
-    license = 'gplv2+'
-    inputs = ['logic']
-    outputs = ['i2s']
-    probes = [
-        {'id': 'sck', 'name': 'SCK', 'desc': 'Bit clock line'},
-        {'id': 'ws', 'name': 'WS', 'desc': 'Word select line'},
-        {'id': 'sd', 'name': 'SD', 'desc': 'Serial data line'},
-    ]
-    optional_probes = []
-    options = {}
-    annotations = [
-        ['Hex', 'Annotations in hex format'],
-    ]
-
-    def __init__(self, **kwargs):
-        self.oldsck = 1
-        self.oldws = 1
-        self.bitcount = 0
-        self.data = 0
-        self.samplesreceived = 0
-        self.first_sample = None
-        self.start_sample = None
-        self.samplenum = -1
-        self.wordlength = -1
-
-    def start(self, metadata):
-        self.samplerate = metadata['samplerate']
-        self.out_proto = self.add(srd.OUTPUT_PROTO, 'i2s')
-        self.out_ann = self.add(srd.OUTPUT_ANN, 'i2s')
-
-    def report(self):
-
-        # Calculate the sample rate.
-        samplerate = '?'
-        if self.start_sample != None and \
-            self.first_sample != None and \
-            self.start_sample > self.first_sample:
-            samplerate = '%d' % (self.samplesreceived *
-                self.samplerate / (self.start_sample -
-                self.first_sample))
-
-        return 'I2S: %d %d-bit samples received at %sHz' % \
-            (self.samplesreceived, self.wordlength, samplerate)
-
-    def decode(self, ss, es, data):
-        for samplenum, (sck, ws, sd) in data:
-
-            # Ignore sample if the bit clock hasn't changed.
-            if sck == self.oldsck:
-                continue
-
-            self.oldsck = sck
-            if sck == 0:   # Ignore the falling clock edge.
-                continue
-
-            self.data = (self.data << 1) | sd
-            self.bitcount += 1
-
-            # This was not the LSB unless WS has flipped.
-            if ws == self.oldws:
-                continue
-
-            # Only submit the sample, if we received the beginning of it.
-            if self.start_sample != None:
-                self.samplesreceived += 1
-                self.put(self.start_sample, self.samplenum, self.out_proto,
-                         ['data', self.data])
-                self.put(self.start_sample, self.samplenum, self.out_ann,
-                         [ANN_HEX, ['%s: 0x%08x' % ('L' if self.oldws else 'R',
-                         self.data)]])
-
-                # Check that the data word was the correct length.
-                if self.wordlength != -1 and self.wordlength != self.bitcount:
-                    self.put(self.start_sample, self.samplenum, self.out_ann,
-                        [ANN_HEX, ['WARNING: Received a %d-bit word, when a '
-                        '%d-bit word was expected' % (self.bitcount,
-                        self.wordlength)]])
-
-                self.wordlength = self.bitcount
-
-            # Reset decoder state.
-            self.data = 0
-            self.bitcount = 0
-            self.start_sample = self.samplenum
-
-            # Save the first sample position.
-            if self.first_sample == None:
-                self.first_sample = self.samplenum
-
-            self.oldws = ws
-
diff --git a/decoders/i2s/pd.py b/decoders/i2s/pd.py
new file mode 100644 (file)
index 0000000..b921011
--- /dev/null
@@ -0,0 +1,124 @@
+##
+## This file is part of the sigrok project.
+##
+## Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
+##
+## 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
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+##
+
+# I2S protocol decoder
+
+import sigrokdecode as srd
+
+# Annotation formats
+ANN_HEX = 0
+
+class Decoder(srd.Decoder):
+    api_version = 1
+    id = 'i2s'
+    name = 'I2S'
+    longname = 'Integrated Interchip Sound'
+    desc = 'Serial bus for connecting digital audio devices.'
+    license = 'gplv2+'
+    inputs = ['logic']
+    outputs = ['i2s']
+    probes = [
+        {'id': 'sck', 'name': 'SCK', 'desc': 'Bit clock line'},
+        {'id': 'ws', 'name': 'WS', 'desc': 'Word select line'},
+        {'id': 'sd', 'name': 'SD', 'desc': 'Serial data line'},
+    ]
+    optional_probes = []
+    options = {}
+    annotations = [
+        ['Hex', 'Annotations in hex format'],
+    ]
+
+    def __init__(self, **kwargs):
+        self.oldsck = 1
+        self.oldws = 1
+        self.bitcount = 0
+        self.data = 0
+        self.samplesreceived = 0
+        self.first_sample = None
+        self.start_sample = None
+        self.samplenum = -1
+        self.wordlength = -1
+
+    def start(self, metadata):
+        self.samplerate = metadata['samplerate']
+        self.out_proto = self.add(srd.OUTPUT_PROTO, 'i2s')
+        self.out_ann = self.add(srd.OUTPUT_ANN, 'i2s')
+
+    def report(self):
+
+        # Calculate the sample rate.
+        samplerate = '?'
+        if self.start_sample != None and \
+            self.first_sample != None and \
+            self.start_sample > self.first_sample:
+            samplerate = '%d' % (self.samplesreceived *
+                self.samplerate / (self.start_sample -
+                self.first_sample))
+
+        return 'I2S: %d %d-bit samples received at %sHz' % \
+            (self.samplesreceived, self.wordlength, samplerate)
+
+    def decode(self, ss, es, data):
+        for samplenum, (sck, ws, sd) in data:
+
+            # Ignore sample if the bit clock hasn't changed.
+            if sck == self.oldsck:
+                continue
+
+            self.oldsck = sck
+            if sck == 0:   # Ignore the falling clock edge.
+                continue
+
+            self.data = (self.data << 1) | sd
+            self.bitcount += 1
+
+            # This was not the LSB unless WS has flipped.
+            if ws == self.oldws:
+                continue
+
+            # Only submit the sample, if we received the beginning of it.
+            if self.start_sample != None:
+                self.samplesreceived += 1
+                self.put(self.start_sample, self.samplenum, self.out_proto,
+                         ['data', self.data])
+                self.put(self.start_sample, self.samplenum, self.out_ann,
+                         [ANN_HEX, ['%s: 0x%08x' % ('L' if self.oldws else 'R',
+                         self.data)]])
+
+                # Check that the data word was the correct length.
+                if self.wordlength != -1 and self.wordlength != self.bitcount:
+                    self.put(self.start_sample, self.samplenum, self.out_ann,
+                        [ANN_HEX, ['WARNING: Received a %d-bit word, when a '
+                        '%d-bit word was expected' % (self.bitcount,
+                        self.wordlength)]])
+
+                self.wordlength = self.bitcount
+
+            # Reset decoder state.
+            self.data = 0
+            self.bitcount = 0
+            self.start_sample = self.samplenum
+
+            # Save the first sample position.
+            if self.first_sample == None:
+                self.first_sample = self.samplenum
+
+            self.oldws = ws
+
index ce6aedeff2ebfc1c788fcff8b298028c972314be..6d968420950a1ec9b168083817a176943de60a7b 100644 (file)
@@ -20,7 +20,7 @@
 
 pkgdatadir = $(DECODERS_DIR)/jtag
 
-dist_pkgdata_DATA = __init__.py jtag.py
+dist_pkgdata_DATA = __init__.py pd.py
 
 CLEANFILES = *.pyc
 
index 4a53502a48b794a0d9bf4f39f1eaec7c418a085e..4538e0e0f476b953932a467866e6523a4658de64 100644 (file)
@@ -52,5 +52,5 @@ https://en.wikipedia.org/wiki/Joint_Test_Action_Group
 http://focus.ti.com/lit/an/ssya002c/ssya002c.pdf
 '''
 
-from .jtag import *
+from .pd import *
 
diff --git a/decoders/jtag/jtag.py b/decoders/jtag/jtag.py
deleted file mode 100644 (file)
index 4e27ce8..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-##
-## This file is part of the sigrok project.
-##
-## 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
-## the Free Software Foundation; either version 2 of the License, or
-## (at your option) any later version.
-##
-## This program is distributed in the hope that it will be useful,
-## but WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-## GNU General Public License for more details.
-##
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, write to the Free Software
-## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
-##
-
-# JTAG protocol decoder
-
-import sigrokdecode as srd
-
-class Decoder(srd.Decoder):
-    api_version = 1
-    id = 'jtag'
-    name = 'JTAG'
-    longname = 'Joint Test Action Group (IEEE 1149.1)'
-    desc = 'Protocol for testing, debugging, and flashing ICs.'
-    license = 'gplv2+'
-    inputs = ['logic']
-    outputs = ['jtag']
-    probes = [
-        {'id': 'tdi',  'name': 'TDI',  'desc': 'Test data input'},
-        {'id': 'tdo',  'name': 'TDO',  'desc': 'Test data output'},
-        {'id': 'tck',  'name': 'TCK',  'desc': 'Test clock'},
-        {'id': 'tms',  'name': 'TMS',  'desc': 'Test mode select'},
-    ]
-    optional_probes = [
-        {'id': 'trst', 'name': 'TRST#', 'desc': 'Test reset'},
-        {'id': 'srst', 'name': 'SRST#', 'desc': 'System reset'},
-        {'id': 'rtck', 'name': 'RTCK',  'desc': 'Return clock signal'},
-    ]
-    options = {}
-    annotations = [
-        ['Text', 'Human-readable text'],
-    ]
-
-    def __init__(self, **kwargs):
-        # self.state = 'TEST-LOGIC-RESET'
-        self.state = 'RUN-TEST/IDLE'
-        self.oldstate = None
-        self.oldpins = (-1, -1, -1, -1)
-        self.oldtck = -1
-        self.bits_tdi = []
-        self.bits_tdo = []
-
-    def start(self, metadata):
-        self.out_proto = self.add(srd.OUTPUT_PROTO, 'jtag')
-        self.out_ann = self.add(srd.OUTPUT_ANN, 'jtag')
-
-    def report(self):
-        pass
-
-    def advance_state_machine(self, tms):
-        self.oldstate = self.state
-
-        # Intro "tree"
-        if self.state == 'TEST-LOGIC-RESET':
-            self.state = 'TEST-LOGIC-RESET' if (tms) else 'RUN-TEST/IDLE'
-        elif self.state == 'RUN-TEST/IDLE':
-            self.state = 'SELECT-DR-SCAN' if (tms) else 'RUN-TEST/IDLE'
-
-        # DR "tree"
-        elif self.state == 'SELECT-DR-SCAN':
-            self.state = 'SELECT-IR-SCAN' if (tms) else 'CAPTURE-DR'
-        elif self.state == 'CAPTURE-DR':
-            self.state = 'EXIT1-DR' if (tms) else 'SHIFT-DR'
-        elif self.state == 'SHIFT-DR':
-            self.state = 'EXIT1-DR' if (tms) else 'SHIFT-DR'
-        elif self.state == 'EXIT1-DR':
-            self.state = 'UPDATE-DR' if (tms) else 'PAUSE-DR'
-        elif self.state == 'PAUSE-DR':
-            self.state = 'EXIT2-DR' if (tms) else 'PAUSE-DR'
-        elif self.state == 'EXIT2-DR':
-            self.state = 'UPDATE-DR' if (tms) else 'SHIFT-DR'
-        elif self.state == 'UPDATE-DR':
-            self.state = 'SELECT-DR-SCAN' if (tms) else 'RUN-TEST/IDLE'
-
-        # IR "tree"
-        elif self.state == 'SELECT-IR-SCAN':
-            self.state = 'TEST-LOGIC-RESET' if (tms) else 'CAPTURE-IR'
-        elif self.state == 'CAPTURE-IR':
-            self.state = 'EXIT1-IR' if (tms) else 'SHIFT-IR'
-        elif self.state == 'SHIFT-IR':
-            self.state = 'EXIT1-IR' if (tms) else 'SHIFT-IR'
-        elif self.state == 'EXIT1-IR':
-            self.state = 'UPDATE-IR' if (tms) else 'PAUSE-IR'
-        elif self.state == 'PAUSE-IR':
-            self.state = 'EXIT2-IR' if (tms) else 'PAUSE-IR'
-        elif self.state == 'EXIT2-IR':
-            self.state = 'UPDATE-IR' if (tms) else 'SHIFT-IR'
-        elif self.state == 'UPDATE-IR':
-            self.state = 'SELECT-DR-SCAN' if (tms) else 'RUN-TEST/IDLE'
-
-        else:
-            raise Exception('Invalid state: %s' % self.state)
-
-    def handle_rising_tck_edge(self, tdi, tdo, tck, tms):
-        # Rising TCK edges always advance the state machine.
-        self.advance_state_machine(tms)
-
-        # Output the state we just switched to.
-        self.put(self.ss, self.es, self.out_ann,
-                 [0, ['New state: %s' % self.state]])
-        self.put(self.ss, self.es, self.out_proto,
-                 ['NEW STATE', self.state])
-
-        # If we went from SHIFT-IR to SHIFT-IR, or SHIFT-DR to SHIFT-DR,
-        # collect the current TDI/TDO values (upon rising TCK edge).
-        if self.state.startswith('SHIFT-') and self.oldstate == self.state:
-            self.bits_tdi.insert(0, tdi)
-            self.bits_tdo.insert(0, tdo)
-            # TODO: ANN/PROTO output.
-            # self.put(self.ss, self.es, self.out_ann,
-            #          [0, ['TDI add: ' + str(tdi)]])
-            # self.put(self.ss, self.es, self.out_ann,
-            #          [0, ['TDO add: ' + str(tdo)]])
-
-        # Output all TDI/TDO bits if we just switched from SHIFT-* to EXIT1-*.
-        if self.oldstate.startswith('SHIFT-') and \
-           self.state.startswith('EXIT1-'):
-
-            t = self.state[-2:] + ' TDI'
-            b = ''.join(map(str, self.bits_tdi))
-            h = ' (0x%x' % int('0b' + b, 2) + ')'
-            s = t + ': ' + b + h + ', ' + str(len(self.bits_tdi)) + ' bits'
-            self.put(self.ss, self.es, self.out_ann, [0, [s]])
-            self.put(self.ss, self.es, self.out_proto, [t, b])
-            self.bits_tdi = []
-
-            t = self.state[-2:] + ' TDO'
-            b = ''.join(map(str, self.bits_tdo))
-            h = ' (0x%x' % int('0b' + b, 2) + ')'
-            s = t + ': ' + b + h + ', ' + str(len(self.bits_tdo)) + ' bits'
-            self.put(self.ss, self.es, self.out_ann, [0, [s]])
-            self.put(self.ss, self.es, self.out_proto, [t, b])
-            self.bits_tdo = []
-
-    def decode(self, ss, es, data):
-        for (samplenum, pins) in data:
-
-            # If none of the pins changed, there's nothing to do.
-            if self.oldpins == pins:
-                continue
-
-            # Store current pin values for the next round.
-            self.oldpins = pins
-
-            # Get individual pin values into local variables.
-            # Unused probes will have a value of > 1.
-            (tdi, tdo, tck, tms, trst, srst, rtck) = pins
-
-            # We only care about TCK edges (either rising or falling).
-            if (self.oldtck == tck):
-                continue
-
-            # Store start/end sample for later usage.
-            self.ss, self.es = ss, es
-
-            # self.put(self.ss, self.es, self.out_ann,
-            #     [0, ['tdi:%s, tdo:%s, tck:%s, tms:%s' \
-            #          % (tdi, tdo, tck, tms)]])
-
-            if (self.oldtck == 0 and tck == 1):
-                self.handle_rising_tck_edge(tdi, tdo, tck, tms)
-
-            self.oldtck = tck
-
diff --git a/decoders/jtag/pd.py b/decoders/jtag/pd.py
new file mode 100644 (file)
index 0000000..4e27ce8
--- /dev/null
@@ -0,0 +1,180 @@
+##
+## This file is part of the sigrok project.
+##
+## 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
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+##
+
+# JTAG protocol decoder
+
+import sigrokdecode as srd
+
+class Decoder(srd.Decoder):
+    api_version = 1
+    id = 'jtag'
+    name = 'JTAG'
+    longname = 'Joint Test Action Group (IEEE 1149.1)'
+    desc = 'Protocol for testing, debugging, and flashing ICs.'
+    license = 'gplv2+'
+    inputs = ['logic']
+    outputs = ['jtag']
+    probes = [
+        {'id': 'tdi',  'name': 'TDI',  'desc': 'Test data input'},
+        {'id': 'tdo',  'name': 'TDO',  'desc': 'Test data output'},
+        {'id': 'tck',  'name': 'TCK',  'desc': 'Test clock'},
+        {'id': 'tms',  'name': 'TMS',  'desc': 'Test mode select'},
+    ]
+    optional_probes = [
+        {'id': 'trst', 'name': 'TRST#', 'desc': 'Test reset'},
+        {'id': 'srst', 'name': 'SRST#', 'desc': 'System reset'},
+        {'id': 'rtck', 'name': 'RTCK',  'desc': 'Return clock signal'},
+    ]
+    options = {}
+    annotations = [
+        ['Text', 'Human-readable text'],
+    ]
+
+    def __init__(self, **kwargs):
+        # self.state = 'TEST-LOGIC-RESET'
+        self.state = 'RUN-TEST/IDLE'
+        self.oldstate = None
+        self.oldpins = (-1, -1, -1, -1)
+        self.oldtck = -1
+        self.bits_tdi = []
+        self.bits_tdo = []
+
+    def start(self, metadata):
+        self.out_proto = self.add(srd.OUTPUT_PROTO, 'jtag')
+        self.out_ann = self.add(srd.OUTPUT_ANN, 'jtag')
+
+    def report(self):
+        pass
+
+    def advance_state_machine(self, tms):
+        self.oldstate = self.state
+
+        # Intro "tree"
+        if self.state == 'TEST-LOGIC-RESET':
+            self.state = 'TEST-LOGIC-RESET' if (tms) else 'RUN-TEST/IDLE'
+        elif self.state == 'RUN-TEST/IDLE':
+            self.state = 'SELECT-DR-SCAN' if (tms) else 'RUN-TEST/IDLE'
+
+        # DR "tree"
+        elif self.state == 'SELECT-DR-SCAN':
+            self.state = 'SELECT-IR-SCAN' if (tms) else 'CAPTURE-DR'
+        elif self.state == 'CAPTURE-DR':
+            self.state = 'EXIT1-DR' if (tms) else 'SHIFT-DR'
+        elif self.state == 'SHIFT-DR':
+            self.state = 'EXIT1-DR' if (tms) else 'SHIFT-DR'
+        elif self.state == 'EXIT1-DR':
+            self.state = 'UPDATE-DR' if (tms) else 'PAUSE-DR'
+        elif self.state == 'PAUSE-DR':
+            self.state = 'EXIT2-DR' if (tms) else 'PAUSE-DR'
+        elif self.state == 'EXIT2-DR':
+            self.state = 'UPDATE-DR' if (tms) else 'SHIFT-DR'
+        elif self.state == 'UPDATE-DR':
+            self.state = 'SELECT-DR-SCAN' if (tms) else 'RUN-TEST/IDLE'
+
+        # IR "tree"
+        elif self.state == 'SELECT-IR-SCAN':
+            self.state = 'TEST-LOGIC-RESET' if (tms) else 'CAPTURE-IR'
+        elif self.state == 'CAPTURE-IR':
+            self.state = 'EXIT1-IR' if (tms) else 'SHIFT-IR'
+        elif self.state == 'SHIFT-IR':
+            self.state = 'EXIT1-IR' if (tms) else 'SHIFT-IR'
+        elif self.state == 'EXIT1-IR':
+            self.state = 'UPDATE-IR' if (tms) else 'PAUSE-IR'
+        elif self.state == 'PAUSE-IR':
+            self.state = 'EXIT2-IR' if (tms) else 'PAUSE-IR'
+        elif self.state == 'EXIT2-IR':
+            self.state = 'UPDATE-IR' if (tms) else 'SHIFT-IR'
+        elif self.state == 'UPDATE-IR':
+            self.state = 'SELECT-DR-SCAN' if (tms) else 'RUN-TEST/IDLE'
+
+        else:
+            raise Exception('Invalid state: %s' % self.state)
+
+    def handle_rising_tck_edge(self, tdi, tdo, tck, tms):
+        # Rising TCK edges always advance the state machine.
+        self.advance_state_machine(tms)
+
+        # Output the state we just switched to.
+        self.put(self.ss, self.es, self.out_ann,
+                 [0, ['New state: %s' % self.state]])
+        self.put(self.ss, self.es, self.out_proto,
+                 ['NEW STATE', self.state])
+
+        # If we went from SHIFT-IR to SHIFT-IR, or SHIFT-DR to SHIFT-DR,
+        # collect the current TDI/TDO values (upon rising TCK edge).
+        if self.state.startswith('SHIFT-') and self.oldstate == self.state:
+            self.bits_tdi.insert(0, tdi)
+            self.bits_tdo.insert(0, tdo)
+            # TODO: ANN/PROTO output.
+            # self.put(self.ss, self.es, self.out_ann,
+            #          [0, ['TDI add: ' + str(tdi)]])
+            # self.put(self.ss, self.es, self.out_ann,
+            #          [0, ['TDO add: ' + str(tdo)]])
+
+        # Output all TDI/TDO bits if we just switched from SHIFT-* to EXIT1-*.
+        if self.oldstate.startswith('SHIFT-') and \
+           self.state.startswith('EXIT1-'):
+
+            t = self.state[-2:] + ' TDI'
+            b = ''.join(map(str, self.bits_tdi))
+            h = ' (0x%x' % int('0b' + b, 2) + ')'
+            s = t + ': ' + b + h + ', ' + str(len(self.bits_tdi)) + ' bits'
+            self.put(self.ss, self.es, self.out_ann, [0, [s]])
+            self.put(self.ss, self.es, self.out_proto, [t, b])
+            self.bits_tdi = []
+
+            t = self.state[-2:] + ' TDO'
+            b = ''.join(map(str, self.bits_tdo))
+            h = ' (0x%x' % int('0b' + b, 2) + ')'
+            s = t + ': ' + b + h + ', ' + str(len(self.bits_tdo)) + ' bits'
+            self.put(self.ss, self.es, self.out_ann, [0, [s]])
+            self.put(self.ss, self.es, self.out_proto, [t, b])
+            self.bits_tdo = []
+
+    def decode(self, ss, es, data):
+        for (samplenum, pins) in data:
+
+            # If none of the pins changed, there's nothing to do.
+            if self.oldpins == pins:
+                continue
+
+            # Store current pin values for the next round.
+            self.oldpins = pins
+
+            # Get individual pin values into local variables.
+            # Unused probes will have a value of > 1.
+            (tdi, tdo, tck, tms, trst, srst, rtck) = pins
+
+            # We only care about TCK edges (either rising or falling).
+            if (self.oldtck == tck):
+                continue
+
+            # Store start/end sample for later usage.
+            self.ss, self.es = ss, es
+
+            # self.put(self.ss, self.es, self.out_ann,
+            #     [0, ['tdi:%s, tdo:%s, tck:%s, tms:%s' \
+            #          % (tdi, tdo, tck, tms)]])
+
+            if (self.oldtck == 0 and tck == 1):
+                self.handle_rising_tck_edge(tdi, tdo, tck, tms)
+
+            self.oldtck = tck
+
index 08d74d61d3ee9035bdbf9307cc46919edc1b8341..7cd39dadac54128f3693f7781481add5f9bef340 100644 (file)
@@ -20,7 +20,7 @@
 
 pkgdatadir = $(DECODERS_DIR)/jtag_stm32
 
-dist_pkgdata_DATA = __init__.py jtag_stm32.py
+dist_pkgdata_DATA = __init__.py pd.py
 
 CLEANFILES = *.pyc
 
index bc35c46c8522aac74e907bb359a95460d432b74a..12e667bfc8e5493eae803b8153d6a355330ba1c9 100644 (file)
@@ -28,5 +28,5 @@ https://en.wikipedia.org/wiki/STM32
 http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/REFERENCE_MANUAL/CD00171190.pdf (e.g. chapter 31.7: "JTAG debug port")
 '''
 
-from .jtag_stm32 import *
+from .pd import *
 
diff --git a/decoders/jtag_stm32/jtag_stm32.py b/decoders/jtag_stm32/jtag_stm32.py
deleted file mode 100644 (file)
index e30788c..0000000
+++ /dev/null
@@ -1,232 +0,0 @@
-##
-## This file is part of the sigrok project.
-##
-## 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
-## the Free Software Foundation; either version 2 of the License, or
-## (at your option) any later version.
-##
-## This program is distributed in the hope that it will be useful,
-## but WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-## GNU General Public License for more details.
-##
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, write to the Free Software
-## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
-##
-
-# ST STM32 JTAG protocol decoder
-
-import sigrokdecode as srd
-
-# JTAG debug port data registers (in IR[3:0]) and their sizes (in bits)
-# Note: The ARM DAP-DP is not IEEE 1149.1 (JTAG) compliant (as per ARM docs),
-#       as it does not implement the EXTEST, SAMPLE, and PRELOAD instructions.
-#       Instead, BYPASS is decoded for any of these instructions.
-ir = {
-    '1111': ['BYPASS', 1],  # Bypass register
-    '1110': ['IDCODE', 32], # ID code register
-    '1010': ['DPACC', 35],  # Debug port access register
-    '1011': ['APACC', 35],  # Access port access register
-    '1000': ['ABORT', 35],  # Abort register # TODO: 32 bits? Datasheet typo?
-}
-
-# ARM Cortex-M3 r1p1-01rel0 ID code
-cm3_idcode = 0x3ba00477
-
-# JTAG ID code in the STM32F10xxx BSC (boundary scan) TAP
-jtag_idcode = {
-    0x06412041: 'Low-density device, rev. A',
-    0x06410041: 'Medium-density device, rev. A',
-    0x16410041: 'Medium-density device, rev. B/Z/Y',
-    0x06414041: 'High-density device, rev. A/Z/Y',
-    0x06430041: 'XL-density device, rev. A',
-    0x06418041: 'Connectivity-line device, rev. A/Z',
-}
-
-# ACK[2:0] in the DPACC/APACC registers (unlisted values are reserved)
-ack_val = {
-    '001': 'WAIT',
-    '010': 'OK/FAULT',
-}
-
-# 32bit debug port registers (addressed via A[3:2])
-dp_reg = {
-    '00': 'Reserved', # Must be kept at reset value
-    '01': 'DP CTRL/STAT',
-    '10': 'DP SELECT',
-    '11': 'DP RDBUFF',
-}
-
-# APB-AP registers (each of them 32 bits wide)
-apb_ap_reg = {
-    0x00: ['CSW', 'Control/status word'],
-    0x04: ['TAR', 'Transfer address'],
-    # 0x08: Reserved SBZ
-    0x0c: ['DRW', 'Data read/write'],
-    0x10: ['BD0', 'Banked data 0'],
-    0x14: ['BD1', 'Banked data 1'],
-    0x18: ['BD2', 'Banked data 2'],
-    0x1c: ['BD3', 'Banked data 3'],
-    # 0x20-0xf4: Reserved SBZ
-    0x800000000: ['ROM', 'Debug ROM address'],
-    0xfc: ['IDR', 'Identification register'],
-}
-
-# TODO: All start/end sample values in self.put() calls are bogus.
-# TODO: Split off generic ARM/Cortex-M3 parts into another protocol decoder?
-
-# Bits[31:28]: Version (here: 0x3)
-#              JTAG-DP: 0x3, SW-DP: 0x2
-# Bits[27:12]: Part number (here: 0xba00)
-#              JTAG-DP: 0xba00, SW-DP: 0xba10
-# Bits[11:1]:  JEDEC (JEP-106) manufacturer ID (here: 0x23b)
-#              Bits[11:8]: Continuation code ('ARM Limited': 0x04)
-#              Bits[7:1]: Identity code ('ARM Limited': 0x3b)
-# Bits[0:0]:   Reserved (here: 0x1)
-def decode_device_id_code(bits):
-    id_hex = '0x%x' % int('0b' + bits, 2)
-    ver =    '0x%x' % int('0b' + bits[-32:-28], 2)
-    part =   '0x%x' % int('0b' + bits[-28:-12], 2)
-    manuf =  '0x%x' % int('0b' + bits[-12:-1], 2)
-    res =    '0x%x' % int('0b' + bits[-1], 2)
-    return (id_hex, ver, part, manuf, res)
-
-# DPACC is used to access debug port registers (CTRL/STAT, SELECT, RDBUFF).
-# APACC is used to access all Access Port (AHB-AP) registers.
-
-# APACC/DPACC, when transferring data IN:
-# Bits[34:3] = DATA[31:0]: 32bit data to transfer (write request)
-# Bits[2:1] = A[3:2]: 2-bit address (debug/access port register)
-# Bits[0:0] = RnW: Read request (1) or write request (0)
-def data_in(instruction, bits):
-    data, a, rnw = bits[:-3], bits[-3:-1], bits[-1]
-    data_hex = '0x%x' % int('0b' + data, 2)
-    r = 'Read request' if (rnw == '1') else 'Write request'
-    # reg = dp_reg[a] if (instruction == 'DPACC') else apb_ap_reg[a]
-    reg = dp_reg[a] if (instruction == 'DPACC') else a # TODO
-    return 'New transaction: DATA: %s, A: %s, RnW: %s' % (data_hex, reg, r)
-
-# APACC/DPACC, when transferring data OUT:
-# Bits[34:3] = DATA[31:0]: 32bit data which is read (read request)
-# Bits[2:0] = ACK[2:0]: 3-bit acknowledge
-def data_out(bits):
-    data, ack = bits[:-3], bits[-3:]
-    data_hex = '0x%x' % int('0b' + data, 2)
-    ack_meaning = ack_val.get(ack, 'Reserved')
-    return 'Previous transaction result: DATA: %s, ACK: %s' \
-           % (data_hex, ack_meaning)
-
-class Decoder(srd.Decoder):
-    api_version = 1
-    id = 'jtag_stm32'
-    name = 'JTAG / STM32'
-    longname = 'Joint Test Action Group / ST STM32'
-    desc = 'ST STM32-specific JTAG protocol.'
-    license = 'gplv2+'
-    inputs = ['jtag']
-    outputs = ['jtag_stm32']
-    probes = []
-    optional_probes = []
-    options = {}
-    annotations = [
-        ['Text', 'Human-readable text'],
-    ]
-
-    def __init__(self, **kwargs):
-        self.state = 'IDLE'
-        # self.state = 'BYPASS'
-
-    def start(self, metadata):
-        # self.out_proto = self.add(srd.OUTPUT_PROTO, 'jtag_stm32')
-        self.out_ann = self.add(srd.OUTPUT_ANN, 'jtag_stm32')
-
-    def report(self):
-        pass
-
-    def handle_reg_bypass(self, cmd, bits):
-        # TODO
-        self.put(self.ss, self.es, self.out_ann, [0, ['BYPASS: ' + bits]])
-
-    def handle_reg_idcode(self, cmd, bits):
-        # TODO
-        # IDCODE is a read-only register which is always accessible.
-        # IR == IDCODE: The device ID code is shifted out via DR next.
-        self.put(self.ss, self.es, self.out_ann,
-                 [0, ['IDCODE: %s (ver=%s, part=%s, manuf=%s, res=%s)' % \
-                 decode_device_id_code(bits)]])
-
-    def handle_reg_dpacc(self, cmd, bits):
-        # self.put(self.ss, self.es, self.out_ann,
-        #          [0, ['DPACC/%s: %s' % (cmd, bits)]])
-        s = data_in('DPACC', bits) if (cmd == 'DR TDI') else data_out(bits)
-        self.put(self.ss, self.es, self.out_ann, [0, [s]])
-
-    def handle_reg_apacc(self, cmd, bits):
-        # self.put(self.ss, self.es, self.out_ann,
-        #          [0, ['APACC/%s: %s' % (cmd, bits)]])
-        s = data_in('APACC', bits) if (cmd == 'DR TDI') else data_out(bits)
-        self.put(self.ss, self.es, self.out_ann, [0, [s]])
-
-    def handle_reg_abort(self, cmd, bits):
-        # Bits[31:1]: reserved. Bit[0]: DAPABORT.
-        a = '' if (bits[0] == '1') else 'No '
-        s = 'DAPABORT = %s: %sDAP abort generated' % (bits[0], a)
-        self.put(self.ss, self.es, self.out_ann, [0, [s]])
-
-        # Warn if DAPABORT[31:1] contains non-zero bits.
-        if (bits[:-1] != ('0' * 31)):
-            self.put(self.ss, self.es, self.out_ann,
-                     [0, ['WARNING: DAPABORT[31:1] reserved!']])
-
-    def handle_reg_unknown(self, cmd, bits):
-        self.put(self.ss, self.es, self.out_ann,
-                 [0, ['Unknown instruction: ' % bits]]) # TODO
-
-    def decode(self, ss, es, data):
-        # Assumption: The right-most char in the 'val' bitstring is the LSB.
-        cmd, val = data
-
-        self.ss, self.es = ss, es
-
-        # self.put(self.ss, self.es, self.out_ann, [0, [cmd + ' / ' + val]])
-
-        # State machine
-        if self.state == 'IDLE':
-            # Wait until a new instruction is shifted into the IR register.
-            if cmd != 'IR TDI':
-                return
-            # Switch to the state named after the instruction, or 'UNKNOWN'.
-            # Ignore bits other than IR[3:0]. While the IR register is only
-            # 4 bits in size, some programs (e.g. OpenOCD) might fill in a
-            # few more (dummy) bits. OpenOCD makes IR at least 8 bits long.
-            self.state = ir.get(val[-4:], ['UNKNOWN', 0])[0]
-            self.put(self.ss, self.es, self.out_ann, [0, ['IR: ' + self.state]])
-        elif self.state == 'BYPASS':
-            # Here we're interested in incoming bits (TDI).
-            if cmd != 'DR TDI':
-                return
-            handle_reg = getattr(self, 'handle_reg_%s' % self.state.lower())
-            handle_reg(cmd, val)
-            self.state = 'IDLE'
-        elif self.state in ('IDCODE', 'ABORT', 'UNKNOWN'):
-            # Here we're interested in outgoing bits (TDO).
-            if cmd != 'DR TDO':
-                return
-            handle_reg = getattr(self, 'handle_reg_%s' % self.state.lower())
-            handle_reg(cmd, val)
-            self.state = 'IDLE'
-        elif self.state in ('DPACC', 'APACC'):
-            # Here we're interested in incoming and outgoing bits (TDI/TDO).
-            if cmd not in ('DR TDI', 'DR TDO'):
-                return
-            handle_reg = getattr(self, 'handle_reg_%s' % self.state.lower())
-            handle_reg(cmd, val)
-            if cmd == 'DR TDO': # TODO: Assumes 'DR TDI' comes before 'DR TDO'
-                self.state = 'IDLE'
-        else:
-            raise Exception('Invalid state: %s' % self.state)
-
diff --git a/decoders/jtag_stm32/pd.py b/decoders/jtag_stm32/pd.py
new file mode 100644 (file)
index 0000000..e30788c
--- /dev/null
@@ -0,0 +1,232 @@
+##
+## This file is part of the sigrok project.
+##
+## 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
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+##
+
+# ST STM32 JTAG protocol decoder
+
+import sigrokdecode as srd
+
+# JTAG debug port data registers (in IR[3:0]) and their sizes (in bits)
+# Note: The ARM DAP-DP is not IEEE 1149.1 (JTAG) compliant (as per ARM docs),
+#       as it does not implement the EXTEST, SAMPLE, and PRELOAD instructions.
+#       Instead, BYPASS is decoded for any of these instructions.
+ir = {
+    '1111': ['BYPASS', 1],  # Bypass register
+    '1110': ['IDCODE', 32], # ID code register
+    '1010': ['DPACC', 35],  # Debug port access register
+    '1011': ['APACC', 35],  # Access port access register
+    '1000': ['ABORT', 35],  # Abort register # TODO: 32 bits? Datasheet typo?
+}
+
+# ARM Cortex-M3 r1p1-01rel0 ID code
+cm3_idcode = 0x3ba00477
+
+# JTAG ID code in the STM32F10xxx BSC (boundary scan) TAP
+jtag_idcode = {
+    0x06412041: 'Low-density device, rev. A',
+    0x06410041: 'Medium-density device, rev. A',
+    0x16410041: 'Medium-density device, rev. B/Z/Y',
+    0x06414041: 'High-density device, rev. A/Z/Y',
+    0x06430041: 'XL-density device, rev. A',
+    0x06418041: 'Connectivity-line device, rev. A/Z',
+}
+
+# ACK[2:0] in the DPACC/APACC registers (unlisted values are reserved)
+ack_val = {
+    '001': 'WAIT',
+    '010': 'OK/FAULT',
+}
+
+# 32bit debug port registers (addressed via A[3:2])
+dp_reg = {
+    '00': 'Reserved', # Must be kept at reset value
+    '01': 'DP CTRL/STAT',
+    '10': 'DP SELECT',
+    '11': 'DP RDBUFF',
+}
+
+# APB-AP registers (each of them 32 bits wide)
+apb_ap_reg = {
+    0x00: ['CSW', 'Control/status word'],
+    0x04: ['TAR', 'Transfer address'],
+    # 0x08: Reserved SBZ
+    0x0c: ['DRW', 'Data read/write'],
+    0x10: ['BD0', 'Banked data 0'],
+    0x14: ['BD1', 'Banked data 1'],
+    0x18: ['BD2', 'Banked data 2'],
+    0x1c: ['BD3', 'Banked data 3'],
+    # 0x20-0xf4: Reserved SBZ
+    0x800000000: ['ROM', 'Debug ROM address'],
+    0xfc: ['IDR', 'Identification register'],
+}
+
+# TODO: All start/end sample values in self.put() calls are bogus.
+# TODO: Split off generic ARM/Cortex-M3 parts into another protocol decoder?
+
+# Bits[31:28]: Version (here: 0x3)
+#              JTAG-DP: 0x3, SW-DP: 0x2
+# Bits[27:12]: Part number (here: 0xba00)
+#              JTAG-DP: 0xba00, SW-DP: 0xba10
+# Bits[11:1]:  JEDEC (JEP-106) manufacturer ID (here: 0x23b)
+#              Bits[11:8]: Continuation code ('ARM Limited': 0x04)
+#              Bits[7:1]: Identity code ('ARM Limited': 0x3b)
+# Bits[0:0]:   Reserved (here: 0x1)
+def decode_device_id_code(bits):
+    id_hex = '0x%x' % int('0b' + bits, 2)
+    ver =    '0x%x' % int('0b' + bits[-32:-28], 2)
+    part =   '0x%x' % int('0b' + bits[-28:-12], 2)
+    manuf =  '0x%x' % int('0b' + bits[-12:-1], 2)
+    res =    '0x%x' % int('0b' + bits[-1], 2)
+    return (id_hex, ver, part, manuf, res)
+
+# DPACC is used to access debug port registers (CTRL/STAT, SELECT, RDBUFF).
+# APACC is used to access all Access Port (AHB-AP) registers.
+
+# APACC/DPACC, when transferring data IN:
+# Bits[34:3] = DATA[31:0]: 32bit data to transfer (write request)
+# Bits[2:1] = A[3:2]: 2-bit address (debug/access port register)
+# Bits[0:0] = RnW: Read request (1) or write request (0)
+def data_in(instruction, bits):
+    data, a, rnw = bits[:-3], bits[-3:-1], bits[-1]
+    data_hex = '0x%x' % int('0b' + data, 2)
+    r = 'Read request' if (rnw == '1') else 'Write request'
+    # reg = dp_reg[a] if (instruction == 'DPACC') else apb_ap_reg[a]
+    reg = dp_reg[a] if (instruction == 'DPACC') else a # TODO
+    return 'New transaction: DATA: %s, A: %s, RnW: %s' % (data_hex, reg, r)
+
+# APACC/DPACC, when transferring data OUT:
+# Bits[34:3] = DATA[31:0]: 32bit data which is read (read request)
+# Bits[2:0] = ACK[2:0]: 3-bit acknowledge
+def data_out(bits):
+    data, ack = bits[:-3], bits[-3:]
+    data_hex = '0x%x' % int('0b' + data, 2)
+    ack_meaning = ack_val.get(ack, 'Reserved')
+    return 'Previous transaction result: DATA: %s, ACK: %s' \
+           % (data_hex, ack_meaning)
+
+class Decoder(srd.Decoder):
+    api_version = 1
+    id = 'jtag_stm32'
+    name = 'JTAG / STM32'
+    longname = 'Joint Test Action Group / ST STM32'
+    desc = 'ST STM32-specific JTAG protocol.'
+    license = 'gplv2+'
+    inputs = ['jtag']
+    outputs = ['jtag_stm32']
+    probes = []
+    optional_probes = []
+    options = {}
+    annotations = [
+        ['Text', 'Human-readable text'],
+    ]
+
+    def __init__(self, **kwargs):
+        self.state = 'IDLE'
+        # self.state = 'BYPASS'
+
+    def start(self, metadata):
+        # self.out_proto = self.add(srd.OUTPUT_PROTO, 'jtag_stm32')
+        self.out_ann = self.add(srd.OUTPUT_ANN, 'jtag_stm32')
+
+    def report(self):
+        pass
+
+    def handle_reg_bypass(self, cmd, bits):
+        # TODO
+        self.put(self.ss, self.es, self.out_ann, [0, ['BYPASS: ' + bits]])
+
+    def handle_reg_idcode(self, cmd, bits):
+        # TODO
+        # IDCODE is a read-only register which is always accessible.
+        # IR == IDCODE: The device ID code is shifted out via DR next.
+        self.put(self.ss, self.es, self.out_ann,
+                 [0, ['IDCODE: %s (ver=%s, part=%s, manuf=%s, res=%s)' % \
+                 decode_device_id_code(bits)]])
+
+    def handle_reg_dpacc(self, cmd, bits):
+        # self.put(self.ss, self.es, self.out_ann,
+        #          [0, ['DPACC/%s: %s' % (cmd, bits)]])
+        s = data_in('DPACC', bits) if (cmd == 'DR TDI') else data_out(bits)
+        self.put(self.ss, self.es, self.out_ann, [0, [s]])
+
+    def handle_reg_apacc(self, cmd, bits):
+        # self.put(self.ss, self.es, self.out_ann,
+        #          [0, ['APACC/%s: %s' % (cmd, bits)]])
+        s = data_in('APACC', bits) if (cmd == 'DR TDI') else data_out(bits)
+        self.put(self.ss, self.es, self.out_ann, [0, [s]])
+
+    def handle_reg_abort(self, cmd, bits):
+        # Bits[31:1]: reserved. Bit[0]: DAPABORT.
+        a = '' if (bits[0] == '1') else 'No '
+        s = 'DAPABORT = %s: %sDAP abort generated' % (bits[0], a)
+        self.put(self.ss, self.es, self.out_ann, [0, [s]])
+
+        # Warn if DAPABORT[31:1] contains non-zero bits.
+        if (bits[:-1] != ('0' * 31)):
+            self.put(self.ss, self.es, self.out_ann,
+                     [0, ['WARNING: DAPABORT[31:1] reserved!']])
+
+    def handle_reg_unknown(self, cmd, bits):
+        self.put(self.ss, self.es, self.out_ann,
+                 [0, ['Unknown instruction: ' % bits]]) # TODO
+
+    def decode(self, ss, es, data):
+        # Assumption: The right-most char in the 'val' bitstring is the LSB.
+        cmd, val = data
+
+        self.ss, self.es = ss, es
+
+        # self.put(self.ss, self.es, self.out_ann, [0, [cmd + ' / ' + val]])
+
+        # State machine
+        if self.state == 'IDLE':
+            # Wait until a new instruction is shifted into the IR register.
+            if cmd != 'IR TDI':
+                return
+            # Switch to the state named after the instruction, or 'UNKNOWN'.
+            # Ignore bits other than IR[3:0]. While the IR register is only
+            # 4 bits in size, some programs (e.g. OpenOCD) might fill in a
+            # few more (dummy) bits. OpenOCD makes IR at least 8 bits long.
+            self.state = ir.get(val[-4:], ['UNKNOWN', 0])[0]
+            self.put(self.ss, self.es, self.out_ann, [0, ['IR: ' + self.state]])
+        elif self.state == 'BYPASS':
+            # Here we're interested in incoming bits (TDI).
+            if cmd != 'DR TDI':
+                return
+            handle_reg = getattr(self, 'handle_reg_%s' % self.state.lower())
+            handle_reg(cmd, val)
+            self.state = 'IDLE'
+        elif self.state in ('IDCODE', 'ABORT', 'UNKNOWN'):
+            # Here we're interested in outgoing bits (TDO).
+            if cmd != 'DR TDO':
+                return
+            handle_reg = getattr(self, 'handle_reg_%s' % self.state.lower())
+            handle_reg(cmd, val)
+            self.state = 'IDLE'
+        elif self.state in ('DPACC', 'APACC'):
+            # Here we're interested in incoming and outgoing bits (TDI/TDO).
+            if cmd not in ('DR TDI', 'DR TDO'):
+                return
+            handle_reg = getattr(self, 'handle_reg_%s' % self.state.lower())
+            handle_reg(cmd, val)
+            if cmd == 'DR TDO': # TODO: Assumes 'DR TDI' comes before 'DR TDO'
+                self.state = 'IDLE'
+        else:
+            raise Exception('Invalid state: %s' % self.state)
+
index 6ab18181632e619ca2f6e7b1285c039526b6157a..82a219066674bc32873229a7abfbb455cc2e2ee2 100644 (file)
@@ -20,7 +20,7 @@
 
 pkgdatadir = $(DECODERS_DIR)/lm75
 
-dist_pkgdata_DATA = __init__.py lm75.py
+dist_pkgdata_DATA = __init__.py pd.py
 
 CLEANFILES = *.pyc
 
index fd72612bacbfe569342033660090591220f5e167..548cf6521bf01087dab5a5f1b1cbc3e823aa42a9 100644 (file)
@@ -30,5 +30,5 @@ Details:
 TODO.
 '''
 
-from .lm75 import *
+from .pd import *
 
diff --git a/decoders/lm75/lm75.py b/decoders/lm75/lm75.py
deleted file mode 100644 (file)
index 9d2f0ab..0000000
+++ /dev/null
@@ -1,211 +0,0 @@
-##
-## This file is part of the sigrok project.
-##
-## 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
-## the Free Software Foundation; either version 2 of the License, or
-## (at your option) any later version.
-##
-## This program is distributed in the hope that it will be useful,
-## but WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-## GNU General Public License for more details.
-##
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, write to the Free Software
-## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
-##
-
-# National LM75 (and compatibles) temperature sensor protocol decoder
-
-# TODO: Better support for various LM75 compatible devices.
-
-import sigrokdecode as srd
-
-# LM75 only supports 9 bit resolution, compatible devices usually 9-12 bits.
-resolution = {
-    # CONFIG[6:5]: <resolution>
-    0x00: 9,
-    0x01: 10,
-    0x02: 11,
-    0x03: 12,
-}
-
-ft = {
-    # CONFIG[4:3]: <fault tolerance setting>
-    0x00: 1,
-    0x01: 2,
-    0x02: 4,
-    0x03: 6,
-}
-
-class Decoder(srd.Decoder):
-    api_version = 1
-    id = 'lm75'
-    name = 'LM75'
-    longname = 'National LM75'
-    desc = 'National LM75 (and compatibles) temperature sensor protocol.'
-    license = 'gplv2+'
-    inputs = ['i2c']
-    outputs = ['lm75']
-    probes = []
-    optional_probes = [
-        {'id': 'os', 'name': 'OS', 'desc': 'Overtemperature shutdown'},
-        {'id': 'a0', 'name': 'A0', 'desc': 'I2C slave address input 0'},
-        {'id': 'a1', 'name': 'A1', 'desc': 'I2C slave address input 1'},
-        {'id': 'a2', 'name': 'A2', 'desc': 'I2C slave address input 2'},
-    ]
-    options = {
-        'sensor': ['Sensor type', 'lm75'],
-        'resolution': ['Resolution', 9], # 9-12 bit, sensor/config dependent
-    }
-    annotations = [
-        ['Celsius', 'Temperature in degrees Celsius'],
-        ['Kelvin', 'Temperature in Kelvin'],
-        ['Text (verbose)', 'Human-readable text (verbose)'],
-        ['Text', 'Human-readable text'],
-        ['Warnings', 'Human-readable warnings'],
-    ]
-
-    def __init__(self, **kwargs):
-        self.state = 'IDLE'
-        self.reg = 0x00 # Currently selected register
-        self.databytes = []
-        self.mintemp = 0
-        self.maxtemp = 0
-        self.avgvalues = []
-
-    def start(self, metadata):
-        # self.out_proto = self.add(srd.OUTPUT_PROTO, 'lm75')
-        self.out_ann = self.add(srd.OUTPUT_ANN, 'lm75')
-
-    def report(self):
-        # TODO: print() or self.put() or return xyz, or... ?
-        avg = sum(self.avgvalues) / len(self.avgvalues)
-        temperatures = (self.mintemp, self.maxtemp, avg)
-        # TODO: Configurable report() output, e.g. for Kelvin.
-        return 'Min/max/avg temperature: %f/%f/%f Â°C' % temperatures
-
-    def putx(self, data):
-        # Helper for annotations which span exactly one I2C packet.
-        self.put(self.ss, self.es, self.out_ann, data)
-
-    def putb(self, data):
-        # Helper for annotations which span a block of I2C packets.
-        self.put(self.block_start, self.block_end, self.out_ann, data)
-
-    def warn_upon_invalid_slave(self, addr):
-        # LM75 and compatible devices have a 7-bit I2C slave address where
-        # the 4 MSBs are fixed to 1001, and the 3 LSBs are configurable.
-        # Thus, valid slave addresses (1001xxx) range from 0x48 to 0x4f.
-        if addr not in range(0x48, 0x4f + 1):
-            s = 'Warning: I2C slave 0x%02x not an LM75 compatible sensor.'
-            self.putx([4, [s % addr]])
-
-    def output_temperature(self, s, rw):
-        # TODO: Support for resolutions other than 9 bit.
-        before, after = self.databytes[0], (self.databytes[1] >> 7) * 5
-        celsius = float('%d.%d' % (before, after))
-        kelvin = celsius + 273.15
-        self.putb([0, ['%s: %.1f Â°C' % (s, celsius)]])
-        self.putb([1, ['%s: %.1f K' % (s, kelvin)]])
-
-        # Warn about the temperature register (0x00) being read-only.
-        if s == 'Temperature' and rw == 'WRITE':
-            s = 'Warning: The temperature register is read-only!'
-            self.putb([4, [s]])
-
-        # Keep some statistics. Can be output in report(), for example.
-        if celsius < self.mintemp:
-            self.mintemp = celsius
-        if celsius > self.maxtemp:
-            self.maxtemp = celsius
-        self.avgvalues.append(celsius)
-
-    def handle_temperature_reg(self, b, s, rw):
-        # Common helper for the temperature/T_HYST/T_OS registers.
-        if len(self.databytes) == 0:
-            self.block_start = self.ss
-            self.databytes.append(b)
-            return
-        self.databytes.append(b)
-        self.block_end = self.es
-        self.output_temperature(s, rw)
-        self.databytes = []
-
-    def handle_reg_0x00(self, b, rw):
-        # Temperature register (16bits, read-only).
-        self.handle_temperature_reg(b, 'Temperature', rw)
-
-    def handle_reg_0x01(self, b, rw):
-        # Configuration register (8 bits, read/write).
-        # TODO: Bit-exact annotation ranges.
-
-        sd = b & (1 << 0)
-        tmp = 'normal operation' if (sd == 0) else 'shutdown mode'
-        s = 'SD = %d: %s\n' % (sd, tmp)
-        s2 = 'SD = %s, ' % tmp
-
-        cmp_int = b & (1 << 1)
-        tmp = 'comparator' if (cmp_int == 0) else 'interrupt'
-        s += 'CMP/INT = %d: %s mode\n' % (cmp_int, tmp)
-        s2 += 'CMP/INT = %s, ' % tmp
-
-        pol = b & (1 << 2)
-        tmp = 'low' if (pol == 0) else 'high'
-        s += 'POL = %d: OS polarity is active-%s\n' % (pol, tmp)
-        s2 += 'POL = active-%s, ' % tmp
-
-        bits = (b & ((1 << 4) | (1 << 3))) >> 3
-        s += 'Fault tolerance setting: %d bit(s)\n' % ft[bits]
-        s2 += 'FT = %d' % ft[bits]
-
-        # Not supported by LM75, but by various compatible devices.
-        if self.options['sensor'] != 'lm75': # TODO
-            bits = (b & ((1 << 6) | (1 << 5))) >> 5
-            s += 'Resolution: %d bits\n' % resolution[bits]
-            s2 += ', resolution = %d' % resolution[bits]
-
-        self.putx([2, [s]])
-        self.putx([3, [s2]])
-
-    def handle_reg_0x02(self, b, rw):
-        # T_HYST register (16 bits, read/write).
-        self.handle_temperature_reg(b, 'T_HYST trip temperature', rw)
-
-    def handle_reg_0x03(self, b, rw):
-        # T_OS register (16 bits, read/write).
-        self.handle_temperature_reg(b, 'T_OS trip temperature', rw)
-
-    def decode(self, ss, es, data):
-        cmd, databyte = data
-
-        # Store the start/end samples of this I2C packet.
-        self.ss, self.es = ss, es
-
-        # State machine.
-        if self.state == 'IDLE':
-            # Wait for an I2C START condition.
-            if cmd != 'START':
-                return
-            self.state = 'GET SLAVE ADDR'
-        elif self.state == 'GET SLAVE ADDR':
-            # Wait for an address read/write operation.
-            if cmd in ('ADDRESS READ', 'ADDRESS WRITE'):
-                self.warn_upon_invalid_slave(databyte)
-                self.state = cmd[8:] + ' REGS' # READ REGS / WRITE REGS
-        elif self.state in ('READ REGS', 'WRITE REGS'):
-            if cmd in ('DATA READ', 'DATA WRITE'):
-                handle_reg = getattr(self, 'handle_reg_0x%02x' % self.reg)
-                handle_reg(databyte, cmd[5:]) # READ / WRITE
-            elif cmd == 'STOP':
-                # TODO: Any output?
-                self.state = 'IDLE'
-            else:
-                # self.putx([0, ['Ignoring: %s (data=%s)' % (cmd, databyte)]])
-                pass
-        else:
-            raise Exception('Invalid state: %s' % self.state)
-
diff --git a/decoders/lm75/pd.py b/decoders/lm75/pd.py
new file mode 100644 (file)
index 0000000..9d2f0ab
--- /dev/null
@@ -0,0 +1,211 @@
+##
+## This file is part of the sigrok project.
+##
+## 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
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+##
+
+# National LM75 (and compatibles) temperature sensor protocol decoder
+
+# TODO: Better support for various LM75 compatible devices.
+
+import sigrokdecode as srd
+
+# LM75 only supports 9 bit resolution, compatible devices usually 9-12 bits.
+resolution = {
+    # CONFIG[6:5]: <resolution>
+    0x00: 9,
+    0x01: 10,
+    0x02: 11,
+    0x03: 12,
+}
+
+ft = {
+    # CONFIG[4:3]: <fault tolerance setting>
+    0x00: 1,
+    0x01: 2,
+    0x02: 4,
+    0x03: 6,
+}
+
+class Decoder(srd.Decoder):
+    api_version = 1
+    id = 'lm75'
+    name = 'LM75'
+    longname = 'National LM75'
+    desc = 'National LM75 (and compatibles) temperature sensor protocol.'
+    license = 'gplv2+'
+    inputs = ['i2c']
+    outputs = ['lm75']
+    probes = []
+    optional_probes = [
+        {'id': 'os', 'name': 'OS', 'desc': 'Overtemperature shutdown'},
+        {'id': 'a0', 'name': 'A0', 'desc': 'I2C slave address input 0'},
+        {'id': 'a1', 'name': 'A1', 'desc': 'I2C slave address input 1'},
+        {'id': 'a2', 'name': 'A2', 'desc': 'I2C slave address input 2'},
+    ]
+    options = {
+        'sensor': ['Sensor type', 'lm75'],
+        'resolution': ['Resolution', 9], # 9-12 bit, sensor/config dependent
+    }
+    annotations = [
+        ['Celsius', 'Temperature in degrees Celsius'],
+        ['Kelvin', 'Temperature in Kelvin'],
+        ['Text (verbose)', 'Human-readable text (verbose)'],
+        ['Text', 'Human-readable text'],
+        ['Warnings', 'Human-readable warnings'],
+    ]
+
+    def __init__(self, **kwargs):
+        self.state = 'IDLE'
+        self.reg = 0x00 # Currently selected register
+        self.databytes = []
+        self.mintemp = 0
+        self.maxtemp = 0
+        self.avgvalues = []
+
+    def start(self, metadata):
+        # self.out_proto = self.add(srd.OUTPUT_PROTO, 'lm75')
+        self.out_ann = self.add(srd.OUTPUT_ANN, 'lm75')
+
+    def report(self):
+        # TODO: print() or self.put() or return xyz, or... ?
+        avg = sum(self.avgvalues) / len(self.avgvalues)
+        temperatures = (self.mintemp, self.maxtemp, avg)
+        # TODO: Configurable report() output, e.g. for Kelvin.
+        return 'Min/max/avg temperature: %f/%f/%f Â°C' % temperatures
+
+    def putx(self, data):
+        # Helper for annotations which span exactly one I2C packet.
+        self.put(self.ss, self.es, self.out_ann, data)
+
+    def putb(self, data):
+        # Helper for annotations which span a block of I2C packets.
+        self.put(self.block_start, self.block_end, self.out_ann, data)
+
+    def warn_upon_invalid_slave(self, addr):
+        # LM75 and compatible devices have a 7-bit I2C slave address where
+        # the 4 MSBs are fixed to 1001, and the 3 LSBs are configurable.
+        # Thus, valid slave addresses (1001xxx) range from 0x48 to 0x4f.
+        if addr not in range(0x48, 0x4f + 1):
+            s = 'Warning: I2C slave 0x%02x not an LM75 compatible sensor.'
+            self.putx([4, [s % addr]])
+
+    def output_temperature(self, s, rw):
+        # TODO: Support for resolutions other than 9 bit.
+        before, after = self.databytes[0], (self.databytes[1] >> 7) * 5
+        celsius = float('%d.%d' % (before, after))
+        kelvin = celsius + 273.15
+        self.putb([0, ['%s: %.1f Â°C' % (s, celsius)]])
+        self.putb([1, ['%s: %.1f K' % (s, kelvin)]])
+
+        # Warn about the temperature register (0x00) being read-only.
+        if s == 'Temperature' and rw == 'WRITE':
+            s = 'Warning: The temperature register is read-only!'
+            self.putb([4, [s]])
+
+        # Keep some statistics. Can be output in report(), for example.
+        if celsius < self.mintemp:
+            self.mintemp = celsius
+        if celsius > self.maxtemp:
+            self.maxtemp = celsius
+        self.avgvalues.append(celsius)
+
+    def handle_temperature_reg(self, b, s, rw):
+        # Common helper for the temperature/T_HYST/T_OS registers.
+        if len(self.databytes) == 0:
+            self.block_start = self.ss
+            self.databytes.append(b)
+            return
+        self.databytes.append(b)
+        self.block_end = self.es
+        self.output_temperature(s, rw)
+        self.databytes = []
+
+    def handle_reg_0x00(self, b, rw):
+        # Temperature register (16bits, read-only).
+        self.handle_temperature_reg(b, 'Temperature', rw)
+
+    def handle_reg_0x01(self, b, rw):
+        # Configuration register (8 bits, read/write).
+        # TODO: Bit-exact annotation ranges.
+
+        sd = b & (1 << 0)
+        tmp = 'normal operation' if (sd == 0) else 'shutdown mode'
+        s = 'SD = %d: %s\n' % (sd, tmp)
+        s2 = 'SD = %s, ' % tmp
+
+        cmp_int = b & (1 << 1)
+        tmp = 'comparator' if (cmp_int == 0) else 'interrupt'
+        s += 'CMP/INT = %d: %s mode\n' % (cmp_int, tmp)
+        s2 += 'CMP/INT = %s, ' % tmp
+
+        pol = b & (1 << 2)
+        tmp = 'low' if (pol == 0) else 'high'
+        s += 'POL = %d: OS polarity is active-%s\n' % (pol, tmp)
+        s2 += 'POL = active-%s, ' % tmp
+
+        bits = (b & ((1 << 4) | (1 << 3))) >> 3
+        s += 'Fault tolerance setting: %d bit(s)\n' % ft[bits]
+        s2 += 'FT = %d' % ft[bits]
+
+        # Not supported by LM75, but by various compatible devices.
+        if self.options['sensor'] != 'lm75': # TODO
+            bits = (b & ((1 << 6) | (1 << 5))) >> 5
+            s += 'Resolution: %d bits\n' % resolution[bits]
+            s2 += ', resolution = %d' % resolution[bits]
+
+        self.putx([2, [s]])
+        self.putx([3, [s2]])
+
+    def handle_reg_0x02(self, b, rw):
+        # T_HYST register (16 bits, read/write).
+        self.handle_temperature_reg(b, 'T_HYST trip temperature', rw)
+
+    def handle_reg_0x03(self, b, rw):
+        # T_OS register (16 bits, read/write).
+        self.handle_temperature_reg(b, 'T_OS trip temperature', rw)
+
+    def decode(self, ss, es, data):
+        cmd, databyte = data
+
+        # Store the start/end samples of this I2C packet.
+        self.ss, self.es = ss, es
+
+        # State machine.
+        if self.state == 'IDLE':
+            # Wait for an I2C START condition.
+            if cmd != 'START':
+                return
+            self.state = 'GET SLAVE ADDR'
+        elif self.state == 'GET SLAVE ADDR':
+            # Wait for an address read/write operation.
+            if cmd in ('ADDRESS READ', 'ADDRESS WRITE'):
+                self.warn_upon_invalid_slave(databyte)
+                self.state = cmd[8:] + ' REGS' # READ REGS / WRITE REGS
+        elif self.state in ('READ REGS', 'WRITE REGS'):
+            if cmd in ('DATA READ', 'DATA WRITE'):
+                handle_reg = getattr(self, 'handle_reg_0x%02x' % self.reg)
+                handle_reg(databyte, cmd[5:]) # READ / WRITE
+            elif cmd == 'STOP':
+                # TODO: Any output?
+                self.state = 'IDLE'
+            else:
+                # self.putx([0, ['Ignoring: %s (data=%s)' % (cmd, databyte)]])
+                pass
+        else:
+            raise Exception('Invalid state: %s' % self.state)
+
index 28de382de4ae880496c78473773fef8328059d56..d9cf564d69c1ac07f7e5ce799a2e0a6fc20983f4 100644 (file)
@@ -20,7 +20,7 @@
 
 pkgdatadir = $(DECODERS_DIR)/lpc
 
-dist_pkgdata_DATA = __init__.py lpc.py
+dist_pkgdata_DATA = __init__.py pd.py
 
 CLEANFILES = *.pyc
 
index ce2a1406fd0ba66527a8f6ff684c7cd87b47a37b..1c79b7334cc6a30aae82da26757ef54f57cb82a6 100644 (file)
@@ -25,5 +25,5 @@ Details:
 TODO
 '''
 
-from .lpc import *
+from .pd import *
 
diff --git a/decoders/lpc/lpc.py b/decoders/lpc/lpc.py
deleted file mode 100644 (file)
index cd56a9b..0000000
+++ /dev/null
@@ -1,349 +0,0 @@
-##
-## This file is part of the sigrok project.
-##
-## 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
-## the Free Software Foundation; either version 2 of the License, or
-## (at your option) any later version.
-##
-## This program is distributed in the hope that it will be useful,
-## but WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-## GNU General Public License for more details.
-##
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, write to the Free Software
-## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
-##
-
-# LPC protocol decoder
-
-import sigrokdecode as srd
-
-# ...
-fields = {
-    # START field (indicates start or stop of a transaction)
-    'START': {
-        0b0000: 'Start of cycle for a target',
-        0b0001: 'Reserved',
-        0b0010: 'Grant for bus master 0',
-        0b0011: 'Grant for bus master 1',
-        0b0100: 'Reserved',
-        0b0101: 'Reserved',
-        0b0110: 'Reserved',
-        0b0111: 'Reserved',
-        0b1000: 'Reserved',
-        0b1001: 'Reserved',
-        0b1010: 'Reserved',
-        0b1011: 'Reserved',
-        0b1100: 'Reserved',
-        0b1101: 'Start of cycle for a Firmware Memory Read cycle',
-        0b1110: 'Start of cycle for a Firmware Memory Write cycle',
-        0b1111: 'Stop/abort (end of a cycle for a target)',
-    },
-    # Cycle type / direction field
-    # Bit 0 (LAD[0]) is unused, should always be 0.
-    # Neither host nor peripheral are allowed to drive 0b11x0.
-    'CT_DR': {
-        0b0000: 'I/O read',
-        0b0010: 'I/O write',
-        0b0100: 'Memory read',
-        0b0110: 'Memory write',
-        0b1000: 'DMA read',
-        0b1010: 'DMA write',
-        0b1100: 'Reserved / not allowed',
-        0b1110: 'Reserved / not allowed',
-    },
-    # SIZE field (determines how many bytes are to be transferred)
-    # Bits[3:2] are reserved, must be driven to 0b00.
-    # Neither host nor peripheral are allowed to drive 0b0010.
-    'SIZE': {
-        0b0000: '8 bits (1 byte)',
-        0b0001: '16 bits (2 bytes)',
-        0b0010: 'Reserved / not allowed',
-        0b0011: '32 bits (4 bytes)',
-    },
-    # CHANNEL field (bits[2:0] contain the DMA channel number)
-    'CHANNEL': {
-        0b0000: '0',
-        0b0001: '1',
-        0b0010: '2',
-        0b0011: '3',
-        0b0100: '4',
-        0b0101: '5',
-        0b0110: '6',
-        0b0111: '7',
-    },
-    # SYNC field (used to add wait states)
-    'SYNC': {
-        0b0000: 'Ready',
-        0b0001: 'Reserved',
-        0b0010: 'Reserved',
-        0b0011: 'Reserved',
-        0b0100: 'Reserved',
-        0b0101: 'Short wait',
-        0b0110: 'Long wait',
-        0b0111: 'Reserved',
-        0b1000: 'Reserved',
-        0b1001: 'Ready more (DMA only)',
-        0b1010: 'Error',
-        0b1011: 'Reserved',
-        0b1100: 'Reserved',
-        0b1101: 'Reserved',
-        0b1110: 'Reserved',
-        0b1111: 'Reserved',
-    },
-}
-
-class Decoder(srd.Decoder):
-    api_version = 1
-    id = 'lpc'
-    name = 'LPC'
-    longname = 'Low-Pin-Count'
-    desc = 'Protocol for low-bandwidth devices on PC mainboards.'
-    license = 'gplv2+'
-    inputs = ['logic']
-    outputs = ['lpc']
-    probes = [
-        {'id': 'lframe', 'name': 'LFRAME#', 'desc': 'TODO'},
-        {'id': 'lreset', 'name': 'LRESET#', 'desc': 'TODO'},
-        {'id': 'lclk',   'name': 'LCLK',    'desc': 'TODO'},
-        {'id': 'lad0',   'name': 'LAD[0]',  'desc': 'TODO'},
-        {'id': 'lad1',   'name': 'LAD[1]',  'desc': 'TODO'},
-        {'id': 'lad2',   'name': 'LAD[2]',  'desc': 'TODO'},
-        {'id': 'lad3',   'name': 'LAD[3]',  'desc': 'TODO'},
-    ]
-    optional_probes = [
-        {'id': 'ldrq',   'name': 'LDRQ#',   'desc': 'TODO'},
-        {'id': 'serirq', 'name': 'SERIRQ',  'desc': 'TODO'},
-        {'id': 'clkrun', 'name': 'CLKRUN#', 'desc': 'TODO'},
-        {'id': 'lpme',   'name': 'LPME#',   'desc': 'TODO'},
-        {'id': 'lpcpd',  'name': 'LPCPD#',  'desc': 'TODO'},
-        {'id': 'lsmi',   'name': 'LSMI#',   'desc': 'TODO'},
-    ]
-    options = {}
-    annotations = [
-        ['Text', 'Human-readable text'],
-    ]
-
-    def __init__(self, **kwargs):
-        self.state = 'IDLE'
-        self.oldlclk = -1
-        self.samplenum = 0
-        self.clocknum = 0
-        self.lad = -1
-        self.addr = 0
-        self.cur_nibble = 0
-        self.cycle_type = -1
-        self.oldpins = (-1, -1, -1, -1, -1, -1, -1)
-
-    def start(self, metadata):
-        self.out_proto = self.add(srd.OUTPUT_PROTO, 'lpc')
-        self.out_ann = self.add(srd.OUTPUT_ANN, 'lpc')
-
-    def report(self):
-        pass
-
-    def handle_get_start(self, lad, lframe):
-        # LAD[3:0]: START field (1 clock cycle).
-
-        # The last value of LAD[3:0] before LFRAME# gets de-asserted is what
-        # the peripherals must use. However, the host can keep LFRAME# asserted
-        # multiple clocks, and we output all START fields that occur, even
-        # though the peripherals are supposed to ignore all but the last one.
-        s = fields['START'][lad]
-        self.put(0, 0, self.out_ann, [0, [s]])
-
-        # Output a warning if LAD[3:0] changes while LFRAME# is low.
-        # TODO
-        if (self.lad != -1 and self.lad != lad):
-            self.put(0, 0, self.out_ann,
-                     [0, ['Warning: LAD[3:0] changed while '
-                     'LFRAME# was asserted']])
-
-        # LFRAME# is asserted (low). Wait until it gets de-asserted again
-        # (the host is allowed to keep it asserted multiple clocks).
-        if lframe != 1:
-            return
-
-        self.start_field = self.lad
-        self.state = 'GET CT/DR'
-
-    def handle_get_ct_dr(self, lad, lad_bits):
-        # LAD[3:0]: Cycle type / direction field (1 clock cycle).
-
-        self.cycle_type = fields['CT_DR'][lad]
-
-        # TODO: Warning/error on invalid cycle types.
-        if self.cycle_type == 'Reserved':
-            self.put(0, 0, self.out_ann,
-                     [0, ['Warning: Invalid cycle type (%s)' % lad_bits]])
-
-        # ...
-        self.put(0, 0, self.out_ann, [0, ['Cycle type: %s' % self.cycle_type]])
-
-        self.state = 'GET ADDR'
-        self.addr = 0
-        self.cur_nibble = 0
-
-    def handle_get_addr(self, lad, lad_bits):
-        # LAD[3:0]: ADDR field (4/8/0 clock cycles).
-
-        # I/O cycles: 4 ADDR clocks. Memory cycles: 8 ADDR clocks.
-        # DMA cycles: no ADDR clocks at all.
-        if self.cycle_type in ('I/O read', 'I/O write'):
-            addr_nibbles = 4 # Address is 16bits.
-        elif self.cycle_type in ('Memory read', 'Memory write'):
-            addr_nibbles = 8 # Address is 32bits.
-        else:
-            addr_nibbles = 0 # TODO: How to handle later on?
-
-        # Data is driven MSN-first.
-        offset = ((addr_nibbles - 1) - self.cur_nibble) * 4
-        self.addr |= (lad << offset)
-
-        # Continue if we haven't seen all ADDR cycles, yet.
-        # TODO: Off-by-one?
-        if (self.cur_nibble < addr_nibbles - 1):
-            self.cur_nibble += 1
-            return
-
-        self.put(0, 0, self.out_ann, [0, ['Address: %s' % hex(self.addr)]])
-
-        self.state = 'GET TAR'
-        self.tar_count = 0
-
-    def handle_get_tar(self, lad, lad_bits):
-        # LAD[3:0]: First TAR (turn-around) field (2 clock cycles).
-
-        self.put(0, 0, self.out_ann, [0, ['TAR, cycle %d: %s'
-                 % (self.tarcount, lad_bits)]])
-
-        # On the first TAR clock cycle LAD[3:0] is driven to 1111 by
-        # either the host or peripheral. On the second clock cycle,
-        # the host or peripheral tri-states LAD[3:0], but its value
-        # should still be 1111, due to pull-ups on the LAD lines.
-        if lad_bits != '1111':
-            self.put(0, 0, self.out_ann,
-                     [0, ['Warning: TAR, cycle %d: %s (expected 1111)'
-                     % (self.tarcount, lad_bits)]])
-
-        if (self.tarcount != 2):
-            self.tarcount += 1
-            return
-
-        self.state = 'GET SYNC'
-
-    def handle_get_sync(self, lad, lad_bits):
-        # LAD[3:0]: SYNC field (1-n clock cycles).
-
-        self.sync_val = lad_bits
-        self.cycle_type = fields['SYNC'][lad]
-
-        # TODO: Warnings if reserved value are seen?
-        if self.cycle_type == 'Reserved':
-            self.put(0, 0, self.out_ann, [0, ['Warning: SYNC, cycle %d: %s '
-                     '(reserved value)' % (self.synccount, self.sync_val)]])
-
-        self.put(0, 0, self.out_ann, [0, ['SYNC, cycle %d: %s'
-                 % (self.synccount, self.sync_val)]])
-
-        # TODO
-
-        self.state = 'GET DATA'
-        self.cycle_count = 0
-
-    def handle_get_data(self, lad, lad_bits):
-        # LAD[3:0]: DATA field (2 clock cycles).
-
-        if (self.cycle_count == 0):
-            self.databyte = lad
-        elif (self.cycle_count == 1):
-            self.databyte |= (lad << 4)
-        else:
-            pass # TODO: Error?
-
-        if (self.cycle_count != 2):
-            self.cycle_count += 1
-            return
-
-        self.put(0, 0, self.out_ann, [0, ['DATA: %s' % hex(self.databyte)]])
-        
-        self.state = 'GET TAR2'
-
-    def handle_get_tar2(self, lad, lad_bits):
-        # LAD[3:0]: Second TAR field (2 clock cycles).
-
-        self.put(0, 0, self.out_ann, [0, ['TAR, cycle %d: %s'
-                 % (self.tarcount, lad_bits)]])
-
-        # On the first TAR clock cycle LAD[3:0] is driven to 1111 by
-        # either the host or peripheral. On the second clock cycle,
-        # the host or peripheral tri-states LAD[3:0], but its value
-        # should still be 1111, due to pull-ups on the LAD lines.
-        if lad_bits != '1111':
-            self.put(0, 0, self.out_ann,
-                     [0, ['Warning: TAR, cycle %d: %s (expected 1111)'
-                     % (self.tarcount, lad_bits)]])
-
-        if (self.tarcount != 2):
-            self.tarcount += 1
-            return
-
-        self.state = 'GET SYNC'
-
-    # TODO: At which edge of the clock is data latched? Falling?
-    def decode(self, ss, es, data):
-        for (samplenum, pins) in data:
-
-            # If none of the pins changed, there's nothing to do.
-            if self.oldpins == pins:
-                continue
-
-            # Store current pin values for the next round.
-            self.oldpins = pins
-
-            # Get individual pin values into local variables.
-            # TODO: Handle optional pins.
-            (lframe, lreset, lclk, lad0, lad1, lad2, lad3) = pins
-
-            # Only look at the signals upon falling LCLK edges.
-            # TODO: Rising?
-            ## if not (self.oldlclk == 1 and lclk == 0)
-            ##     self.oldlclk = lclk
-            ##     continue
-
-            # Store LAD[3:0] bit values (one nibble) in local variables.
-            # Most (but not all) states need this.
-            if self.state != 'IDLE':
-                lad = (lad3 << 3) | (lad2 << 2) | (lad1 << 1) | lad0
-                lad_bits = bin(lad)[2:]
-
-            # State machine
-            if self.state == 'IDLE':
-                # A valid LPC cycle starts with LFRAME# being asserted (low).
-                # TODO?
-                if lframe != 0:
-                   continue
-                self.state = 'GET START'
-                self.lad = -1
-                # self.clocknum = 0
-            elif self.state == 'GET START':
-                handle_get_start(lad, lad_bits, lframe)
-            elif self.state == 'GET CT/DR':
-                handle_get_ct_dr(lad, lad_bits)
-            elif self.state == 'GET ADDR':
-                handle_get_addr(lad, lad_bits)
-            elif self.state == 'GET TAR':
-                handle_get_tar(lad, lad_bits)
-            elif self.state == 'GET SYNC':
-                handle_get_sync(lad, lad_bits)
-            elif self.state == 'GET DATA':
-                handle_get_data(lad, lad_bits)
-            elif self.state == 'GET TAR2':
-                handle_get_tar2(lad, lad_bits)
-            else:
-                raise Exception('Invalid state: %s' % self.state)
-
diff --git a/decoders/lpc/pd.py b/decoders/lpc/pd.py
new file mode 100644 (file)
index 0000000..cd56a9b
--- /dev/null
@@ -0,0 +1,349 @@
+##
+## This file is part of the sigrok project.
+##
+## 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
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+##
+
+# LPC protocol decoder
+
+import sigrokdecode as srd
+
+# ...
+fields = {
+    # START field (indicates start or stop of a transaction)
+    'START': {
+        0b0000: 'Start of cycle for a target',
+        0b0001: 'Reserved',
+        0b0010: 'Grant for bus master 0',
+        0b0011: 'Grant for bus master 1',
+        0b0100: 'Reserved',
+        0b0101: 'Reserved',
+        0b0110: 'Reserved',
+        0b0111: 'Reserved',
+        0b1000: 'Reserved',
+        0b1001: 'Reserved',
+        0b1010: 'Reserved',
+        0b1011: 'Reserved',
+        0b1100: 'Reserved',
+        0b1101: 'Start of cycle for a Firmware Memory Read cycle',
+        0b1110: 'Start of cycle for a Firmware Memory Write cycle',
+        0b1111: 'Stop/abort (end of a cycle for a target)',
+    },
+    # Cycle type / direction field
+    # Bit 0 (LAD[0]) is unused, should always be 0.
+    # Neither host nor peripheral are allowed to drive 0b11x0.
+    'CT_DR': {
+        0b0000: 'I/O read',
+        0b0010: 'I/O write',
+        0b0100: 'Memory read',
+        0b0110: 'Memory write',
+        0b1000: 'DMA read',
+        0b1010: 'DMA write',
+        0b1100: 'Reserved / not allowed',
+        0b1110: 'Reserved / not allowed',
+    },
+    # SIZE field (determines how many bytes are to be transferred)
+    # Bits[3:2] are reserved, must be driven to 0b00.
+    # Neither host nor peripheral are allowed to drive 0b0010.
+    'SIZE': {
+        0b0000: '8 bits (1 byte)',
+        0b0001: '16 bits (2 bytes)',
+        0b0010: 'Reserved / not allowed',
+        0b0011: '32 bits (4 bytes)',
+    },
+    # CHANNEL field (bits[2:0] contain the DMA channel number)
+    'CHANNEL': {
+        0b0000: '0',
+        0b0001: '1',
+        0b0010: '2',
+        0b0011: '3',
+        0b0100: '4',
+        0b0101: '5',
+        0b0110: '6',
+        0b0111: '7',
+    },
+    # SYNC field (used to add wait states)
+    'SYNC': {
+        0b0000: 'Ready',
+        0b0001: 'Reserved',
+        0b0010: 'Reserved',
+        0b0011: 'Reserved',
+        0b0100: 'Reserved',
+        0b0101: 'Short wait',
+        0b0110: 'Long wait',
+        0b0111: 'Reserved',
+        0b1000: 'Reserved',
+        0b1001: 'Ready more (DMA only)',
+        0b1010: 'Error',
+        0b1011: 'Reserved',
+        0b1100: 'Reserved',
+        0b1101: 'Reserved',
+        0b1110: 'Reserved',
+        0b1111: 'Reserved',
+    },
+}
+
+class Decoder(srd.Decoder):
+    api_version = 1
+    id = 'lpc'
+    name = 'LPC'
+    longname = 'Low-Pin-Count'
+    desc = 'Protocol for low-bandwidth devices on PC mainboards.'
+    license = 'gplv2+'
+    inputs = ['logic']
+    outputs = ['lpc']
+    probes = [
+        {'id': 'lframe', 'name': 'LFRAME#', 'desc': 'TODO'},
+        {'id': 'lreset', 'name': 'LRESET#', 'desc': 'TODO'},
+        {'id': 'lclk',   'name': 'LCLK',    'desc': 'TODO'},
+        {'id': 'lad0',   'name': 'LAD[0]',  'desc': 'TODO'},
+        {'id': 'lad1',   'name': 'LAD[1]',  'desc': 'TODO'},
+        {'id': 'lad2',   'name': 'LAD[2]',  'desc': 'TODO'},
+        {'id': 'lad3',   'name': 'LAD[3]',  'desc': 'TODO'},
+    ]
+    optional_probes = [
+        {'id': 'ldrq',   'name': 'LDRQ#',   'desc': 'TODO'},
+        {'id': 'serirq', 'name': 'SERIRQ',  'desc': 'TODO'},
+        {'id': 'clkrun', 'name': 'CLKRUN#', 'desc': 'TODO'},
+        {'id': 'lpme',   'name': 'LPME#',   'desc': 'TODO'},
+        {'id': 'lpcpd',  'name': 'LPCPD#',  'desc': 'TODO'},
+        {'id': 'lsmi',   'name': 'LSMI#',   'desc': 'TODO'},
+    ]
+    options = {}
+    annotations = [
+        ['Text', 'Human-readable text'],
+    ]
+
+    def __init__(self, **kwargs):
+        self.state = 'IDLE'
+        self.oldlclk = -1
+        self.samplenum = 0
+        self.clocknum = 0
+        self.lad = -1
+        self.addr = 0
+        self.cur_nibble = 0
+        self.cycle_type = -1
+        self.oldpins = (-1, -1, -1, -1, -1, -1, -1)
+
+    def start(self, metadata):
+        self.out_proto = self.add(srd.OUTPUT_PROTO, 'lpc')
+        self.out_ann = self.add(srd.OUTPUT_ANN, 'lpc')
+
+    def report(self):
+        pass
+
+    def handle_get_start(self, lad, lframe):
+        # LAD[3:0]: START field (1 clock cycle).
+
+        # The last value of LAD[3:0] before LFRAME# gets de-asserted is what
+        # the peripherals must use. However, the host can keep LFRAME# asserted
+        # multiple clocks, and we output all START fields that occur, even
+        # though the peripherals are supposed to ignore all but the last one.
+        s = fields['START'][lad]
+        self.put(0, 0, self.out_ann, [0, [s]])
+
+        # Output a warning if LAD[3:0] changes while LFRAME# is low.
+        # TODO
+        if (self.lad != -1 and self.lad != lad):
+            self.put(0, 0, self.out_ann,
+                     [0, ['Warning: LAD[3:0] changed while '
+                     'LFRAME# was asserted']])
+
+        # LFRAME# is asserted (low). Wait until it gets de-asserted again
+        # (the host is allowed to keep it asserted multiple clocks).
+        if lframe != 1:
+            return
+
+        self.start_field = self.lad
+        self.state = 'GET CT/DR'
+
+    def handle_get_ct_dr(self, lad, lad_bits):
+        # LAD[3:0]: Cycle type / direction field (1 clock cycle).
+
+        self.cycle_type = fields['CT_DR'][lad]
+
+        # TODO: Warning/error on invalid cycle types.
+        if self.cycle_type == 'Reserved':
+            self.put(0, 0, self.out_ann,
+                     [0, ['Warning: Invalid cycle type (%s)' % lad_bits]])
+
+        # ...
+        self.put(0, 0, self.out_ann, [0, ['Cycle type: %s' % self.cycle_type]])
+
+        self.state = 'GET ADDR'
+        self.addr = 0
+        self.cur_nibble = 0
+
+    def handle_get_addr(self, lad, lad_bits):
+        # LAD[3:0]: ADDR field (4/8/0 clock cycles).
+
+        # I/O cycles: 4 ADDR clocks. Memory cycles: 8 ADDR clocks.
+        # DMA cycles: no ADDR clocks at all.
+        if self.cycle_type in ('I/O read', 'I/O write'):
+            addr_nibbles = 4 # Address is 16bits.
+        elif self.cycle_type in ('Memory read', 'Memory write'):
+            addr_nibbles = 8 # Address is 32bits.
+        else:
+            addr_nibbles = 0 # TODO: How to handle later on?
+
+        # Data is driven MSN-first.
+        offset = ((addr_nibbles - 1) - self.cur_nibble) * 4
+        self.addr |= (lad << offset)
+
+        # Continue if we haven't seen all ADDR cycles, yet.
+        # TODO: Off-by-one?
+        if (self.cur_nibble < addr_nibbles - 1):
+            self.cur_nibble += 1
+            return
+
+        self.put(0, 0, self.out_ann, [0, ['Address: %s' % hex(self.addr)]])
+
+        self.state = 'GET TAR'
+        self.tar_count = 0
+
+    def handle_get_tar(self, lad, lad_bits):
+        # LAD[3:0]: First TAR (turn-around) field (2 clock cycles).
+
+        self.put(0, 0, self.out_ann, [0, ['TAR, cycle %d: %s'
+                 % (self.tarcount, lad_bits)]])
+
+        # On the first TAR clock cycle LAD[3:0] is driven to 1111 by
+        # either the host or peripheral. On the second clock cycle,
+        # the host or peripheral tri-states LAD[3:0], but its value
+        # should still be 1111, due to pull-ups on the LAD lines.
+        if lad_bits != '1111':
+            self.put(0, 0, self.out_ann,
+                     [0, ['Warning: TAR, cycle %d: %s (expected 1111)'
+                     % (self.tarcount, lad_bits)]])
+
+        if (self.tarcount != 2):
+            self.tarcount += 1
+            return
+
+        self.state = 'GET SYNC'
+
+    def handle_get_sync(self, lad, lad_bits):
+        # LAD[3:0]: SYNC field (1-n clock cycles).
+
+        self.sync_val = lad_bits
+        self.cycle_type = fields['SYNC'][lad]
+
+        # TODO: Warnings if reserved value are seen?
+        if self.cycle_type == 'Reserved':
+            self.put(0, 0, self.out_ann, [0, ['Warning: SYNC, cycle %d: %s '
+                     '(reserved value)' % (self.synccount, self.sync_val)]])
+
+        self.put(0, 0, self.out_ann, [0, ['SYNC, cycle %d: %s'
+                 % (self.synccount, self.sync_val)]])
+
+        # TODO
+
+        self.state = 'GET DATA'
+        self.cycle_count = 0
+
+    def handle_get_data(self, lad, lad_bits):
+        # LAD[3:0]: DATA field (2 clock cycles).
+
+        if (self.cycle_count == 0):
+            self.databyte = lad
+        elif (self.cycle_count == 1):
+            self.databyte |= (lad << 4)
+        else:
+            pass # TODO: Error?
+
+        if (self.cycle_count != 2):
+            self.cycle_count += 1
+            return
+
+        self.put(0, 0, self.out_ann, [0, ['DATA: %s' % hex(self.databyte)]])
+        
+        self.state = 'GET TAR2'
+
+    def handle_get_tar2(self, lad, lad_bits):
+        # LAD[3:0]: Second TAR field (2 clock cycles).
+
+        self.put(0, 0, self.out_ann, [0, ['TAR, cycle %d: %s'
+                 % (self.tarcount, lad_bits)]])
+
+        # On the first TAR clock cycle LAD[3:0] is driven to 1111 by
+        # either the host or peripheral. On the second clock cycle,
+        # the host or peripheral tri-states LAD[3:0], but its value
+        # should still be 1111, due to pull-ups on the LAD lines.
+        if lad_bits != '1111':
+            self.put(0, 0, self.out_ann,
+                     [0, ['Warning: TAR, cycle %d: %s (expected 1111)'
+                     % (self.tarcount, lad_bits)]])
+
+        if (self.tarcount != 2):
+            self.tarcount += 1
+            return
+
+        self.state = 'GET SYNC'
+
+    # TODO: At which edge of the clock is data latched? Falling?
+    def decode(self, ss, es, data):
+        for (samplenum, pins) in data:
+
+            # If none of the pins changed, there's nothing to do.
+            if self.oldpins == pins:
+                continue
+
+            # Store current pin values for the next round.
+            self.oldpins = pins
+
+            # Get individual pin values into local variables.
+            # TODO: Handle optional pins.
+            (lframe, lreset, lclk, lad0, lad1, lad2, lad3) = pins
+
+            # Only look at the signals upon falling LCLK edges.
+            # TODO: Rising?
+            ## if not (self.oldlclk == 1 and lclk == 0)
+            ##     self.oldlclk = lclk
+            ##     continue
+
+            # Store LAD[3:0] bit values (one nibble) in local variables.
+            # Most (but not all) states need this.
+            if self.state != 'IDLE':
+                lad = (lad3 << 3) | (lad2 << 2) | (lad1 << 1) | lad0
+                lad_bits = bin(lad)[2:]
+
+            # State machine
+            if self.state == 'IDLE':
+                # A valid LPC cycle starts with LFRAME# being asserted (low).
+                # TODO?
+                if lframe != 0:
+                   continue
+                self.state = 'GET START'
+                self.lad = -1
+                # self.clocknum = 0
+            elif self.state == 'GET START':
+                handle_get_start(lad, lad_bits, lframe)
+            elif self.state == 'GET CT/DR':
+                handle_get_ct_dr(lad, lad_bits)
+            elif self.state == 'GET ADDR':
+                handle_get_addr(lad, lad_bits)
+            elif self.state == 'GET TAR':
+                handle_get_tar(lad, lad_bits)
+            elif self.state == 'GET SYNC':
+                handle_get_sync(lad, lad_bits)
+            elif self.state == 'GET DATA':
+                handle_get_data(lad, lad_bits)
+            elif self.state == 'GET TAR2':
+                handle_get_tar2(lad, lad_bits)
+            else:
+                raise Exception('Invalid state: %s' % self.state)
+
index ee53993e12105308a27577e17be05d32dc3f997e..24413596d5a7e5cbe0556490c9f59b00bd1a22e2 100644 (file)
@@ -20,7 +20,7 @@
 
 pkgdatadir = $(DECODERS_DIR)/maxim_ds28ea00
 
-dist_pkgdata_DATA = __init__.py maxim_ds28ea00.py
+dist_pkgdata_DATA = __init__.py pd.py
 
 CLEANFILES = *.pyc
 
index 508ae5b960077fd21eee6fa02c7a25c3b9b531da..cb1c77870bae562a5cda9d71ec5b29010d3771f0 100644 (file)
@@ -28,5 +28,5 @@ Details:
 TODO
 '''
 
-from .maxim_ds28ea00 import *
+from .pd import *
 
diff --git a/decoders/maxim_ds28ea00/maxim_ds28ea00.py b/decoders/maxim_ds28ea00/maxim_ds28ea00.py
deleted file mode 100644 (file)
index 026457e..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-##
-## This file is part of the sigrok project.
-##
-## Copyright (C) 2012 Iztok Jeras <iztok.jeras@gmail.com>
-##
-## 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
-## the Free Software Foundation; either version 2 of the License, or
-## (at your option) any later version.
-##
-## This program is distributed in the hope that it will be useful,
-## but WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-## GNU General Public License for more details.
-##
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, write to the Free Software
-## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
-##
-
-# Maxim DS28EA00 protocol decoder
-
-import sigrokdecode as srd
-
-# Dictionary of FUNCTION commands and their names.
-command = {
-    # Scratchpad
-    0x4e: 'Write scratchpad',
-    0xbe: 'Read scratchpad',
-    0x48: 'Copy scratchpad',
-    # Thermometer
-    0x44: 'Convert temperature',
-    0xb4: 'Read power mode',
-    0xb8: 'Recall EEPROM',
-    0xf5: 'PIO access read',
-    0xA5: 'PIO access write',
-    0x99: 'Chain',
-}
-
-class Decoder(srd.Decoder):
-    api_version = 1
-    id = 'maxim_ds28ea00'
-    name = 'Maxim DS28EA00'
-    longname = 'Maxim DS28EA00 1-Wire digital thermometer'
-    desc = '1-Wire digital thermometer with Sequence Detect and PIO'
-    license = 'gplv2+'
-    inputs = ['onewire_network']
-    outputs = ['maxim_ds28ea00']
-    probes = []
-    optional_probes = [
-        {'id': 'pioa', 'name': 'PIOA/DONE#',
-         'desc': 'PIOA channel and chain output'},
-        {'id': 'piob', 'name': 'PIOB/EN#',
-         'desc': 'PIOB channel and chain output'},
-    ]
-    options = {}
-    annotations = [
-        ['Text', 'Human-readable text'],
-    ]
-
-    def __init__(self, **kwargs):
-        self.trn_beg = 0
-        self.trn_end = 0
-        self.state = 'ROM'
-        self.rom = 0x0000000000000000
-
-    def start(self, metadata):
-        self.out_ann = self.add(srd.OUTPUT_ANN, 'maxim_ds28ea00')
-
-    def report(self):
-        pass
-
-    def putx(self, data):
-        self.put(self.ss, self.es, self.out_ann, data)
-
-    def decode(self, ss, es, data):
-        code, val = data
-
-        self.ss, self.es = ss, es
-
-        # State machine.
-        if code == 'RESET/PRESENCE':
-            self.putx([0, ['Reset/presence: %s'
-                           % ('true' if val else 'false')]])
-            self.state = 'ROM'
-        elif code == 'ROM':
-            self.rom = val
-            self.putx([0, ['ROM: 0x%016x' % (val)]])
-            self.state = 'COMMAND'
-        elif code == 'DATA':
-            if self.state == 'COMMAND':
-                if val not in command:
-                    self.putx([0, ['Unrecognized command: 0x%02x' % val]])
-                    return
-                self.putx([0, ['Function command: 0x%02x \'%s\''
-                          % (val, command[val])]])
-                self.state = command[val].upper()
-            elif self.state == 'READ SCRATCHPAD':
-                self.putx([0, ['Scratchpad data: 0x%02x' % val]])
-            elif self.state == 'CONVERT TEMPERATURE':
-                self.putx([0, ['Temperature conversion status: 0x%02x' % val]])
-            elif self.state in [s.upper() for s in command.values()]:
-                self.putx([0, ['TODO \'%s\': 0x%02x' % (self.state, val)]])
-            else:
-                raise Exception('Invalid state: %s' % self.state)
-
diff --git a/decoders/maxim_ds28ea00/pd.py b/decoders/maxim_ds28ea00/pd.py
new file mode 100644 (file)
index 0000000..026457e
--- /dev/null
@@ -0,0 +1,106 @@
+##
+## This file is part of the sigrok project.
+##
+## Copyright (C) 2012 Iztok Jeras <iztok.jeras@gmail.com>
+##
+## 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
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+##
+
+# Maxim DS28EA00 protocol decoder
+
+import sigrokdecode as srd
+
+# Dictionary of FUNCTION commands and their names.
+command = {
+    # Scratchpad
+    0x4e: 'Write scratchpad',
+    0xbe: 'Read scratchpad',
+    0x48: 'Copy scratchpad',
+    # Thermometer
+    0x44: 'Convert temperature',
+    0xb4: 'Read power mode',
+    0xb8: 'Recall EEPROM',
+    0xf5: 'PIO access read',
+    0xA5: 'PIO access write',
+    0x99: 'Chain',
+}
+
+class Decoder(srd.Decoder):
+    api_version = 1
+    id = 'maxim_ds28ea00'
+    name = 'Maxim DS28EA00'
+    longname = 'Maxim DS28EA00 1-Wire digital thermometer'
+    desc = '1-Wire digital thermometer with Sequence Detect and PIO'
+    license = 'gplv2+'
+    inputs = ['onewire_network']
+    outputs = ['maxim_ds28ea00']
+    probes = []
+    optional_probes = [
+        {'id': 'pioa', 'name': 'PIOA/DONE#',
+         'desc': 'PIOA channel and chain output'},
+        {'id': 'piob', 'name': 'PIOB/EN#',
+         'desc': 'PIOB channel and chain output'},
+    ]
+    options = {}
+    annotations = [
+        ['Text', 'Human-readable text'],
+    ]
+
+    def __init__(self, **kwargs):
+        self.trn_beg = 0
+        self.trn_end = 0
+        self.state = 'ROM'
+        self.rom = 0x0000000000000000
+
+    def start(self, metadata):
+        self.out_ann = self.add(srd.OUTPUT_ANN, 'maxim_ds28ea00')
+
+    def report(self):
+        pass
+
+    def putx(self, data):
+        self.put(self.ss, self.es, self.out_ann, data)
+
+    def decode(self, ss, es, data):
+        code, val = data
+
+        self.ss, self.es = ss, es
+
+        # State machine.
+        if code == 'RESET/PRESENCE':
+            self.putx([0, ['Reset/presence: %s'
+                           % ('true' if val else 'false')]])
+            self.state = 'ROM'
+        elif code == 'ROM':
+            self.rom = val
+            self.putx([0, ['ROM: 0x%016x' % (val)]])
+            self.state = 'COMMAND'
+        elif code == 'DATA':
+            if self.state == 'COMMAND':
+                if val not in command:
+                    self.putx([0, ['Unrecognized command: 0x%02x' % val]])
+                    return
+                self.putx([0, ['Function command: 0x%02x \'%s\''
+                          % (val, command[val])]])
+                self.state = command[val].upper()
+            elif self.state == 'READ SCRATCHPAD':
+                self.putx([0, ['Scratchpad data: 0x%02x' % val]])
+            elif self.state == 'CONVERT TEMPERATURE':
+                self.putx([0, ['Temperature conversion status: 0x%02x' % val]])
+            elif self.state in [s.upper() for s in command.values()]:
+                self.putx([0, ['TODO \'%s\': 0x%02x' % (self.state, val)]])
+            else:
+                raise Exception('Invalid state: %s' % self.state)
+
index f14874fa5bc610f83e79a58eab2819f920ac8a74..c9d0d4b502740a8da9893d4a57703a0c64179ef1 100644 (file)
@@ -20,7 +20,7 @@
 
 pkgdatadir = $(DECODERS_DIR)/mlx90614
 
-dist_pkgdata_DATA = __init__.py mlx90614.py
+dist_pkgdata_DATA = __init__.py pd.py
 
 CLEANFILES = *.pyc
 
index 0ceabc20d986606587413b494333a512a5b758b6..c14e67f40f3c7a02adf627c709c95b48dc42904a 100644 (file)
@@ -25,5 +25,5 @@ Details:
 TODO
 '''
 
-from .mlx90614 import *
+from .pd import *
 
diff --git a/decoders/mlx90614/mlx90614.py b/decoders/mlx90614/mlx90614.py
deleted file mode 100644 (file)
index 1ee88d7..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-##
-## This file is part of the sigrok project.
-##
-## 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
-## the Free Software Foundation; either version 2 of the License, or
-## (at your option) any later version.
-##
-## This program is distributed in the hope that it will be useful,
-## but WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-## GNU General Public License for more details.
-##
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, write to the Free Software
-## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
-##
-
-# Melexis MLX90614 Infrared Thermometer protocol decoder
-
-import sigrokdecode as srd
-
-class Decoder(srd.Decoder):
-    api_version = 1
-    id = 'mlx90614'
-    name = 'MLX90614'
-    longname = 'Melexis MLX90614'
-    desc = 'Infrared Thermometer protocol.'
-    license = 'gplv2+'
-    inputs = ['i2c']
-    outputs = ['mlx90614']
-    probes = []
-    optional_probes = []
-    options = {}
-    annotations = [
-        ['Celsius', 'Temperature in degrees Celsius'],
-        ['Kelvin', 'Temperature in degrees Kelvin'],
-    ]
-
-    def __init__(self, **kwargs):
-        self.state = 'IGNORE START REPEAT'
-        self.data = []
-
-    def start(self, metadata):
-        # self.out_proto = self.add(srd.OUTPUT_PROTO, 'mlx90614')
-        self.out_ann = self.add(srd.OUTPUT_ANN, 'mlx90614')
-
-    def report(self):
-        pass
-
-    def putx(self, data):
-        self.put(self.ss, self.es, self.out_ann, data)
-
-    # Quick hack implementation! This needs to be improved a lot!
-    def decode(self, ss, es, data):
-        cmd, databyte = data
-
-        # State machine.
-        if self.state == 'IGNORE START REPEAT':
-            if cmd != 'START REPEAT':
-                return
-            self.state = 'IGNORE ADDRESS WRITE'
-        elif self.state == 'IGNORE ADDRESS WRITE':
-            if cmd != 'ADDRESS WRITE':
-                return
-            self.state = 'GET TEMPERATURE'
-        elif self.state == 'GET TEMPERATURE':
-            if cmd != 'DATA WRITE':
-                return
-            if len(self.data) == 0:
-                self.data.append(databyte)
-                self.ss = ss
-            elif len(self.data) == 1:
-                self.data.append(databyte)
-                self.es = es
-            else:
-                kelvin = (self.data[0] | (self.data[1] << 8)) * 0.02
-                celsius = kelvin - 273.15
-                self.putx([0, ['Temperature: %3.2f Â°C' % celsius]])
-                self.putx([1, ['Temperature: %3.2f Â°K' % kelvin]])
-                self.state = 'IGNORE START REPEAT'
-                self.data = []
-        else:
-            raise Exception('Invalid state: %d' % self.state)
-
diff --git a/decoders/mlx90614/pd.py b/decoders/mlx90614/pd.py
new file mode 100644 (file)
index 0000000..1ee88d7
--- /dev/null
@@ -0,0 +1,87 @@
+##
+## This file is part of the sigrok project.
+##
+## 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
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+##
+
+# Melexis MLX90614 Infrared Thermometer protocol decoder
+
+import sigrokdecode as srd
+
+class Decoder(srd.Decoder):
+    api_version = 1
+    id = 'mlx90614'
+    name = 'MLX90614'
+    longname = 'Melexis MLX90614'
+    desc = 'Infrared Thermometer protocol.'
+    license = 'gplv2+'
+    inputs = ['i2c']
+    outputs = ['mlx90614']
+    probes = []
+    optional_probes = []
+    options = {}
+    annotations = [
+        ['Celsius', 'Temperature in degrees Celsius'],
+        ['Kelvin', 'Temperature in degrees Kelvin'],
+    ]
+
+    def __init__(self, **kwargs):
+        self.state = 'IGNORE START REPEAT'
+        self.data = []
+
+    def start(self, metadata):
+        # self.out_proto = self.add(srd.OUTPUT_PROTO, 'mlx90614')
+        self.out_ann = self.add(srd.OUTPUT_ANN, 'mlx90614')
+
+    def report(self):
+        pass
+
+    def putx(self, data):
+        self.put(self.ss, self.es, self.out_ann, data)
+
+    # Quick hack implementation! This needs to be improved a lot!
+    def decode(self, ss, es, data):
+        cmd, databyte = data
+
+        # State machine.
+        if self.state == 'IGNORE START REPEAT':
+            if cmd != 'START REPEAT':
+                return
+            self.state = 'IGNORE ADDRESS WRITE'
+        elif self.state == 'IGNORE ADDRESS WRITE':
+            if cmd != 'ADDRESS WRITE':
+                return
+            self.state = 'GET TEMPERATURE'
+        elif self.state == 'GET TEMPERATURE':
+            if cmd != 'DATA WRITE':
+                return
+            if len(self.data) == 0:
+                self.data.append(databyte)
+                self.ss = ss
+            elif len(self.data) == 1:
+                self.data.append(databyte)
+                self.es = es
+            else:
+                kelvin = (self.data[0] | (self.data[1] << 8)) * 0.02
+                celsius = kelvin - 273.15
+                self.putx([0, ['Temperature: %3.2f Â°C' % celsius]])
+                self.putx([1, ['Temperature: %3.2f Â°K' % kelvin]])
+                self.state = 'IGNORE START REPEAT'
+                self.data = []
+        else:
+            raise Exception('Invalid state: %d' % self.state)
+
index 2d571f3bd8a3d2d751f4fef6faef5b297e7545e6..69497966bd18e38884fae7cd2749d3eaafb34866 100644 (file)
@@ -20,7 +20,7 @@
 
 pkgdatadir = $(DECODERS_DIR)/mx25lxx05d
 
-dist_pkgdata_DATA = __init__.py mx25lxx05d.py
+dist_pkgdata_DATA = __init__.py pd.py
 
 CLEANFILES = *.pyc
 
index 3f3c1c662d13d707cbfc6ff138619869446ce0f9..74b70e8184f569bd876c12797415718a220dc6e3 100644 (file)
@@ -29,5 +29,5 @@ Details:
 http://www.macronix.com/QuickPlace/hq/PageLibrary4825740B00298A3B.nsf/h_Index/3F21BAC2E121E17848257639003A3146/$File/MX25L1605D-3205D-6405D-1.5.pdf
 '''
 
-from .mx25lxx05d import *
+from .pd import *
 
diff --git a/decoders/mx25lxx05d/mx25lxx05d.py b/decoders/mx25lxx05d/mx25lxx05d.py
deleted file mode 100644 (file)
index 182ae26..0000000
+++ /dev/null
@@ -1,381 +0,0 @@
-##
-## This file is part of the sigrok project.
-##
-## Copyright (C) 2011-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
-## the Free Software Foundation; either version 2 of the License, or
-## (at your option) any later version.
-##
-## This program is distributed in the hope that it will be useful,
-## but WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-## GNU General Public License for more details.
-##
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, write to the Free Software
-## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
-##
-
-# Macronix MX25Lxx05D SPI (NOR) flash chip protocol decoder
-
-# Note: Works for MX25L1605D/MX25L3205D/MX25L6405D.
-
-import sigrokdecode as srd
-
-# Dict which maps command IDs to their names and descriptions.
-cmds = {
-    0x06: ('WREN', 'Write enable'),
-    0x04: ('WRDI', 'Write disable'),
-    0x9f: ('RDID', 'Read identification'),
-    0x05: ('RDSR', 'Read status register'),
-    0x01: ('WRSR', 'Write status register'),
-    0x03: ('READ', 'Read data'),
-    0x0b: ('FAST/READ', 'Fast read data'),
-    0xbb: ('2READ', '2x I/O read'),
-    0x20: ('SE', 'Sector erase'),
-    0xd8: ('BE', 'Block erase'),
-    0x60: ('CE', 'Chip erase'),
-    0xc7: ('CE2', 'Chip erase'), # Alternative command ID
-    0x02: ('PP', 'Page program'),
-    0xad: ('CP', 'Continuously program mode'),
-    0xb9: ('DP', 'Deep power down'),
-    0xab: ('RDP/RES', 'Release from deep powerdown / Read electronic ID'),
-    0x90: ('REMS', 'Read electronic manufacturer & device ID'),
-    0xef: ('REMS2', 'Read ID for 2x I/O mode'),
-    0xb1: ('ENSO', 'Enter secured OTP'),
-    0xc1: ('EXSO', 'Exit secured OTP'),
-    0x2b: ('RDSCUR', 'Read security register'),
-    0x2f: ('WRSCUR', 'Write security register'),
-    0x70: ('ESRY', 'Enable SO to output RY/BY#'),
-    0x80: ('DSRY', 'Disable SO to output RY/BY#'),
-}
-
-device_name = {
-    0x14: 'MX25L1605D',
-    0x15: 'MX25L3205D',
-    0x16: 'MX25L6405D',
-}
-
-def decode_status_reg(data):
-    # TODO: Additional per-bit(s) self.put() calls with correct start/end.
-
-    # Bits[0:0]: WIP (write in progress)
-    s = 'W' if (data & (1 << 0)) else 'No w'
-    ret = '%srite operation in progress.\n' % s
-
-    # Bits[1:1]: WEL (write enable latch)
-    s = '' if (data & (1 << 1)) else 'not '
-    ret += 'Internal write enable latch is %sset.\n' % s
-
-    # Bits[5:2]: Block protect bits
-    # TODO: More detailed decoding (chip-dependent).
-    ret += 'Block protection bits (BP3-BP0): 0x%x.\n' % ((data & 0x3c) >> 2)
-
-    # Bits[6:6]: Continuously program mode (CP mode)
-    s = '' if (data & (1 << 6)) else 'not '
-    ret += 'Device is %sin continuously program mode (CP mode).\n' % s
-
-    # Bits[7:7]: SRWD (status register write disable)
-    s = 'not ' if (data & (1 << 7)) else ''
-    ret += 'Status register writes are %sallowed.\n' % s
-
-    return ret
-
-class Decoder(srd.Decoder):
-    api_version = 1
-    id = 'mx25lxx05d'
-    name = 'MX25Lxx05D'
-    longname = 'Macronix MX25Lxx05D'
-    desc = 'SPI (NOR) flash chip protocol.'
-    license = 'gplv2+'
-    inputs = ['spi', 'logic']
-    outputs = ['mx25lxx05d']
-    probes = []
-    optional_probes = [
-        {'id': 'hold', 'name': 'HOLD#', 'desc': 'TODO.'},
-        {'id': 'wp_acc', 'name': 'WP#/ACC', 'desc': 'TODO.'},
-    ]
-    options = {}
-    annotations = [
-        ['Text', 'Human-readable text'],
-        ['Verbose decode', 'Decoded register bits, read/write data'],
-        ['Warnings', 'Human-readable warnings'],
-    ]
-
-    def __init__(self, **kwargs):
-        self.state = None
-        self.cmdstate = 1
-        self.addr = 0
-        self.data = []
-
-    def start(self, metadata):
-        # self.out_proto = self.add(srd.OUTPUT_PROTO, 'mx25lxx05d')
-        self.out_ann = self.add(srd.OUTPUT_ANN, 'mx25lxx05d')
-
-    def report(self):
-        pass
-
-    def putx(self, data):
-        # Simplification, most annotations span exactly one SPI byte/packet.
-        self.put(self.ss, self.es, self.out_ann, data)
-
-    def handle_wren(self, mosi, miso):
-        self.putx([0, ['Command: %s' % cmds[self.state][1]]])
-        self.state = None
-
-    def handle_wrdi(self, mosi, miso):
-        pass # TODO
-
-    # TODO: Check/display device ID / name
-    def handle_rdid(self, mosi, miso):
-        if self.cmdstate == 1:
-            # Byte 1: Master sends command ID.
-            self.start_sample = self.ss
-            self.putx([0, ['Command: %s' % cmds[self.state][1]]])
-        elif self.cmdstate == 2:
-            # Byte 2: Slave sends the JEDEC manufacturer ID.
-            self.putx([0, ['Manufacturer ID: 0x%02x' % miso]])
-        elif self.cmdstate == 3:
-            # Byte 3: Slave sends the memory type (0x20 for this chip).
-            self.putx([0, ['Memory type: 0x%02x' % miso]])
-        elif self.cmdstate == 4:
-            # Byte 4: Slave sends the device ID.
-            self.device_id = miso
-            self.putx([0, ['Device ID: 0x%02x' % miso]])
-
-        if self.cmdstate == 4:
-            # TODO: Check self.device_id is valid & exists in device_names.
-            # TODO: Same device ID? Check!
-            d = 'Device: Macronix %s' % device_name[self.device_id]
-            self.put(self.start_sample, self.es, self.out_ann, [0, [d]])
-            self.state = None
-        else:
-            self.cmdstate += 1
-
-    def handle_rdsr(self, mosi, miso):
-        # Read status register: Master asserts CS#, sends RDSR command,
-        # reads status register byte. If CS# is kept asserted, the status
-        # register can be read continuously / multiple times in a row.
-        # When done, the master de-asserts CS# again.
-        if self.cmdstate == 1:
-            # Byte 1: Master sends command ID.
-            self.putx([0, ['Command: %s' % cmds[self.state][1]]])
-        elif self.cmdstate >= 2:
-            # Bytes 2-x: Slave sends status register as long as master clocks.
-            if self.cmdstate <= 3: # TODO: While CS# asserted.
-                self.putx([0, ['Status register: 0x%02x' % miso]])
-                self.putx([1, [decode_status_reg(miso)]])
-
-            if self.cmdstate == 3: # TODO: If CS# got de-asserted.
-                self.state = None
-                return
-
-        self.cmdstate += 1
-
-    def handle_wrsr(self, mosi, miso):
-        pass # TODO
-
-    def handle_read(self, mosi, miso):
-        # Read data bytes: Master asserts CS#, sends READ command, sends
-        # 3-byte address, reads >= 1 data bytes, de-asserts CS#.
-        if self.cmdstate == 1:
-            # Byte 1: Master sends command ID.
-            self.putx([0, ['Command: %s' % cmds[self.state][1]]])
-        elif self.cmdstate in (2, 3, 4):
-            # Bytes 2/3/4: Master sends read address (24bits, MSB-first).
-            self.addr |= (mosi << ((4 - self.cmdstate) * 8))
-            # self.putx([0, ['Read address, byte %d: 0x%02x' % \
-            #                (4 - self.cmdstate, mosi)]])
-            if self.cmdstate == 4:
-                self.putx([0, ['Read address: 0x%06x' % self.addr]])
-                self.addr = 0
-        elif self.cmdstate >= 5:
-            # Bytes 5-x: Master reads data bytes (until CS# de-asserted).
-            # TODO: For now we hardcode 256 bytes per READ command.
-            if self.cmdstate <= 256 + 4: # TODO: While CS# asserted.
-                self.data.append(miso)
-                # self.putx([0, ['New read byte: 0x%02x' % miso]])
-
-            if self.cmdstate == 256 + 4: # TODO: If CS# got de-asserted.
-                # s = ', '.join(map(hex, self.data))
-                s = ''.join(map(chr, self.data))
-                self.putx([0, ['Read data']])
-                self.putx([1, ['Read data: %s' % s]])
-                self.data = []
-                self.state = None
-                return
-
-        self.cmdstate += 1
-
-    def handle_fast_read(self, mosi, miso):
-        pass # TODO
-
-    def handle_2read(self, mosi, miso):
-        pass # TODO
-
-    # TODO: Warn/abort if we don't see the necessary amount of bytes.
-    # TODO: Warn if WREN was not seen before.
-    def handle_se(self, mosi, miso):
-        if self.cmdstate == 1:
-            # Byte 1: Master sends command ID.
-            self.addr = 0
-            self.start_sample = self.ss
-            self.putx([0, ['Command: %s' % cmds[self.state][1]]])
-        elif self.cmdstate in (2, 3, 4):
-            # Bytes 2/3/4: Master sends sectror address (24bits, MSB-first).
-            self.addr |= (mosi << ((4 - self.cmdstate) * 8))
-            # self.putx([0, ['Sector address, byte %d: 0x%02x' % \
-            #                (4 - self.cmdstate, mosi)]])
-
-        if self.cmdstate == 4:
-            d = 'Erase sector %d (0x%06x)' % (self.addr, self.addr)
-            self.put(self.start_sample, self.es, self.out_ann, [0, [d]])
-            # TODO: Max. size depends on chip, check that too if possible.
-            if self.addr % 4096 != 0:
-                # Sector addresses must be 4K-aligned (same for all 3 chips).
-                d = 'Warning: Invalid sector address!'
-                self.put(self.start_sample, self.es, self.out_ann, [2, [d]])
-            self.state = None
-        else:
-            self.cmdstate += 1
-
-    def handle_be(self, mosi, miso):
-        pass # TODO
-
-    def handle_ce(self, mosi, miso):
-        pass # TODO
-
-    def handle_ce2(self, mosi, miso):
-        pass # TODO
-
-    def handle_pp(self, mosi, miso):
-        # Page program: Master asserts CS#, sends PP command, sends 3-byte
-        # page address, sends >= 1 data bytes, de-asserts CS#.
-        if self.cmdstate == 1:
-            # Byte 1: Master sends command ID.
-            self.putx([0, ['Command: %s' % cmds[self.state][1]]])
-        elif self.cmdstate in (2, 3, 4):
-            # Bytes 2/3/4: Master sends page address (24bits, MSB-first).
-            self.addr |= (mosi << ((4 - self.cmdstate) * 8))
-            # self.putx([0, ['Page address, byte %d: 0x%02x' % \
-            #                (4 - self.cmdstate, mosi)]])
-            if self.cmdstate == 4:
-                self.putx([0, ['Page address: 0x%06x' % self.addr]])
-                self.addr = 0
-        elif self.cmdstate >= 5:
-            # Bytes 5-x: Master sends data bytes (until CS# de-asserted).
-            # TODO: For now we hardcode 256 bytes per page / PP command.
-            if self.cmdstate <= 256 + 4: # TODO: While CS# asserted.
-                self.data.append(mosi)
-                # self.putx([0, ['New data byte: 0x%02x' % mosi]])
-
-            if self.cmdstate == 256 + 4: # TODO: If CS# got de-asserted.
-                # s = ', '.join(map(hex, self.data))
-                s = ''.join(map(chr, self.data))
-                self.putx([0, ['Page data']])
-                self.putx([1, ['Page data: %s' % s]])
-                self.data = []
-                self.state = None
-                return
-
-        self.cmdstate += 1
-
-    def handle_cp(self, mosi, miso):
-        pass # TODO
-
-    def handle_dp(self, mosi, miso):
-        pass # TODO
-
-    def handle_rdp_res(self, mosi, miso):
-        pass # TODO
-
-    def handle_rems(self, mosi, miso):
-        if self.cmdstate == 1:
-            # Byte 1: Master sends command ID.
-            self.start_sample = self.ss
-            self.putx([0, ['Command: %s' % cmds[self.state][1]]])
-        elif self.cmdstate in (2, 3):
-            # Bytes 2/3: Master sends two dummy bytes.
-            # TODO: Check dummy bytes? Check reply from device?
-            self.putx([0, ['Dummy byte: %s' % mosi]])
-        elif self.cmdstate == 4:
-            # Byte 4: Master sends 0x00 or 0x01.
-            # 0x00: Master wants manufacturer ID as first reply byte.
-            # 0x01: Master wants device ID as first reply byte.
-            self.manufacturer_id_first = True if (mosi == 0x00) else False
-            d = 'manufacturer' if (mosi == 0x00) else 'device'
-            self.putx([0, ['Master wants %s ID first' % d]])
-        elif self.cmdstate == 5:
-            # Byte 5: Slave sends manufacturer ID (or device ID).
-            self.ids = [miso]
-            d = 'Manufacturer' if self.manufacturer_id_first else 'Device'
-            self.putx([0, ['%s ID' % d]])
-        elif self.cmdstate == 6:
-            # Byte 6: Slave sends device ID (or manufacturer ID).
-            self.ids.append(miso)
-            d = 'Manufacturer' if self.manufacturer_id_first else 'Device'
-            self.putx([0, ['%s ID' % d]])
-
-        if self.cmdstate == 6:
-            self.end_sample = self.es
-            id = self.ids[1] if self.manufacturer_id_first else self.ids[0]
-            self.putx([0, ['Device: Macronix %s' % device_name[id]]])
-            self.state = None
-        else:
-            self.cmdstate += 1
-
-    def handle_rems2(self, mosi, miso):
-        pass # TODO
-
-    def handle_enso(self, mosi, miso):
-        pass # TODO
-
-    def handle_exso(self, mosi, miso):
-        pass # TODO
-
-    def handle_rdscur(self, mosi, miso):
-        pass # TODO
-
-    def handle_wrscur(self, mosi, miso):
-        pass # TODO
-
-    def handle_esry(self, mosi, miso):
-        pass # TODO
-
-    def handle_dsry(self, mosi, miso):
-        pass # TODO
-
-    def decode(self, ss, es, data):
-
-        ptype, mosi, miso = data
-
-        # if ptype == 'DATA':
-        #     self.putx([0, ['MOSI: 0x%02x, MISO: 0x%02x' % (mosi, miso)]])
-
-        # if ptype == 'CS-CHANGE':
-        #     if mosi == 1 and miso == 0:
-        #         self.putx([0, ['Asserting CS#']])
-        #     elif mosi == 0 and miso == 1:
-        #         self.putx([0, ['De-asserting CS#']])
-
-        if ptype != 'DATA':
-            return
-
-        self.ss, self.es = ss, es
-
-        # If we encountered a known chip command, enter the resp. state.
-        if self.state == None:
-            self.state = mosi
-            self.cmdstate = 1
-
-        # Handle commands.
-        if self.state in cmds:
-            s = 'handle_%s' % cmds[self.state][0].lower().replace('/', '_')
-            handle_reg = getattr(self, s)
-            handle_reg(mosi, miso)
-        else:
-            self.putx([0, ['Unknown command: 0x%02x' % mosi]])
-            self.state = None
-
diff --git a/decoders/mx25lxx05d/pd.py b/decoders/mx25lxx05d/pd.py
new file mode 100644 (file)
index 0000000..182ae26
--- /dev/null
@@ -0,0 +1,381 @@
+##
+## This file is part of the sigrok project.
+##
+## Copyright (C) 2011-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
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+##
+
+# Macronix MX25Lxx05D SPI (NOR) flash chip protocol decoder
+
+# Note: Works for MX25L1605D/MX25L3205D/MX25L6405D.
+
+import sigrokdecode as srd
+
+# Dict which maps command IDs to their names and descriptions.
+cmds = {
+    0x06: ('WREN', 'Write enable'),
+    0x04: ('WRDI', 'Write disable'),
+    0x9f: ('RDID', 'Read identification'),
+    0x05: ('RDSR', 'Read status register'),
+    0x01: ('WRSR', 'Write status register'),
+    0x03: ('READ', 'Read data'),
+    0x0b: ('FAST/READ', 'Fast read data'),
+    0xbb: ('2READ', '2x I/O read'),
+    0x20: ('SE', 'Sector erase'),
+    0xd8: ('BE', 'Block erase'),
+    0x60: ('CE', 'Chip erase'),
+    0xc7: ('CE2', 'Chip erase'), # Alternative command ID
+    0x02: ('PP', 'Page program'),
+    0xad: ('CP', 'Continuously program mode'),
+    0xb9: ('DP', 'Deep power down'),
+    0xab: ('RDP/RES', 'Release from deep powerdown / Read electronic ID'),
+    0x90: ('REMS', 'Read electronic manufacturer & device ID'),
+    0xef: ('REMS2', 'Read ID for 2x I/O mode'),
+    0xb1: ('ENSO', 'Enter secured OTP'),
+    0xc1: ('EXSO', 'Exit secured OTP'),
+    0x2b: ('RDSCUR', 'Read security register'),
+    0x2f: ('WRSCUR', 'Write security register'),
+    0x70: ('ESRY', 'Enable SO to output RY/BY#'),
+    0x80: ('DSRY', 'Disable SO to output RY/BY#'),
+}
+
+device_name = {
+    0x14: 'MX25L1605D',
+    0x15: 'MX25L3205D',
+    0x16: 'MX25L6405D',
+}
+
+def decode_status_reg(data):
+    # TODO: Additional per-bit(s) self.put() calls with correct start/end.
+
+    # Bits[0:0]: WIP (write in progress)
+    s = 'W' if (data & (1 << 0)) else 'No w'
+    ret = '%srite operation in progress.\n' % s
+
+    # Bits[1:1]: WEL (write enable latch)
+    s = '' if (data & (1 << 1)) else 'not '
+    ret += 'Internal write enable latch is %sset.\n' % s
+
+    # Bits[5:2]: Block protect bits
+    # TODO: More detailed decoding (chip-dependent).
+    ret += 'Block protection bits (BP3-BP0): 0x%x.\n' % ((data & 0x3c) >> 2)
+
+    # Bits[6:6]: Continuously program mode (CP mode)
+    s = '' if (data & (1 << 6)) else 'not '
+    ret += 'Device is %sin continuously program mode (CP mode).\n' % s
+
+    # Bits[7:7]: SRWD (status register write disable)
+    s = 'not ' if (data & (1 << 7)) else ''
+    ret += 'Status register writes are %sallowed.\n' % s
+
+    return ret
+
+class Decoder(srd.Decoder):
+    api_version = 1
+    id = 'mx25lxx05d'
+    name = 'MX25Lxx05D'
+    longname = 'Macronix MX25Lxx05D'
+    desc = 'SPI (NOR) flash chip protocol.'
+    license = 'gplv2+'
+    inputs = ['spi', 'logic']
+    outputs = ['mx25lxx05d']
+    probes = []
+    optional_probes = [
+        {'id': 'hold', 'name': 'HOLD#', 'desc': 'TODO.'},
+        {'id': 'wp_acc', 'name': 'WP#/ACC', 'desc': 'TODO.'},
+    ]
+    options = {}
+    annotations = [
+        ['Text', 'Human-readable text'],
+        ['Verbose decode', 'Decoded register bits, read/write data'],
+        ['Warnings', 'Human-readable warnings'],
+    ]
+
+    def __init__(self, **kwargs):
+        self.state = None
+        self.cmdstate = 1
+        self.addr = 0
+        self.data = []
+
+    def start(self, metadata):
+        # self.out_proto = self.add(srd.OUTPUT_PROTO, 'mx25lxx05d')
+        self.out_ann = self.add(srd.OUTPUT_ANN, 'mx25lxx05d')
+
+    def report(self):
+        pass
+
+    def putx(self, data):
+        # Simplification, most annotations span exactly one SPI byte/packet.
+        self.put(self.ss, self.es, self.out_ann, data)
+
+    def handle_wren(self, mosi, miso):
+        self.putx([0, ['Command: %s' % cmds[self.state][1]]])
+        self.state = None
+
+    def handle_wrdi(self, mosi, miso):
+        pass # TODO
+
+    # TODO: Check/display device ID / name
+    def handle_rdid(self, mosi, miso):
+        if self.cmdstate == 1:
+            # Byte 1: Master sends command ID.
+            self.start_sample = self.ss
+            self.putx([0, ['Command: %s' % cmds[self.state][1]]])
+        elif self.cmdstate == 2:
+            # Byte 2: Slave sends the JEDEC manufacturer ID.
+            self.putx([0, ['Manufacturer ID: 0x%02x' % miso]])
+        elif self.cmdstate == 3:
+            # Byte 3: Slave sends the memory type (0x20 for this chip).
+            self.putx([0, ['Memory type: 0x%02x' % miso]])
+        elif self.cmdstate == 4:
+            # Byte 4: Slave sends the device ID.
+            self.device_id = miso
+            self.putx([0, ['Device ID: 0x%02x' % miso]])
+
+        if self.cmdstate == 4:
+            # TODO: Check self.device_id is valid & exists in device_names.
+            # TODO: Same device ID? Check!
+            d = 'Device: Macronix %s' % device_name[self.device_id]
+            self.put(self.start_sample, self.es, self.out_ann, [0, [d]])
+            self.state = None
+        else:
+            self.cmdstate += 1
+
+    def handle_rdsr(self, mosi, miso):
+        # Read status register: Master asserts CS#, sends RDSR command,
+        # reads status register byte. If CS# is kept asserted, the status
+        # register can be read continuously / multiple times in a row.
+        # When done, the master de-asserts CS# again.
+        if self.cmdstate == 1:
+            # Byte 1: Master sends command ID.
+            self.putx([0, ['Command: %s' % cmds[self.state][1]]])
+        elif self.cmdstate >= 2:
+            # Bytes 2-x: Slave sends status register as long as master clocks.
+            if self.cmdstate <= 3: # TODO: While CS# asserted.
+                self.putx([0, ['Status register: 0x%02x' % miso]])
+                self.putx([1, [decode_status_reg(miso)]])
+
+            if self.cmdstate == 3: # TODO: If CS# got de-asserted.
+                self.state = None
+                return
+
+        self.cmdstate += 1
+
+    def handle_wrsr(self, mosi, miso):
+        pass # TODO
+
+    def handle_read(self, mosi, miso):
+        # Read data bytes: Master asserts CS#, sends READ command, sends
+        # 3-byte address, reads >= 1 data bytes, de-asserts CS#.
+        if self.cmdstate == 1:
+            # Byte 1: Master sends command ID.
+            self.putx([0, ['Command: %s' % cmds[self.state][1]]])
+        elif self.cmdstate in (2, 3, 4):
+            # Bytes 2/3/4: Master sends read address (24bits, MSB-first).
+            self.addr |= (mosi << ((4 - self.cmdstate) * 8))
+            # self.putx([0, ['Read address, byte %d: 0x%02x' % \
+            #                (4 - self.cmdstate, mosi)]])
+            if self.cmdstate == 4:
+                self.putx([0, ['Read address: 0x%06x' % self.addr]])
+                self.addr = 0
+        elif self.cmdstate >= 5:
+            # Bytes 5-x: Master reads data bytes (until CS# de-asserted).
+            # TODO: For now we hardcode 256 bytes per READ command.
+            if self.cmdstate <= 256 + 4: # TODO: While CS# asserted.
+                self.data.append(miso)
+                # self.putx([0, ['New read byte: 0x%02x' % miso]])
+
+            if self.cmdstate == 256 + 4: # TODO: If CS# got de-asserted.
+                # s = ', '.join(map(hex, self.data))
+                s = ''.join(map(chr, self.data))
+                self.putx([0, ['Read data']])
+                self.putx([1, ['Read data: %s' % s]])
+                self.data = []
+                self.state = None
+                return
+
+        self.cmdstate += 1
+
+    def handle_fast_read(self, mosi, miso):
+        pass # TODO
+
+    def handle_2read(self, mosi, miso):
+        pass # TODO
+
+    # TODO: Warn/abort if we don't see the necessary amount of bytes.
+    # TODO: Warn if WREN was not seen before.
+    def handle_se(self, mosi, miso):
+        if self.cmdstate == 1:
+            # Byte 1: Master sends command ID.
+            self.addr = 0
+            self.start_sample = self.ss
+            self.putx([0, ['Command: %s' % cmds[self.state][1]]])
+        elif self.cmdstate in (2, 3, 4):
+            # Bytes 2/3/4: Master sends sectror address (24bits, MSB-first).
+            self.addr |= (mosi << ((4 - self.cmdstate) * 8))
+            # self.putx([0, ['Sector address, byte %d: 0x%02x' % \
+            #                (4 - self.cmdstate, mosi)]])
+
+        if self.cmdstate == 4:
+            d = 'Erase sector %d (0x%06x)' % (self.addr, self.addr)
+            self.put(self.start_sample, self.es, self.out_ann, [0, [d]])
+            # TODO: Max. size depends on chip, check that too if possible.
+            if self.addr % 4096 != 0:
+                # Sector addresses must be 4K-aligned (same for all 3 chips).
+                d = 'Warning: Invalid sector address!'
+                self.put(self.start_sample, self.es, self.out_ann, [2, [d]])
+            self.state = None
+        else:
+            self.cmdstate += 1
+
+    def handle_be(self, mosi, miso):
+        pass # TODO
+
+    def handle_ce(self, mosi, miso):
+        pass # TODO
+
+    def handle_ce2(self, mosi, miso):
+        pass # TODO
+
+    def handle_pp(self, mosi, miso):
+        # Page program: Master asserts CS#, sends PP command, sends 3-byte
+        # page address, sends >= 1 data bytes, de-asserts CS#.
+        if self.cmdstate == 1:
+            # Byte 1: Master sends command ID.
+            self.putx([0, ['Command: %s' % cmds[self.state][1]]])
+        elif self.cmdstate in (2, 3, 4):
+            # Bytes 2/3/4: Master sends page address (24bits, MSB-first).
+            self.addr |= (mosi << ((4 - self.cmdstate) * 8))
+            # self.putx([0, ['Page address, byte %d: 0x%02x' % \
+            #                (4 - self.cmdstate, mosi)]])
+            if self.cmdstate == 4:
+                self.putx([0, ['Page address: 0x%06x' % self.addr]])
+                self.addr = 0
+        elif self.cmdstate >= 5:
+            # Bytes 5-x: Master sends data bytes (until CS# de-asserted).
+            # TODO: For now we hardcode 256 bytes per page / PP command.
+            if self.cmdstate <= 256 + 4: # TODO: While CS# asserted.
+                self.data.append(mosi)
+                # self.putx([0, ['New data byte: 0x%02x' % mosi]])
+
+            if self.cmdstate == 256 + 4: # TODO: If CS# got de-asserted.
+                # s = ', '.join(map(hex, self.data))
+                s = ''.join(map(chr, self.data))
+                self.putx([0, ['Page data']])
+                self.putx([1, ['Page data: %s' % s]])
+                self.data = []
+                self.state = None
+                return
+
+        self.cmdstate += 1
+
+    def handle_cp(self, mosi, miso):
+        pass # TODO
+
+    def handle_dp(self, mosi, miso):
+        pass # TODO
+
+    def handle_rdp_res(self, mosi, miso):
+        pass # TODO
+
+    def handle_rems(self, mosi, miso):
+        if self.cmdstate == 1:
+            # Byte 1: Master sends command ID.
+            self.start_sample = self.ss
+            self.putx([0, ['Command: %s' % cmds[self.state][1]]])
+        elif self.cmdstate in (2, 3):
+            # Bytes 2/3: Master sends two dummy bytes.
+            # TODO: Check dummy bytes? Check reply from device?
+            self.putx([0, ['Dummy byte: %s' % mosi]])
+        elif self.cmdstate == 4:
+            # Byte 4: Master sends 0x00 or 0x01.
+            # 0x00: Master wants manufacturer ID as first reply byte.
+            # 0x01: Master wants device ID as first reply byte.
+            self.manufacturer_id_first = True if (mosi == 0x00) else False
+            d = 'manufacturer' if (mosi == 0x00) else 'device'
+            self.putx([0, ['Master wants %s ID first' % d]])
+        elif self.cmdstate == 5:
+            # Byte 5: Slave sends manufacturer ID (or device ID).
+            self.ids = [miso]
+            d = 'Manufacturer' if self.manufacturer_id_first else 'Device'
+            self.putx([0, ['%s ID' % d]])
+        elif self.cmdstate == 6:
+            # Byte 6: Slave sends device ID (or manufacturer ID).
+            self.ids.append(miso)
+            d = 'Manufacturer' if self.manufacturer_id_first else 'Device'
+            self.putx([0, ['%s ID' % d]])
+
+        if self.cmdstate == 6:
+            self.end_sample = self.es
+            id = self.ids[1] if self.manufacturer_id_first else self.ids[0]
+            self.putx([0, ['Device: Macronix %s' % device_name[id]]])
+            self.state = None
+        else:
+            self.cmdstate += 1
+
+    def handle_rems2(self, mosi, miso):
+        pass # TODO
+
+    def handle_enso(self, mosi, miso):
+        pass # TODO
+
+    def handle_exso(self, mosi, miso):
+        pass # TODO
+
+    def handle_rdscur(self, mosi, miso):
+        pass # TODO
+
+    def handle_wrscur(self, mosi, miso):
+        pass # TODO
+
+    def handle_esry(self, mosi, miso):
+        pass # TODO
+
+    def handle_dsry(self, mosi, miso):
+        pass # TODO
+
+    def decode(self, ss, es, data):
+
+        ptype, mosi, miso = data
+
+        # if ptype == 'DATA':
+        #     self.putx([0, ['MOSI: 0x%02x, MISO: 0x%02x' % (mosi, miso)]])
+
+        # if ptype == 'CS-CHANGE':
+        #     if mosi == 1 and miso == 0:
+        #         self.putx([0, ['Asserting CS#']])
+        #     elif mosi == 0 and miso == 1:
+        #         self.putx([0, ['De-asserting CS#']])
+
+        if ptype != 'DATA':
+            return
+
+        self.ss, self.es = ss, es
+
+        # If we encountered a known chip command, enter the resp. state.
+        if self.state == None:
+            self.state = mosi
+            self.cmdstate = 1
+
+        # Handle commands.
+        if self.state in cmds:
+            s = 'handle_%s' % cmds[self.state][0].lower().replace('/', '_')
+            handle_reg = getattr(self, s)
+            handle_reg(mosi, miso)
+        else:
+            self.putx([0, ['Unknown command: 0x%02x' % mosi]])
+            self.state = None
+
index 891dbc10c10cbb9c9105f959aa03de782811adf9..45cd50ca0f38d732b8da74119ac5ca3a5df2abd8 100644 (file)
@@ -20,7 +20,7 @@
 
 pkgdatadir = $(DECODERS_DIR)/mxc6225xu
 
-dist_pkgdata_DATA = __init__.py mxc6225xu.py
+dist_pkgdata_DATA = __init__.py pd.py
 
 CLEANFILES = *.pyc
 
index 02b63b22583ef6227acd589bd13b50ff940b1722..3bca9e4f0d21eef641999fbb597915787e561c88 100644 (file)
@@ -30,5 +30,5 @@ Details:
 TODO
 '''
 
-from .mxc6225xu import *
+from .pd import *
 
diff --git a/decoders/mxc6225xu/mxc6225xu.py b/decoders/mxc6225xu/mxc6225xu.py
deleted file mode 100644 (file)
index 39564a9..0000000
+++ /dev/null
@@ -1,229 +0,0 @@
-##
-## This file is part of the sigrok project.
-##
-## 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
-## the Free Software Foundation; either version 2 of the License, or
-## (at your option) any later version.
-##
-## This program is distributed in the hope that it will be useful,
-## but WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-## GNU General Public License for more details.
-##
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, write to the Free Software
-## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
-##
-
-# MEMSIC MXC6225XU protocol decoder
-
-import sigrokdecode as srd
-
-# Definitions of various bits in MXC6225XU registers.
-status = {
-    # SH[1:0]
-    'sh': {
-        0b00: 'none',
-        0b01: 'shake left',
-        0b10: 'shake right',
-        0b11: 'undefined',
-    },
-    # ORI[1:0] and OR[1:0] (same format)
-    'ori': {
-        0b00: 'vertical in upright orientation',
-        0b01: 'rotated 90 degrees clockwise',
-        0b10: 'vertical in inverted orientation',
-        0b11: 'rotated 90 degrees counterclockwise',
-    },
-    # SHTH[1:0]
-    'shth': {
-        0b00: '0.5g',
-        0b01: '1.0g',
-        0b10: '1.5g',
-        0b11: '2.0g',
-    },
-    # SHC[1:0]
-    'shc': {
-        0b00: '16',
-        0b01: '32',
-        0b10: '64',
-        0b11: '128',
-    },
-    # ORC[1:0]
-    'orc': {
-        0b00: '16',
-        0b01: '32',
-        0b10: '64',
-        0b11: '128',
-    },
-}
-
-class Decoder(srd.Decoder):
-    api_version = 1
-    id = 'mxc6225xu'
-    name = 'MXC6225XU'
-    longname = 'MEMSIC MXC6225XU'
-    desc = 'Digital Thermal Orientation Sensor (DTOS) protocol.'
-    license = 'gplv2+'
-    inputs = ['i2c']
-    outputs = ['mxc6225xu']
-    probes = []
-    optional_probes = [
-        {'id': 'int', 'name': 'INT', 'desc': 'DTOS interrupt output pin'},
-    ]
-    options = {}
-    annotations = [
-        ['Text', 'Human-readable text'],
-    ]
-
-    def __init__(self, **kwargs):
-        self.state = 'IDLE'
-
-    def start(self, metadata):
-        # self.out_proto = self.add(srd.OUTPUT_PROTO, 'mxc6225xu')
-        self.out_ann = self.add(srd.OUTPUT_ANN, 'mxc6225xu')
-
-    def report(self):
-        pass
-
-    def putx(self, data):
-        self.put(self.ss, self.es, self.out_ann, data)
-
-    def handle_reg_0x00(self, b):
-        # XOUT: 8-bit x-axis acceleration output.
-        # Data is in 2's complement, values range from -128 to 127.
-        self.putx([0, ['XOUT: %d' % b]])
-
-    def handle_reg_0x01(self, b):
-        # YOUT: 8-bit y-axis acceleration output.
-        # Data is in 2's complement, values range from -128 to 127.
-        self.putx([0, ['YOUT: %d' % b]])
-
-    def handle_reg_0x02(self, b):
-        # STATUS: Orientation and shake status.
-
-        # Bits[7:7]: INT
-        int_val = (b >> 7) & 1
-        s = 'unchanged and no' if (int_val == 0) else 'changed or'
-        ann = 'INT = %d: Orientation %s shake event occured\n' % (int_val, s)
-
-        # Bits[6:5]: SH[1:0]
-        sh = (((b >> 6) & 1) << 1) | ((b >> 5) & 1)
-        ann += 'SH[1:0] = %s: Shake event: %s\n' % \
-               (bin(sh)[2:], status['sh'][sh])
-
-        # Bits[4:4]: TILT
-        tilt = (b >> 4) & 1
-        s = '' if (tilt == 0) else 'not '
-        ann += 'TILT = %d: Orientation measurement is %svalid\n' % (tilt, s)
-
-        # Bits[3:2]: ORI[1:0]
-        ori = (((b >> 3) & 1) << 1) | ((b >> 2) & 1)
-        ann += 'ORI[1:0] = %s: %s\n' % (bin(ori)[2:], status['ori'][ori])
-
-        # Bits[1:0]: OR[1:0]
-        or_val = (((b >> 1) & 1) << 1) | ((b >> 0) & 1)
-        ann += 'OR[1:0] = %s: %s\n' % (bin(or_val)[2:], status['ori'][or_val])
-
-        # ann += 'b = %s\n' % (bin(b))
-
-        self.putx([0, [ann]])
-
-    def handle_reg_0x03(self, b):
-        # DETECTION: Powerdown, orientation and shake detection parameters.
-        # Note: This is a write-only register.
-
-        # Bits[7:7]: PD
-        pd = (b >> 7) & 1
-        s = 'Do not power down' if (pd == 0) else 'Power down'
-        ann = 'PD = %d: %s the device (into a low-power state)\n' % (pd, s)
-
-        # Bits[6:6]: SHM
-        shm = (b >> 6) & 1
-        ann = 'SHM = %d: Set shake mode to %d\n' % (shm, shm)
-
-        # Bits[5:4]: SHTH[1:0]
-        shth = (((b >> 5) & 1) << 1) | ((b >> 4) & 1)
-        ann += 'SHTH[1:0] = %s: Set shake threshold to %s\n' \
-               % (bin(shth)[2:], status['shth'][shth])
-
-        # Bits[3:2]: SHC[1:0]
-        shc = (((b >> 3) & 1) << 1) | ((b >> 2) & 1)
-        ann += 'SHC[1:0] = %s: Set shake count to %s readings\n' \
-               % (bin(shc)[2:], status['shc'][shc])
-
-        # Bits[1:0]: ORC[1:0]
-        orc = (((b >> 1) & 1) << 1) | ((b >> 0) & 1)
-        ann += 'ORC[1:0] = %s: Set orientation count to %s readings\n' \
-               % (bin(orc)[2:], status['orc'][orc])
-
-        self.putx([0, [ann]])
-
-    # TODO: Fixup, this is copy-pasted from another PD.
-    # TODO: Handle/check the ACKs/NACKs.
-    def decode(self, ss, es, data):
-        cmd, databyte = data
-
-        # Store the start/end samples of this I2C packet.
-        self.ss, self.es = ss, es
-
-        # State machine.
-        if self.state == 'IDLE':
-            # Wait for an I2C START condition.
-            if cmd != 'START':
-                return
-            self.state = 'GET SLAVE ADDR'
-            self.block_start_sample = ss
-        elif self.state == 'GET SLAVE ADDR':
-            # Wait for an address write operation.
-            # TODO: We should only handle packets to the slave(?)
-            if cmd != 'ADDRESS WRITE':
-                return
-            self.state = 'GET REG ADDR'
-        elif self.state == 'GET REG ADDR':
-            # Wait for a data write (master selects the slave register).
-            if cmd != 'DATA WRITE':
-                return
-            self.reg = databyte
-            self.state = 'WRITE REGS'
-        elif self.state == 'WRITE REGS':
-            # If we see a Repeated Start here, it's a multi-byte read.
-            if cmd == 'START REPEAT':
-                self.state = 'READ REGS'
-                return
-            # Otherwise: Get data bytes until a STOP condition occurs.
-            if cmd == 'DATA WRITE':
-                handle_reg = getattr(self, 'handle_reg_0x%02x' % self.reg)
-                handle_reg(databyte)
-                self.reg += 1
-                # TODO: Check for NACK!
-            elif cmd == 'STOP':
-                # TODO
-                self.state = 'IDLE'
-            else:
-                pass # TODO
-        elif self.state == 'READ REGS':
-            # Wait for an address read operation.
-            # TODO: We should only handle packets to the slave(?)
-            if cmd == 'ADDRESS READ':
-                self.state = 'READ REGS2'
-                return
-            else:
-                pass # TODO
-        elif self.state == 'READ REGS2':
-            if cmd == 'DATA READ':
-                handle_reg = getattr(self, 'handle_reg_0x%02x' % self.reg)
-                handle_reg(databyte)
-                self.reg += 1
-                # TODO: Check for NACK!
-            elif cmd == 'STOP':
-                # TODO
-                self.state = 'IDLE'
-            else:
-                pass # TODO?
-        else:
-            raise Exception('Invalid state: %d' % self.state)
-
diff --git a/decoders/mxc6225xu/pd.py b/decoders/mxc6225xu/pd.py
new file mode 100644 (file)
index 0000000..39564a9
--- /dev/null
@@ -0,0 +1,229 @@
+##
+## This file is part of the sigrok project.
+##
+## 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
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+##
+
+# MEMSIC MXC6225XU protocol decoder
+
+import sigrokdecode as srd
+
+# Definitions of various bits in MXC6225XU registers.
+status = {
+    # SH[1:0]
+    'sh': {
+        0b00: 'none',
+        0b01: 'shake left',
+        0b10: 'shake right',
+        0b11: 'undefined',
+    },
+    # ORI[1:0] and OR[1:0] (same format)
+    'ori': {
+        0b00: 'vertical in upright orientation',
+        0b01: 'rotated 90 degrees clockwise',
+        0b10: 'vertical in inverted orientation',
+        0b11: 'rotated 90 degrees counterclockwise',
+    },
+    # SHTH[1:0]
+    'shth': {
+        0b00: '0.5g',
+        0b01: '1.0g',
+        0b10: '1.5g',
+        0b11: '2.0g',
+    },
+    # SHC[1:0]
+    'shc': {
+        0b00: '16',
+        0b01: '32',
+        0b10: '64',
+        0b11: '128',
+    },
+    # ORC[1:0]
+    'orc': {
+        0b00: '16',
+        0b01: '32',
+        0b10: '64',
+        0b11: '128',
+    },
+}
+
+class Decoder(srd.Decoder):
+    api_version = 1
+    id = 'mxc6225xu'
+    name = 'MXC6225XU'
+    longname = 'MEMSIC MXC6225XU'
+    desc = 'Digital Thermal Orientation Sensor (DTOS) protocol.'
+    license = 'gplv2+'
+    inputs = ['i2c']
+    outputs = ['mxc6225xu']
+    probes = []
+    optional_probes = [
+        {'id': 'int', 'name': 'INT', 'desc': 'DTOS interrupt output pin'},
+    ]
+    options = {}
+    annotations = [
+        ['Text', 'Human-readable text'],
+    ]
+
+    def __init__(self, **kwargs):
+        self.state = 'IDLE'
+
+    def start(self, metadata):
+        # self.out_proto = self.add(srd.OUTPUT_PROTO, 'mxc6225xu')
+        self.out_ann = self.add(srd.OUTPUT_ANN, 'mxc6225xu')
+
+    def report(self):
+        pass
+
+    def putx(self, data):
+        self.put(self.ss, self.es, self.out_ann, data)
+
+    def handle_reg_0x00(self, b):
+        # XOUT: 8-bit x-axis acceleration output.
+        # Data is in 2's complement, values range from -128 to 127.
+        self.putx([0, ['XOUT: %d' % b]])
+
+    def handle_reg_0x01(self, b):
+        # YOUT: 8-bit y-axis acceleration output.
+        # Data is in 2's complement, values range from -128 to 127.
+        self.putx([0, ['YOUT: %d' % b]])
+
+    def handle_reg_0x02(self, b):
+        # STATUS: Orientation and shake status.
+
+        # Bits[7:7]: INT
+        int_val = (b >> 7) & 1
+        s = 'unchanged and no' if (int_val == 0) else 'changed or'
+        ann = 'INT = %d: Orientation %s shake event occured\n' % (int_val, s)
+
+        # Bits[6:5]: SH[1:0]
+        sh = (((b >> 6) & 1) << 1) | ((b >> 5) & 1)
+        ann += 'SH[1:0] = %s: Shake event: %s\n' % \
+               (bin(sh)[2:], status['sh'][sh])
+
+        # Bits[4:4]: TILT
+        tilt = (b >> 4) & 1
+        s = '' if (tilt == 0) else 'not '
+        ann += 'TILT = %d: Orientation measurement is %svalid\n' % (tilt, s)
+
+        # Bits[3:2]: ORI[1:0]
+        ori = (((b >> 3) & 1) << 1) | ((b >> 2) & 1)
+        ann += 'ORI[1:0] = %s: %s\n' % (bin(ori)[2:], status['ori'][ori])
+
+        # Bits[1:0]: OR[1:0]
+        or_val = (((b >> 1) & 1) << 1) | ((b >> 0) & 1)
+        ann += 'OR[1:0] = %s: %s\n' % (bin(or_val)[2:], status['ori'][or_val])
+
+        # ann += 'b = %s\n' % (bin(b))
+
+        self.putx([0, [ann]])
+
+    def handle_reg_0x03(self, b):
+        # DETECTION: Powerdown, orientation and shake detection parameters.
+        # Note: This is a write-only register.
+
+        # Bits[7:7]: PD
+        pd = (b >> 7) & 1
+        s = 'Do not power down' if (pd == 0) else 'Power down'
+        ann = 'PD = %d: %s the device (into a low-power state)\n' % (pd, s)
+
+        # Bits[6:6]: SHM
+        shm = (b >> 6) & 1
+        ann = 'SHM = %d: Set shake mode to %d\n' % (shm, shm)
+
+        # Bits[5:4]: SHTH[1:0]
+        shth = (((b >> 5) & 1) << 1) | ((b >> 4) & 1)
+        ann += 'SHTH[1:0] = %s: Set shake threshold to %s\n' \
+               % (bin(shth)[2:], status['shth'][shth])
+
+        # Bits[3:2]: SHC[1:0]
+        shc = (((b >> 3) & 1) << 1) | ((b >> 2) & 1)
+        ann += 'SHC[1:0] = %s: Set shake count to %s readings\n' \
+               % (bin(shc)[2:], status['shc'][shc])
+
+        # Bits[1:0]: ORC[1:0]
+        orc = (((b >> 1) & 1) << 1) | ((b >> 0) & 1)
+        ann += 'ORC[1:0] = %s: Set orientation count to %s readings\n' \
+               % (bin(orc)[2:], status['orc'][orc])
+
+        self.putx([0, [ann]])
+
+    # TODO: Fixup, this is copy-pasted from another PD.
+    # TODO: Handle/check the ACKs/NACKs.
+    def decode(self, ss, es, data):
+        cmd, databyte = data
+
+        # Store the start/end samples of this I2C packet.
+        self.ss, self.es = ss, es
+
+        # State machine.
+        if self.state == 'IDLE':
+            # Wait for an I2C START condition.
+            if cmd != 'START':
+                return
+            self.state = 'GET SLAVE ADDR'
+            self.block_start_sample = ss
+        elif self.state == 'GET SLAVE ADDR':
+            # Wait for an address write operation.
+            # TODO: We should only handle packets to the slave(?)
+            if cmd != 'ADDRESS WRITE':
+                return
+            self.state = 'GET REG ADDR'
+        elif self.state == 'GET REG ADDR':
+            # Wait for a data write (master selects the slave register).
+            if cmd != 'DATA WRITE':
+                return
+            self.reg = databyte
+            self.state = 'WRITE REGS'
+        elif self.state == 'WRITE REGS':
+            # If we see a Repeated Start here, it's a multi-byte read.
+            if cmd == 'START REPEAT':
+                self.state = 'READ REGS'
+                return
+            # Otherwise: Get data bytes until a STOP condition occurs.
+            if cmd == 'DATA WRITE':
+                handle_reg = getattr(self, 'handle_reg_0x%02x' % self.reg)
+                handle_reg(databyte)
+                self.reg += 1
+                # TODO: Check for NACK!
+            elif cmd == 'STOP':
+                # TODO
+                self.state = 'IDLE'
+            else:
+                pass # TODO
+        elif self.state == 'READ REGS':
+            # Wait for an address read operation.
+            # TODO: We should only handle packets to the slave(?)
+            if cmd == 'ADDRESS READ':
+                self.state = 'READ REGS2'
+                return
+            else:
+                pass # TODO
+        elif self.state == 'READ REGS2':
+            if cmd == 'DATA READ':
+                handle_reg = getattr(self, 'handle_reg_0x%02x' % self.reg)
+                handle_reg(databyte)
+                self.reg += 1
+                # TODO: Check for NACK!
+            elif cmd == 'STOP':
+                # TODO
+                self.state = 'IDLE'
+            else:
+                pass # TODO?
+        else:
+            raise Exception('Invalid state: %d' % self.state)
+
index 5a4917b786dc533280cec7dfce5f7b5960ea0ed2..7e3752226bc59bc62448e2ffa439807a2ebb30f7 100644 (file)
@@ -20,7 +20,7 @@
 
 pkgdatadir = $(DECODERS_DIR)/nunchuk
 
-dist_pkgdata_DATA = __init__.py nunchuk.py
+dist_pkgdata_DATA = __init__.py pd.py
 
 CLEANFILES = *.pyc
 
index 9b85374729718dd84e0b78ca19d21616c0697224..ac8e64b787447fa5db7f953414adaeef599ff4c1 100644 (file)
@@ -29,5 +29,5 @@ http://todbot.com/blog/2008/02/18/wiichuck-wii-nunchuck-adapter-available/
 https://www.sparkfun.com/products/9281
 '''
 
-from .nunchuk import *
+from .pd import *
 
diff --git a/decoders/nunchuk/nunchuk.py b/decoders/nunchuk/nunchuk.py
deleted file mode 100644 (file)
index 0dae39c..0000000
+++ /dev/null
@@ -1,206 +0,0 @@
-##
-## This file is part of the sigrok project.
-##
-## Copyright (C) 2010-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
-## the Free Software Foundation; either version 2 of the License, or
-## (at your option) any later version.
-##
-## This program is distributed in the hope that it will be useful,
-## but WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-## GNU General Public License for more details.
-##
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, write to the Free Software
-## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
-##
-
-# Nintendo Wii Nunchuk protocol decoder
-
-import sigrokdecode as srd
-
-class Decoder(srd.Decoder):
-    api_version = 1
-    id = 'nunchuk'
-    name = 'Nunchuk'
-    longname = 'Nintendo Wii Nunchuk'
-    desc = 'Nintendo Wii Nunchuk controller protocol.'
-    license = 'gplv2+'
-    inputs = ['i2c']
-    outputs = ['nunchuck']
-    probes = []
-    optional_probes = []
-    options = {}
-    annotations = [
-        ['Text (verbose)', 'Human-readable text (verbose)'],
-        ['Text', 'Human-readable text'],
-        ['Warnings', 'Human-readable warnings'],
-    ]
-
-    def __init__(self, **kwargs):
-        self.state = 'IDLE'
-        self.sx = self.sy = self.ax = self.ay = self.az = self.bz = self.bc = -1
-        self.databytecount = 0
-        self.reg = 0x00
-        self.init_seq = []
-
-    def start(self, metadata):
-        # self.out_proto = self.add(srd.OUTPUT_PROTO, 'nunchuk')
-        self.out_ann = self.add(srd.OUTPUT_ANN, 'nunchuk')
-
-    def report(self):
-        pass
-
-    def putx(self, data):
-        # Helper for annotations which span exactly one I2C packet.
-        self.put(self.ss, self.es, self.out_ann, data)
-
-    def putb(self, data):
-        # Helper for annotations which span a block of I2C packets.
-        self.put(self.block_start_sample, self.block_end_sample,
-                 self.out_ann, data)
-
-    def handle_reg_0x00(self, databyte):
-        self.sx = databyte
-        self.putx([0, ['Analog stick X position: 0x%02x' % self.sx]])
-        self.putx([1, ['SX: 0x%02x' % self.sx]])
-
-    def handle_reg_0x01(self, databyte):
-        self.sy = databyte
-        self.putx([0, ['Analog stick Y position: 0x%02x' % self.sy]])
-        self.putx([1, ['SY: 0x%02x' % self.sy]])
-
-    def handle_reg_0x02(self, databyte):
-        self.ax = databyte << 2
-        self.putx([0, ['Accelerometer X value bits[9:2]: 0x%03x' % self.ax]])
-        self.putx([1, ['AX[9:2]: 0x%03x' % self.ax]])
-
-    def handle_reg_0x03(self, databyte):
-        self.ay = databyte << 2
-        self.putx([0, ['Accelerometer Y value bits[9:2]: 0x%03x' % self.ay]])
-        self.putx([1, ['AY[9:2]: 0x%x' % self.ay]])
-
-    def handle_reg_0x04(self, databyte):
-        self.az = databyte << 2
-        self.putx([0, ['Accelerometer Z value bits[9:2]: 0x%03x' % self.az]])
-        self.putx([1, ['AZ[9:2]: 0x%x' % self.az]])
-
-    # TODO: Bit-exact annotations.
-    def handle_reg_0x05(self, databyte):
-        self.bz = (databyte & (1 << 0)) >> 0 # Bits[0:0]
-        self.bc = (databyte & (1 << 1)) >> 1 # Bits[1:1]
-        ax_rest = (databyte & (3 << 2)) >> 2 # Bits[3:2]
-        ay_rest = (databyte & (3 << 4)) >> 4 # Bits[5:4]
-        az_rest = (databyte & (3 << 6)) >> 6 # Bits[7:6]
-        self.ax |= ax_rest
-        self.ay |= ay_rest
-        self.az |= az_rest
-
-        s = '' if (self.bz == 0) else 'not '
-        self.putx([0, ['Z button: %spressed' % s]])
-        self.putx([1, ['BZ: %d' % self.bz]])
-
-        s = '' if (self.bc == 0) else 'not '
-        self.putx([0, ['C button: %spressed' % s]])
-        self.putx([1, ['BC: %d' % self.bc]])
-
-        self.putx([0, ['Accelerometer X value bits[1:0]: 0x%x' % ax_rest]])
-        self.putx([1, ['AX[1:0]: 0x%x' % ax_rest]])
-
-        self.putx([0, ['Accelerometer Y value bits[1:0]: 0x%x' % ay_rest]])
-        self.putx([1, ['AY[1:0]: 0x%x' % ay_rest]])
-
-        self.putx([0, ['Accelerometer Z value bits[1:0]: 0x%x' % az_rest]])
-        self.putx([1, ['AZ[1:0]: 0x%x' % az_rest]])
-
-    def output_full_block_if_possible(self):
-        # For now, only output summary annotation if all values are available.
-        t = (self.sx, self.sy, self.ax, self.ay, self.az, self.bz, self.bc)
-        if -1 in t:
-            return
-
-        s = 'Analog stick X position: 0x%02x\n' % self.sx
-        s += 'Analog stick Y position: 0x%02x\n' % self.sy
-        s += 'Z button: %spressed\n' % ('' if (self.bz == 0) else 'not ')
-        s += 'C button: %spressed\n' % ('' if (self.bc == 0) else 'not ')
-        s += 'Accelerometer X value: 0x%03x\n' % self.ax
-        s += 'Accelerometer Y value: 0x%03x\n' % self.ay
-        s += 'Accelerometer Z value: 0x%03x\n' % self.az
-        self.put(self.block_start_sample, self.block_end_sample,
-                 self.out_ann, [0, [s]])
-
-        s = 'SX = 0x%02x, SY = 0x%02x, AX = 0x%02x, AY = 0x%02x, ' \
-            'AZ = 0x%02x, BZ = 0x%02x, BC = 0x%02x' % (self.sx, \
-            self.sy, self.ax, self.ay, self.az, self.bz, self.bc)
-        self.put(self.block_start_sample, self.block_end_sample,
-                 self.out_ann, [1, [s]])
-
-    def handle_reg_write(self, databyte):
-        self.putx([0, ['Nunchuk write: 0x%02x' % databyte]])
-        if len(self.init_seq) < 2:
-            self.init_seq.append(databyte)
-
-    def output_init_seq(self):
-        if len(self.init_seq) != 2:
-            self.putb([2, ['Init sequence was %d bytes long (2 expected)' % \
-                      len(self.init_seq)]])
-
-        if self.init_seq != (0x40, 0x00):
-            self.putb([2, ['Unknown init sequence (expected: 0x40 0x00)']])
-
-        # TODO: Detect Nunchuk clones (they have different init sequences).
-        s = 'Initialized Nintendo Wii Nunchuk'
-
-        self.putb([0, [s]])
-        self.putb([1, ['INIT']])
-
-    def decode(self, ss, es, data):
-        cmd, databyte = data
-
-        # Store the start/end samples of this I2C packet.
-        self.ss, self.es = ss, es
-
-        # State machine.
-        if self.state == 'IDLE':
-            # Wait for an I2C START condition.
-            if cmd != 'START':
-                return
-            self.state = 'GET SLAVE ADDR'
-            self.block_start_sample = ss
-        elif self.state == 'GET SLAVE ADDR':
-            # Wait for an address read/write operation.
-            if cmd == 'ADDRESS READ':
-                self.state = 'READ REGS'
-            elif cmd == 'ADDRESS WRITE':
-                self.state = 'WRITE REGS'
-        elif self.state == 'READ REGS':
-            if cmd == 'DATA READ':
-                handle_reg = getattr(self, 'handle_reg_0x%02x' % self.reg)
-                handle_reg(databyte)
-                self.reg += 1
-            elif cmd == 'STOP':
-                self.block_end_sample = es
-                self.output_full_block_if_possible()
-                self.sx = self.sy = self.ax = self.ay = self.az = -1
-                self.bz = self.bc = -1
-                self.state = 'IDLE'
-            else:
-                # self.putx([0, ['Ignoring: %s (data=%s)' % (cmd, databyte)]])
-                pass
-        elif self.state == 'WRITE REGS':
-            if cmd == 'DATA WRITE':
-                self.handle_reg_write(databyte)
-            elif cmd == 'STOP':
-                self.block_end_sample = es
-                self.output_init_seq()
-                self.init_seq = []
-                self.state = 'IDLE'
-            else:
-                # self.putx([0, ['Ignoring: %s (data=%s)' % (cmd, databyte)]])
-                pass
-        else:
-            raise Exception('Invalid state: %s' % self.state)
-
diff --git a/decoders/nunchuk/pd.py b/decoders/nunchuk/pd.py
new file mode 100644 (file)
index 0000000..0dae39c
--- /dev/null
@@ -0,0 +1,206 @@
+##
+## This file is part of the sigrok project.
+##
+## Copyright (C) 2010-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
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+##
+
+# Nintendo Wii Nunchuk protocol decoder
+
+import sigrokdecode as srd
+
+class Decoder(srd.Decoder):
+    api_version = 1
+    id = 'nunchuk'
+    name = 'Nunchuk'
+    longname = 'Nintendo Wii Nunchuk'
+    desc = 'Nintendo Wii Nunchuk controller protocol.'
+    license = 'gplv2+'
+    inputs = ['i2c']
+    outputs = ['nunchuck']
+    probes = []
+    optional_probes = []
+    options = {}
+    annotations = [
+        ['Text (verbose)', 'Human-readable text (verbose)'],
+        ['Text', 'Human-readable text'],
+        ['Warnings', 'Human-readable warnings'],
+    ]
+
+    def __init__(self, **kwargs):
+        self.state = 'IDLE'
+        self.sx = self.sy = self.ax = self.ay = self.az = self.bz = self.bc = -1
+        self.databytecount = 0
+        self.reg = 0x00
+        self.init_seq = []
+
+    def start(self, metadata):
+        # self.out_proto = self.add(srd.OUTPUT_PROTO, 'nunchuk')
+        self.out_ann = self.add(srd.OUTPUT_ANN, 'nunchuk')
+
+    def report(self):
+        pass
+
+    def putx(self, data):
+        # Helper for annotations which span exactly one I2C packet.
+        self.put(self.ss, self.es, self.out_ann, data)
+
+    def putb(self, data):
+        # Helper for annotations which span a block of I2C packets.
+        self.put(self.block_start_sample, self.block_end_sample,
+                 self.out_ann, data)
+
+    def handle_reg_0x00(self, databyte):
+        self.sx = databyte
+        self.putx([0, ['Analog stick X position: 0x%02x' % self.sx]])
+        self.putx([1, ['SX: 0x%02x' % self.sx]])
+
+    def handle_reg_0x01(self, databyte):
+        self.sy = databyte
+        self.putx([0, ['Analog stick Y position: 0x%02x' % self.sy]])
+        self.putx([1, ['SY: 0x%02x' % self.sy]])
+
+    def handle_reg_0x02(self, databyte):
+        self.ax = databyte << 2
+        self.putx([0, ['Accelerometer X value bits[9:2]: 0x%03x' % self.ax]])
+        self.putx([1, ['AX[9:2]: 0x%03x' % self.ax]])
+
+    def handle_reg_0x03(self, databyte):
+        self.ay = databyte << 2
+        self.putx([0, ['Accelerometer Y value bits[9:2]: 0x%03x' % self.ay]])
+        self.putx([1, ['AY[9:2]: 0x%x' % self.ay]])
+
+    def handle_reg_0x04(self, databyte):
+        self.az = databyte << 2
+        self.putx([0, ['Accelerometer Z value bits[9:2]: 0x%03x' % self.az]])
+        self.putx([1, ['AZ[9:2]: 0x%x' % self.az]])
+
+    # TODO: Bit-exact annotations.
+    def handle_reg_0x05(self, databyte):
+        self.bz = (databyte & (1 << 0)) >> 0 # Bits[0:0]
+        self.bc = (databyte & (1 << 1)) >> 1 # Bits[1:1]
+        ax_rest = (databyte & (3 << 2)) >> 2 # Bits[3:2]
+        ay_rest = (databyte & (3 << 4)) >> 4 # Bits[5:4]
+        az_rest = (databyte & (3 << 6)) >> 6 # Bits[7:6]
+        self.ax |= ax_rest
+        self.ay |= ay_rest
+        self.az |= az_rest
+
+        s = '' if (self.bz == 0) else 'not '
+        self.putx([0, ['Z button: %spressed' % s]])
+        self.putx([1, ['BZ: %d' % self.bz]])
+
+        s = '' if (self.bc == 0) else 'not '
+        self.putx([0, ['C button: %spressed' % s]])
+        self.putx([1, ['BC: %d' % self.bc]])
+
+        self.putx([0, ['Accelerometer X value bits[1:0]: 0x%x' % ax_rest]])
+        self.putx([1, ['AX[1:0]: 0x%x' % ax_rest]])
+
+        self.putx([0, ['Accelerometer Y value bits[1:0]: 0x%x' % ay_rest]])
+        self.putx([1, ['AY[1:0]: 0x%x' % ay_rest]])
+
+        self.putx([0, ['Accelerometer Z value bits[1:0]: 0x%x' % az_rest]])
+        self.putx([1, ['AZ[1:0]: 0x%x' % az_rest]])
+
+    def output_full_block_if_possible(self):
+        # For now, only output summary annotation if all values are available.
+        t = (self.sx, self.sy, self.ax, self.ay, self.az, self.bz, self.bc)
+        if -1 in t:
+            return
+
+        s = 'Analog stick X position: 0x%02x\n' % self.sx
+        s += 'Analog stick Y position: 0x%02x\n' % self.sy
+        s += 'Z button: %spressed\n' % ('' if (self.bz == 0) else 'not ')
+        s += 'C button: %spressed\n' % ('' if (self.bc == 0) else 'not ')
+        s += 'Accelerometer X value: 0x%03x\n' % self.ax
+        s += 'Accelerometer Y value: 0x%03x\n' % self.ay
+        s += 'Accelerometer Z value: 0x%03x\n' % self.az
+        self.put(self.block_start_sample, self.block_end_sample,
+                 self.out_ann, [0, [s]])
+
+        s = 'SX = 0x%02x, SY = 0x%02x, AX = 0x%02x, AY = 0x%02x, ' \
+            'AZ = 0x%02x, BZ = 0x%02x, BC = 0x%02x' % (self.sx, \
+            self.sy, self.ax, self.ay, self.az, self.bz, self.bc)
+        self.put(self.block_start_sample, self.block_end_sample,
+                 self.out_ann, [1, [s]])
+
+    def handle_reg_write(self, databyte):
+        self.putx([0, ['Nunchuk write: 0x%02x' % databyte]])
+        if len(self.init_seq) < 2:
+            self.init_seq.append(databyte)
+
+    def output_init_seq(self):
+        if len(self.init_seq) != 2:
+            self.putb([2, ['Init sequence was %d bytes long (2 expected)' % \
+                      len(self.init_seq)]])
+
+        if self.init_seq != (0x40, 0x00):
+            self.putb([2, ['Unknown init sequence (expected: 0x40 0x00)']])
+
+        # TODO: Detect Nunchuk clones (they have different init sequences).
+        s = 'Initialized Nintendo Wii Nunchuk'
+
+        self.putb([0, [s]])
+        self.putb([1, ['INIT']])
+
+    def decode(self, ss, es, data):
+        cmd, databyte = data
+
+        # Store the start/end samples of this I2C packet.
+        self.ss, self.es = ss, es
+
+        # State machine.
+        if self.state == 'IDLE':
+            # Wait for an I2C START condition.
+            if cmd != 'START':
+                return
+            self.state = 'GET SLAVE ADDR'
+            self.block_start_sample = ss
+        elif self.state == 'GET SLAVE ADDR':
+            # Wait for an address read/write operation.
+            if cmd == 'ADDRESS READ':
+                self.state = 'READ REGS'
+            elif cmd == 'ADDRESS WRITE':
+                self.state = 'WRITE REGS'
+        elif self.state == 'READ REGS':
+            if cmd == 'DATA READ':
+                handle_reg = getattr(self, 'handle_reg_0x%02x' % self.reg)
+                handle_reg(databyte)
+                self.reg += 1
+            elif cmd == 'STOP':
+                self.block_end_sample = es
+                self.output_full_block_if_possible()
+                self.sx = self.sy = self.ax = self.ay = self.az = -1
+                self.bz = self.bc = -1
+                self.state = 'IDLE'
+            else:
+                # self.putx([0, ['Ignoring: %s (data=%s)' % (cmd, databyte)]])
+                pass
+        elif self.state == 'WRITE REGS':
+            if cmd == 'DATA WRITE':
+                self.handle_reg_write(databyte)
+            elif cmd == 'STOP':
+                self.block_end_sample = es
+                self.output_init_seq()
+                self.init_seq = []
+                self.state = 'IDLE'
+            else:
+                # self.putx([0, ['Ignoring: %s (data=%s)' % (cmd, databyte)]])
+                pass
+        else:
+            raise Exception('Invalid state: %s' % self.state)
+
index b043eca77fde0b5c6518b273f2cb2a6849b85bbf..f949f4c14a815c5093af84324ca8bd05bbc48cf1 100644 (file)
@@ -20,7 +20,7 @@
 
 pkgdatadir = $(DECODERS_DIR)/onewire_link
 
-dist_pkgdata_DATA = __init__.py onewire_link.py
+dist_pkgdata_DATA = __init__.py pd.py
 
 CLEANFILES = *.pyc
 
index cb0347170958b385212fa5960d13bda3f844d234..c1331c6322d1d6988170816f67c8896c3d9f47a9 100644 (file)
@@ -87,5 +87,5 @@ TODO:
 - Maybe add support for interrupts, check if this feature is deprecated.
 '''
 
-from .onewire_link import *
+from .pd import *
 
diff --git a/decoders/onewire_link/onewire_link.py b/decoders/onewire_link/onewire_link.py
deleted file mode 100644 (file)
index c8bda56..0000000
+++ /dev/null
@@ -1,269 +0,0 @@
-##
-## This file is part of the sigrok project.
-##
-## Copyright (C) 2012 Iztok Jeras <iztok.jeras@gmail.com>
-##
-## 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
-## the Free Software Foundation; either version 2 of the License, or
-## (at your option) any later version.
-##
-## This program is distributed in the hope that it will be useful,
-## but WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-## GNU General Public License for more details.
-##
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, write to the Free Software
-## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
-##
-
-# 1-Wire protocol decoder (link layer)
-
-import sigrokdecode as srd
-
-class Decoder(srd.Decoder):
-    api_version = 1
-    id = 'onewire_link'
-    name = '1-Wire link layer'
-    longname = '1-Wire serial communication bus (link layer)'
-    desc = 'Bidirectional, half-duplex, asynchronous serial bus.'
-    license = 'gplv2+'
-    inputs = ['logic']
-    outputs = ['onewire_link']
-    probes = [
-        {'id': 'owr', 'name': 'OWR', 'desc': '1-Wire signal line'},
-    ]
-    optional_probes = [
-        {'id': 'pwr', 'name': 'PWR', 'desc': '1-Wire power supply pin'},
-    ]
-    options = {
-        'overdrive': ['Overdrive', 1],
-        # Time options (specified in number of samplerate periods):
-        'cnt_normal_bit': ['Normal mode sample bit time', 0],
-        'cnt_normal_slot': ['Normal mode data slot time', 0],
-        'cnt_normal_presence': ['Normal mode sample presence time', 0],
-        'cnt_normal_reset': ['Normal mode reset time', 0],
-        'cnt_overdrive_bit': ['Overdrive mode sample bit time', 0],
-        'cnt_overdrive_slot': ['Overdrive mode data slot time', 0],
-        'cnt_overdrive_presence': ['Overdrive mode sample presence time', 0],
-        'cnt_overdrive_reset': ['Overdrive mode reset time', 0],
-    }
-    annotations = [
-        ['Text', 'Human-readable text'],
-        ['Warnings', 'Human-readable warnings'],
-    ]
-
-    def __init__(self, **kwargs):
-        self.samplenum = 0
-        self.state = 'WAIT FOR FALLING EDGE'
-        self.present = 0
-        self.bit = 0
-        self.bit_cnt = 0
-        self.command = 0
-        self.overdrive = 0
-        self.fall = 0
-        self.rise = 0
-
-    def start(self, metadata):
-        self.out_proto = self.add(srd.OUTPUT_PROTO, 'onewire_link')
-        self.out_ann = self.add(srd.OUTPUT_ANN, 'onewire_link')
-
-        self.samplerate = metadata['samplerate']
-
-        # Check if samplerate is appropriate.
-        if self.options['overdrive']:
-            if self.samplerate < 2000000:
-                self.put(0, 0, self.out_ann, [1,
-                    ['ERROR: Sampling rate is too low. Must be above 2MHz ' +
-                     'for proper overdrive mode decoding.']])
-            elif self.samplerate < 5000000:
-                self.put(0, 0, self.out_ann, [1,
-                  ['WARNING: Sampling rate is suggested to be above 5MHz ' +
-                   'for proper overdrive mode decoding.']])
-        else:
-            if self.samplerate < 400000:
-                self.put(0, 0, self.out_ann, [1,
-                    ['ERROR: Sampling rate is too low. Must be above ' +
-                     '400kHz for proper normal mode decoding.']])
-            elif (self.samplerate < 1000000):
-                self.put(0, 0, self.out_ann, [1,
-                    ['WARNING: Sampling rate is suggested to be above ' +
-                     '1MHz for proper normal mode decoding.']])
-
-        # The default 1-Wire time base is 30us. This is used to calculate
-        # sampling times.
-        samplerate = float(self.samplerate)
-        if self.options['cnt_normal_bit']:
-            self.cnt_normal_bit = self.options['cnt_normal_bit']
-        else:
-            self.cnt_normal_bit = int(samplerate * 0.000015) - 1 # 15ns
-        if self.options['cnt_normal_slot']:
-            self.cnt_normal_slot = self.options['cnt_normal_slot']
-        else:
-            self.cnt_normal_slot = int(samplerate * 0.000060) - 1 # 60ns
-        if self.options['cnt_normal_presence']:
-            self.cnt_normal_presence = self.options['cnt_normal_presence']
-        else:
-            self.cnt_normal_presence = int(samplerate * 0.000075) - 1 # 75ns
-        if self.options['cnt_normal_reset']:
-            self.cnt_normal_reset = self.options['cnt_normal_reset']
-        else:
-            self.cnt_normal_reset = int(samplerate * 0.000480) - 1 # 480ns
-        if self.options['cnt_overdrive_bit']:
-            self.cnt_overdrive_bit = self.options['cnt_overdrive_bit']
-        else:
-            self.cnt_overdrive_bit = int(samplerate * 0.000002) - 1 # 2ns
-        if self.options['cnt_overdrive_slot']:
-            self.cnt_overdrive_slot = self.options['cnt_overdrive_slot']
-        else:
-            self.cnt_overdrive_slot = int(samplerate * 0.0000073) - 1 # 6ns+1.3ns
-        if self.options['cnt_overdrive_presence']:
-            self.cnt_overdrive_presence = self.options['cnt_overdrive_presence']
-        else:
-            self.cnt_overdrive_presence = int(samplerate * 0.000010) - 1 # 10ns
-        if self.options['cnt_overdrive_reset']:
-            self.cnt_overdrive_reset = self.options['cnt_overdrive_reset']
-        else:
-            self.cnt_overdrive_reset = int(samplerate * 0.000048) - 1 # 48ns
-
-        # Organize values into lists.
-        self.cnt_bit = [self.cnt_normal_bit, self.cnt_overdrive_bit]
-        self.cnt_presence = [self.cnt_normal_presence, self.cnt_overdrive_presence]
-        self.cnt_reset = [self.cnt_normal_reset, self.cnt_overdrive_reset]
-        self.cnt_slot = [self.cnt_normal_slot, self.cnt_overdrive_slot]
-
-        # Check if sample times are in the allowed range.
-
-        time_min = float(self.cnt_normal_bit) / self.samplerate
-        time_max = float(self.cnt_normal_bit + 1) / self.samplerate
-        if (time_min < 0.000005) or (time_max > 0.000015):
-            self.put(0, 0, self.out_ann, [1,
-                ['WARNING: The normal mode data sample time interval ' +
-                 '(%2.1fus-%2.1fus) should be inside (5.0us, 15.0us).'
-                 % (time_min * 1000000, time_max * 1000000)]])
-
-        time_min = float(self.cnt_normal_presence) / self.samplerate
-        time_max = float(self.cnt_normal_presence + 1) / self.samplerate
-        if (time_min < 0.0000681) or (time_max > 0.000075):
-            self.put(0, 0, self.out_ann, [1,
-                ['WARNING: The normal mode presence sample time interval ' +
-                 '(%2.1fus-%2.1fus) should be inside (68.1us, 75.0us).'
-                 % (time_min * 1000000, time_max * 1000000)]])
-
-        time_min = float(self.cnt_overdrive_bit) / self.samplerate
-        time_max = float(self.cnt_overdrive_bit + 1) / self.samplerate
-        if (time_min < 0.000001) or (time_max > 0.000002):
-            self.put(0, 0, self.out_ann, [1,
-                ['WARNING: The overdrive mode data sample time interval ' +
-                 '(%2.1fus-%2.1fus) should be inside (1.0us, 2.0us).'
-                 % (time_min * 1000000, time_max * 1000000)]])
-
-        time_min = float(self.cnt_overdrive_presence) / self.samplerate
-        time_max = float(self.cnt_overdrive_presence + 1) / self.samplerate
-        if (time_min < 0.0000073) or (time_max > 0.000010):
-            self.put(0, 0, self.out_ann, [1,
-                ['WARNING: The overdrive mode presence sample time interval ' +
-                 '(%2.1fus-%2.1fus) should be inside (7.3us, 10.0us).'
-                 % (time_min*1000000, time_max*1000000)]])
-
-    def report(self):
-        pass
-
-    def decode(self, ss, es, data):
-        for (self.samplenum, (owr, pwr)) in data:
-            # State machine.
-            if self.state == 'WAIT FOR FALLING EDGE':
-                # The start of a cycle is a falling edge.
-                if owr != 0:
-                    continue
-                # Save the sample number for the falling edge.
-                self.fall = self.samplenum
-                # Go to waiting for sample time.
-                self.state = 'WAIT FOR DATA SAMPLE'
-            elif self.state == 'WAIT FOR DATA SAMPLE':
-                # Sample data bit.
-                t = self.samplenum - self.fall
-                if t == self.cnt_bit[self.overdrive]:
-                    self.bit = owr
-                    self.state = 'WAIT FOR DATA SLOT END'
-            elif self.state == 'WAIT FOR DATA SLOT END':
-                # A data slot ends in a recovery period, otherwise, this is
-                # probably a reset.
-                t = self.samplenum - self.fall
-                if t != self.cnt_slot[self.overdrive]:
-                    continue
-
-                if owr == 0:
-                    # This seems to be a reset slot, wait for its end.
-                    self.state = 'WAIT FOR RISING EDGE'
-                    continue
-
-                self.put(self.fall, self.samplenum, self.out_ann,
-                         [0, ['Bit: %d' % self.bit]])
-                self.put(self.fall, self.samplenum, self.out_proto,
-                         ['BIT', self.bit])
-
-                # Checking the first command to see if overdrive mode
-                # should be entered.
-                if self.bit_cnt <= 8:
-                    self.command |= (self.bit << self.bit_cnt)
-                elif self.bit_cnt == 8 and self.command in [0x3c, 0x69]:
-                    self.put(self.fall, self.cnt_bit[self.overdrive],
-                             self.out_ann, [0, ['Entering overdrive mode']])
-                # Increment the bit counter.
-                self.bit_cnt += 1
-                # Wait for next slot.
-                self.state = 'WAIT FOR FALLING EDGE'
-            elif self.state == 'WAIT FOR RISING EDGE':
-                # The end of a cycle is a rising edge.
-                if owr != 1:
-                    continue
-
-                # Check if this was a reset cycle.
-                t = self.samplenum - self.fall
-                if t > self.cnt_normal_reset:
-                    # Save the sample number for the falling edge.
-                    self.rise = self.samplenum
-                    self.state = 'WAIT FOR PRESENCE DETECT'
-                    # Exit overdrive mode.
-                    if self.overdrive:
-                        self.put(self.fall, self.cnt_bit[self.overdrive],
-                                 self.out_ann, [0, ['Exiting overdrive mode']])
-                        self.overdrive = 0
-                    # Clear command bit counter and data register.
-                    self.bit_cnt = 0
-                    self.command = 0
-                elif (t > self.cnt_overdrive_reset) and self.overdrive:
-                    # Save the sample number for the falling edge.
-                    self.rise = self.samplenum
-                    self.state = "WAIT FOR PRESENCE DETECT"
-                # Otherwise this is assumed to be a data bit.
-                else:
-                    self.state = "WAIT FOR FALLING EDGE"
-            elif self.state == 'WAIT FOR PRESENCE DETECT':
-                # Sample presence status.
-                t = self.samplenum - self.rise
-                if t == self.cnt_presence[self.overdrive]:
-                    self.present = owr
-                    self.state = 'WAIT FOR RESET SLOT END'
-            elif self.state == 'WAIT FOR RESET SLOT END':
-                # A reset slot ends in a long recovery period.
-                t = self.samplenum - self.rise
-                if t != self.cnt_reset[self.overdrive]:
-                    continue
-
-                if owr == 0:
-                    # This seems to be a reset slot, wait for its end.
-                    self.state = 'WAIT FOR RISING EDGE'
-                    continue
-
-                self.put(self.fall, self.samplenum, self.out_ann,
-                         [0, ['Reset/presence: %s'
-                         % ('false' if self.present else 'true')]])
-                self.put(self.fall, self.samplenum, self.out_proto,
-                         ['RESET/PRESENCE', not self.present])
-                # Wait for next slot.
-                self.state = 'WAIT FOR FALLING EDGE'
-            else:
-                raise Exception('Invalid state: %s' % self.state)
diff --git a/decoders/onewire_link/pd.py b/decoders/onewire_link/pd.py
new file mode 100644 (file)
index 0000000..c8bda56
--- /dev/null
@@ -0,0 +1,269 @@
+##
+## This file is part of the sigrok project.
+##
+## Copyright (C) 2012 Iztok Jeras <iztok.jeras@gmail.com>
+##
+## 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
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+##
+
+# 1-Wire protocol decoder (link layer)
+
+import sigrokdecode as srd
+
+class Decoder(srd.Decoder):
+    api_version = 1
+    id = 'onewire_link'
+    name = '1-Wire link layer'
+    longname = '1-Wire serial communication bus (link layer)'
+    desc = 'Bidirectional, half-duplex, asynchronous serial bus.'
+    license = 'gplv2+'
+    inputs = ['logic']
+    outputs = ['onewire_link']
+    probes = [
+        {'id': 'owr', 'name': 'OWR', 'desc': '1-Wire signal line'},
+    ]
+    optional_probes = [
+        {'id': 'pwr', 'name': 'PWR', 'desc': '1-Wire power supply pin'},
+    ]
+    options = {
+        'overdrive': ['Overdrive', 1],
+        # Time options (specified in number of samplerate periods):
+        'cnt_normal_bit': ['Normal mode sample bit time', 0],
+        'cnt_normal_slot': ['Normal mode data slot time', 0],
+        'cnt_normal_presence': ['Normal mode sample presence time', 0],
+        'cnt_normal_reset': ['Normal mode reset time', 0],
+        'cnt_overdrive_bit': ['Overdrive mode sample bit time', 0],
+        'cnt_overdrive_slot': ['Overdrive mode data slot time', 0],
+        'cnt_overdrive_presence': ['Overdrive mode sample presence time', 0],
+        'cnt_overdrive_reset': ['Overdrive mode reset time', 0],
+    }
+    annotations = [
+        ['Text', 'Human-readable text'],
+        ['Warnings', 'Human-readable warnings'],
+    ]
+
+    def __init__(self, **kwargs):
+        self.samplenum = 0
+        self.state = 'WAIT FOR FALLING EDGE'
+        self.present = 0
+        self.bit = 0
+        self.bit_cnt = 0
+        self.command = 0
+        self.overdrive = 0
+        self.fall = 0
+        self.rise = 0
+
+    def start(self, metadata):
+        self.out_proto = self.add(srd.OUTPUT_PROTO, 'onewire_link')
+        self.out_ann = self.add(srd.OUTPUT_ANN, 'onewire_link')
+
+        self.samplerate = metadata['samplerate']
+
+        # Check if samplerate is appropriate.
+        if self.options['overdrive']:
+            if self.samplerate < 2000000:
+                self.put(0, 0, self.out_ann, [1,
+                    ['ERROR: Sampling rate is too low. Must be above 2MHz ' +
+                     'for proper overdrive mode decoding.']])
+            elif self.samplerate < 5000000:
+                self.put(0, 0, self.out_ann, [1,
+                  ['WARNING: Sampling rate is suggested to be above 5MHz ' +
+                   'for proper overdrive mode decoding.']])
+        else:
+            if self.samplerate < 400000:
+                self.put(0, 0, self.out_ann, [1,
+                    ['ERROR: Sampling rate is too low. Must be above ' +
+                     '400kHz for proper normal mode decoding.']])
+            elif (self.samplerate < 1000000):
+                self.put(0, 0, self.out_ann, [1,
+                    ['WARNING: Sampling rate is suggested to be above ' +
+                     '1MHz for proper normal mode decoding.']])
+
+        # The default 1-Wire time base is 30us. This is used to calculate
+        # sampling times.
+        samplerate = float(self.samplerate)
+        if self.options['cnt_normal_bit']:
+            self.cnt_normal_bit = self.options['cnt_normal_bit']
+        else:
+            self.cnt_normal_bit = int(samplerate * 0.000015) - 1 # 15ns
+        if self.options['cnt_normal_slot']:
+            self.cnt_normal_slot = self.options['cnt_normal_slot']
+        else:
+            self.cnt_normal_slot = int(samplerate * 0.000060) - 1 # 60ns
+        if self.options['cnt_normal_presence']:
+            self.cnt_normal_presence = self.options['cnt_normal_presence']
+        else:
+            self.cnt_normal_presence = int(samplerate * 0.000075) - 1 # 75ns
+        if self.options['cnt_normal_reset']:
+            self.cnt_normal_reset = self.options['cnt_normal_reset']
+        else:
+            self.cnt_normal_reset = int(samplerate * 0.000480) - 1 # 480ns
+        if self.options['cnt_overdrive_bit']:
+            self.cnt_overdrive_bit = self.options['cnt_overdrive_bit']
+        else:
+            self.cnt_overdrive_bit = int(samplerate * 0.000002) - 1 # 2ns
+        if self.options['cnt_overdrive_slot']:
+            self.cnt_overdrive_slot = self.options['cnt_overdrive_slot']
+        else:
+            self.cnt_overdrive_slot = int(samplerate * 0.0000073) - 1 # 6ns+1.3ns
+        if self.options['cnt_overdrive_presence']:
+            self.cnt_overdrive_presence = self.options['cnt_overdrive_presence']
+        else:
+            self.cnt_overdrive_presence = int(samplerate * 0.000010) - 1 # 10ns
+        if self.options['cnt_overdrive_reset']:
+            self.cnt_overdrive_reset = self.options['cnt_overdrive_reset']
+        else:
+            self.cnt_overdrive_reset = int(samplerate * 0.000048) - 1 # 48ns
+
+        # Organize values into lists.
+        self.cnt_bit = [self.cnt_normal_bit, self.cnt_overdrive_bit]
+        self.cnt_presence = [self.cnt_normal_presence, self.cnt_overdrive_presence]
+        self.cnt_reset = [self.cnt_normal_reset, self.cnt_overdrive_reset]
+        self.cnt_slot = [self.cnt_normal_slot, self.cnt_overdrive_slot]
+
+        # Check if sample times are in the allowed range.
+
+        time_min = float(self.cnt_normal_bit) / self.samplerate
+        time_max = float(self.cnt_normal_bit + 1) / self.samplerate
+        if (time_min < 0.000005) or (time_max > 0.000015):
+            self.put(0, 0, self.out_ann, [1,
+                ['WARNING: The normal mode data sample time interval ' +
+                 '(%2.1fus-%2.1fus) should be inside (5.0us, 15.0us).'
+                 % (time_min * 1000000, time_max * 1000000)]])
+
+        time_min = float(self.cnt_normal_presence) / self.samplerate
+        time_max = float(self.cnt_normal_presence + 1) / self.samplerate
+        if (time_min < 0.0000681) or (time_max > 0.000075):
+            self.put(0, 0, self.out_ann, [1,
+                ['WARNING: The normal mode presence sample time interval ' +
+                 '(%2.1fus-%2.1fus) should be inside (68.1us, 75.0us).'
+                 % (time_min * 1000000, time_max * 1000000)]])
+
+        time_min = float(self.cnt_overdrive_bit) / self.samplerate
+        time_max = float(self.cnt_overdrive_bit + 1) / self.samplerate
+        if (time_min < 0.000001) or (time_max > 0.000002):
+            self.put(0, 0, self.out_ann, [1,
+                ['WARNING: The overdrive mode data sample time interval ' +
+                 '(%2.1fus-%2.1fus) should be inside (1.0us, 2.0us).'
+                 % (time_min * 1000000, time_max * 1000000)]])
+
+        time_min = float(self.cnt_overdrive_presence) / self.samplerate
+        time_max = float(self.cnt_overdrive_presence + 1) / self.samplerate
+        if (time_min < 0.0000073) or (time_max > 0.000010):
+            self.put(0, 0, self.out_ann, [1,
+                ['WARNING: The overdrive mode presence sample time interval ' +
+                 '(%2.1fus-%2.1fus) should be inside (7.3us, 10.0us).'
+                 % (time_min*1000000, time_max*1000000)]])
+
+    def report(self):
+        pass
+
+    def decode(self, ss, es, data):
+        for (self.samplenum, (owr, pwr)) in data:
+            # State machine.
+            if self.state == 'WAIT FOR FALLING EDGE':
+                # The start of a cycle is a falling edge.
+                if owr != 0:
+                    continue
+                # Save the sample number for the falling edge.
+                self.fall = self.samplenum
+                # Go to waiting for sample time.
+                self.state = 'WAIT FOR DATA SAMPLE'
+            elif self.state == 'WAIT FOR DATA SAMPLE':
+                # Sample data bit.
+                t = self.samplenum - self.fall
+                if t == self.cnt_bit[self.overdrive]:
+                    self.bit = owr
+                    self.state = 'WAIT FOR DATA SLOT END'
+            elif self.state == 'WAIT FOR DATA SLOT END':
+                # A data slot ends in a recovery period, otherwise, this is
+                # probably a reset.
+                t = self.samplenum - self.fall
+                if t != self.cnt_slot[self.overdrive]:
+                    continue
+
+                if owr == 0:
+                    # This seems to be a reset slot, wait for its end.
+                    self.state = 'WAIT FOR RISING EDGE'
+                    continue
+
+                self.put(self.fall, self.samplenum, self.out_ann,
+                         [0, ['Bit: %d' % self.bit]])
+                self.put(self.fall, self.samplenum, self.out_proto,
+                         ['BIT', self.bit])
+
+                # Checking the first command to see if overdrive mode
+                # should be entered.
+                if self.bit_cnt <= 8:
+                    self.command |= (self.bit << self.bit_cnt)
+                elif self.bit_cnt == 8 and self.command in [0x3c, 0x69]:
+                    self.put(self.fall, self.cnt_bit[self.overdrive],
+                             self.out_ann, [0, ['Entering overdrive mode']])
+                # Increment the bit counter.
+                self.bit_cnt += 1
+                # Wait for next slot.
+                self.state = 'WAIT FOR FALLING EDGE'
+            elif self.state == 'WAIT FOR RISING EDGE':
+                # The end of a cycle is a rising edge.
+                if owr != 1:
+                    continue
+
+                # Check if this was a reset cycle.
+                t = self.samplenum - self.fall
+                if t > self.cnt_normal_reset:
+                    # Save the sample number for the falling edge.
+                    self.rise = self.samplenum
+                    self.state = 'WAIT FOR PRESENCE DETECT'
+                    # Exit overdrive mode.
+                    if self.overdrive:
+                        self.put(self.fall, self.cnt_bit[self.overdrive],
+                                 self.out_ann, [0, ['Exiting overdrive mode']])
+                        self.overdrive = 0
+                    # Clear command bit counter and data register.
+                    self.bit_cnt = 0
+                    self.command = 0
+                elif (t > self.cnt_overdrive_reset) and self.overdrive:
+                    # Save the sample number for the falling edge.
+                    self.rise = self.samplenum
+                    self.state = "WAIT FOR PRESENCE DETECT"
+                # Otherwise this is assumed to be a data bit.
+                else:
+                    self.state = "WAIT FOR FALLING EDGE"
+            elif self.state == 'WAIT FOR PRESENCE DETECT':
+                # Sample presence status.
+                t = self.samplenum - self.rise
+                if t == self.cnt_presence[self.overdrive]:
+                    self.present = owr
+                    self.state = 'WAIT FOR RESET SLOT END'
+            elif self.state == 'WAIT FOR RESET SLOT END':
+                # A reset slot ends in a long recovery period.
+                t = self.samplenum - self.rise
+                if t != self.cnt_reset[self.overdrive]:
+                    continue
+
+                if owr == 0:
+                    # This seems to be a reset slot, wait for its end.
+                    self.state = 'WAIT FOR RISING EDGE'
+                    continue
+
+                self.put(self.fall, self.samplenum, self.out_ann,
+                         [0, ['Reset/presence: %s'
+                         % ('false' if self.present else 'true')]])
+                self.put(self.fall, self.samplenum, self.out_proto,
+                         ['RESET/PRESENCE', not self.present])
+                # Wait for next slot.
+                self.state = 'WAIT FOR FALLING EDGE'
+            else:
+                raise Exception('Invalid state: %s' % self.state)
index 2484987ee6721be94228d2f04be9dd8db18a3a8a..d0a84a80440d452c1c39152b94986aa39d8866fb 100644 (file)
@@ -20,7 +20,7 @@
 
 pkgdatadir = $(DECODERS_DIR)/onewire_network
 
-dist_pkgdata_DATA = __init__.py onewire_network.py
+dist_pkgdata_DATA = __init__.py pd.py
 
 CLEANFILES = *.pyc
 
index 25b3f5d4cce3d7b32bb793830b36efee0b140931..74b9f4bf658cd43971050ed2706b7a8b4d6cb87e 100644 (file)
@@ -58,5 +58,5 @@ TODO:
  - Add reporting original/complement address values from the search algorithm.
 '''
 
-from .onewire_network import *
+from .pd import *
 
diff --git a/decoders/onewire_network/onewire_network.py b/decoders/onewire_network/onewire_network.py
deleted file mode 100644 (file)
index ab11ea4..0000000
+++ /dev/null
@@ -1,190 +0,0 @@
-##
-## This file is part of the sigrok project.
-##
-## Copyright (C) 2012 Iztok Jeras <iztok.jeras@gmail.com>
-##
-## 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
-## the Free Software Foundation; either version 2 of the License, or
-## (at your option) any later version.
-##
-## This program is distributed in the hope that it will be useful,
-## but WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-## GNU General Public License for more details.
-##
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, write to the Free Software
-## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
-##
-
-# 1-Wire protocol decoder (network layer)
-
-import sigrokdecode as srd
-
-# Dictionary of ROM commands and their names, next state.
-command = {
-    0x33: ['Read ROM'              , 'GET ROM'   ],
-    0x0f: ['Conditional read ROM'  , 'GET ROM'   ],
-    0xcc: ['Skip ROM'              , 'TRANSPORT' ],
-    0x55: ['Match ROM'             , 'GET ROM'   ],
-    0xf0: ['Search ROM'            , 'SEARCH ROM'],
-    0xec: ['Conditional search ROM', 'SEARCH ROM'],
-    0x3c: ['Overdrive skip ROM'    , 'TRANSPORT' ],
-    0x69: ['Overdrive match ROM'   , 'GET ROM'   ],
-}
-
-class Decoder(srd.Decoder):
-    api_version = 1
-    id = 'onewire_network'
-    name = '1-Wire network layer'
-    longname = '1-Wire serial communication bus (network layer)'
-    desc = 'Bidirectional, half-duplex, asynchronous serial bus.'
-    license = 'gplv2+'
-    inputs = ['onewire_link']
-    outputs = ['onewire_network']
-    probes = []
-    optional_probes = []
-    options = {}
-    annotations = [
-        ['Text', 'Human-readable text'],
-    ]
-
-    def __init__(self, **kwargs):
-        self.beg = 0
-        self.end = 0
-        self.state = 'COMMAND'
-        self.bit_cnt = 0
-        self.search = 'P'
-        self.data_p = 0x0
-        self.data_n = 0x0
-        self.data = 0x0
-        self.rom = 0x0000000000000000
-
-    def start(self, metadata):
-        self.out_proto = self.add(srd.OUTPUT_PROTO, 'onewire_network')
-        self.out_ann = self.add(srd.OUTPUT_ANN, 'onewire_network')
-
-    def report(self):
-        pass
-
-    def putx(self, data):
-        # Helper function for most annotations.
-        self.put(self.beg, self.end, self.out_ann, data)
-
-    def puty(self, data):
-        # Helper function for most protocol packets.
-        self.put(self.beg, self.end, self.out_proto, data)
-
-    def decode(self, ss, es, data):
-        code, val = data
-
-        # State machine.
-        if code == 'RESET/PRESENCE':
-            self.search = 'P'
-            self.bit_cnt = 0
-            self.put(ss, es, self.out_ann,
-                     [0, ['Reset/presence: %s' % ('true' if val else 'false')]])
-            self.put(ss, es, self.out_proto, ['RESET/PRESENCE', val])
-            self.state = 'COMMAND'
-            return
-
-        # For now we're only interested in 'RESET/PRESENCE' and 'BIT' packets.
-        if code != 'BIT':
-            return
-
-        if self.state == 'COMMAND':
-            # Receiving and decoding a ROM command.
-            if self.onewire_collect(8, val, ss, es) == 0:
-                return
-            if self.data in command:
-                self.putx([0, ['ROM command: 0x%02x \'%s\''
-                          % (self.data, command[self.data][0])]])
-                self.state = command[self.data][1]
-            else:
-                self.putx([0, ['ROM command: 0x%02x \'%s\''
-                          % (self.data, 'unrecognized')]])
-                self.state = 'COMMAND ERROR'
-        elif self.state == 'GET ROM':
-            # A 64 bit device address is selected.
-            # Family code (1 byte) + serial number (6 bytes) + CRC (1 byte)
-            if self.onewire_collect(64, val, ss, es) == 0:
-                return
-            self.rom = self.data & 0xffffffffffffffff
-            self.putx([0, ['ROM: 0x%016x' % self.rom]])
-            self.puty(['ROM', self.rom])
-            self.state = 'TRANSPORT'
-        elif self.state == 'SEARCH ROM':
-            # A 64 bit device address is searched for.
-            # Family code (1 byte) + serial number (6 bytes) + CRC (1 byte)
-            if self.onewire_search(64, val, ss, es) == 0:
-                return
-            self.rom = self.data & 0xffffffffffffffff
-            self.putx([0, ['ROM: 0x%016x' % self.rom]])
-            self.puty(['ROM', self.rom])
-            self.state = 'TRANSPORT'
-        elif self.state == 'TRANSPORT':
-            # The transport layer is handled in byte sized units.
-            if self.onewire_collect(8, val, ss, es) == 0:
-                return
-            self.putx([0, ['Data: 0x%02x' % self.data]])
-            self.puty(['DATA', self.data])
-        elif self.state == 'COMMAND ERROR':
-            # Since the command is not recognized, print raw data.
-            if self.onewire_collect(8, val, ss, es) == 0:
-                return
-            self.putx([0, ['ROM error data: 0x%02x' % self.data]])
-        else:
-            raise Exception('Invalid state: %s' % self.state)
-
-    # Data collector.
-    def onewire_collect(self, length, val, ss, es):
-        # Storing the sample this sequence begins with.
-        if self.bit_cnt == 1:
-            self.beg = ss
-        self.data = self.data & ~(1 << self.bit_cnt) | (val << self.bit_cnt)
-        self.bit_cnt += 1
-        # Storing the sample this sequence ends with.
-        # In case the full length of the sequence is received, return 1.
-        if self.bit_cnt == length:
-            self.end = es
-            self.data = self.data & ((1 << length) - 1)
-            self.bit_cnt = 0
-            return 1
-        else:
-            return 0
-
-    # Search collector.
-    def onewire_search(self, length, val, ss, es):
-        # Storing the sample this sequence begins with.
-        if (self.bit_cnt == 0) and (self.search == 'P'):
-            self.beg = ss
-
-        if self.search == 'P':
-            # Master receives an original address bit.
-            self.data_p = self.data_p & ~(1 << self.bit_cnt) | \
-                          (val << self.bit_cnt)
-            self.search = 'N'
-        elif self.search == 'N':
-            # Master receives a complemented address bit.
-            self.data_n = self.data_n & ~(1 << self.bit_cnt) | \
-                          (val << self.bit_cnt)
-            self.search = 'D'
-        elif self.search == 'D':
-            # Master transmits an address bit.
-            self.data = self.data & ~(1 << self.bit_cnt) | (val << self.bit_cnt)
-            self.search = 'P'
-            self.bit_cnt += 1
-
-        # Storing the sample this sequence ends with.
-        # In case the full length of the sequence is received, return 1.
-        if self.bit_cnt == length:
-            self.end = es
-            self.data_p = self.data_p & ((1 << length) - 1)
-            self.data_n = self.data_n & ((1 << length) - 1)
-            self.data = self.data & ((1 << length) - 1)
-            self.search = 'P'
-            self.bit_cnt = 0
-            return 1
-        else:
-            return 0
diff --git a/decoders/onewire_network/pd.py b/decoders/onewire_network/pd.py
new file mode 100644 (file)
index 0000000..ab11ea4
--- /dev/null
@@ -0,0 +1,190 @@
+##
+## This file is part of the sigrok project.
+##
+## Copyright (C) 2012 Iztok Jeras <iztok.jeras@gmail.com>
+##
+## 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
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+##
+
+# 1-Wire protocol decoder (network layer)
+
+import sigrokdecode as srd
+
+# Dictionary of ROM commands and their names, next state.
+command = {
+    0x33: ['Read ROM'              , 'GET ROM'   ],
+    0x0f: ['Conditional read ROM'  , 'GET ROM'   ],
+    0xcc: ['Skip ROM'              , 'TRANSPORT' ],
+    0x55: ['Match ROM'             , 'GET ROM'   ],
+    0xf0: ['Search ROM'            , 'SEARCH ROM'],
+    0xec: ['Conditional search ROM', 'SEARCH ROM'],
+    0x3c: ['Overdrive skip ROM'    , 'TRANSPORT' ],
+    0x69: ['Overdrive match ROM'   , 'GET ROM'   ],
+}
+
+class Decoder(srd.Decoder):
+    api_version = 1
+    id = 'onewire_network'
+    name = '1-Wire network layer'
+    longname = '1-Wire serial communication bus (network layer)'
+    desc = 'Bidirectional, half-duplex, asynchronous serial bus.'
+    license = 'gplv2+'
+    inputs = ['onewire_link']
+    outputs = ['onewire_network']
+    probes = []
+    optional_probes = []
+    options = {}
+    annotations = [
+        ['Text', 'Human-readable text'],
+    ]
+
+    def __init__(self, **kwargs):
+        self.beg = 0
+        self.end = 0
+        self.state = 'COMMAND'
+        self.bit_cnt = 0
+        self.search = 'P'
+        self.data_p = 0x0
+        self.data_n = 0x0
+        self.data = 0x0
+        self.rom = 0x0000000000000000
+
+    def start(self, metadata):
+        self.out_proto = self.add(srd.OUTPUT_PROTO, 'onewire_network')
+        self.out_ann = self.add(srd.OUTPUT_ANN, 'onewire_network')
+
+    def report(self):
+        pass
+
+    def putx(self, data):
+        # Helper function for most annotations.
+        self.put(self.beg, self.end, self.out_ann, data)
+
+    def puty(self, data):
+        # Helper function for most protocol packets.
+        self.put(self.beg, self.end, self.out_proto, data)
+
+    def decode(self, ss, es, data):
+        code, val = data
+
+        # State machine.
+        if code == 'RESET/PRESENCE':
+            self.search = 'P'
+            self.bit_cnt = 0
+            self.put(ss, es, self.out_ann,
+                     [0, ['Reset/presence: %s' % ('true' if val else 'false')]])
+            self.put(ss, es, self.out_proto, ['RESET/PRESENCE', val])
+            self.state = 'COMMAND'
+            return
+
+        # For now we're only interested in 'RESET/PRESENCE' and 'BIT' packets.
+        if code != 'BIT':
+            return
+
+        if self.state == 'COMMAND':
+            # Receiving and decoding a ROM command.
+            if self.onewire_collect(8, val, ss, es) == 0:
+                return
+            if self.data in command:
+                self.putx([0, ['ROM command: 0x%02x \'%s\''
+                          % (self.data, command[self.data][0])]])
+                self.state = command[self.data][1]
+            else:
+                self.putx([0, ['ROM command: 0x%02x \'%s\''
+                          % (self.data, 'unrecognized')]])
+                self.state = 'COMMAND ERROR'
+        elif self.state == 'GET ROM':
+            # A 64 bit device address is selected.
+            # Family code (1 byte) + serial number (6 bytes) + CRC (1 byte)
+            if self.onewire_collect(64, val, ss, es) == 0:
+                return
+            self.rom = self.data & 0xffffffffffffffff
+            self.putx([0, ['ROM: 0x%016x' % self.rom]])
+            self.puty(['ROM', self.rom])
+            self.state = 'TRANSPORT'
+        elif self.state == 'SEARCH ROM':
+            # A 64 bit device address is searched for.
+            # Family code (1 byte) + serial number (6 bytes) + CRC (1 byte)
+            if self.onewire_search(64, val, ss, es) == 0:
+                return
+            self.rom = self.data & 0xffffffffffffffff
+            self.putx([0, ['ROM: 0x%016x' % self.rom]])
+            self.puty(['ROM', self.rom])
+            self.state = 'TRANSPORT'
+        elif self.state == 'TRANSPORT':
+            # The transport layer is handled in byte sized units.
+            if self.onewire_collect(8, val, ss, es) == 0:
+                return
+            self.putx([0, ['Data: 0x%02x' % self.data]])
+            self.puty(['DATA', self.data])
+        elif self.state == 'COMMAND ERROR':
+            # Since the command is not recognized, print raw data.
+            if self.onewire_collect(8, val, ss, es) == 0:
+                return
+            self.putx([0, ['ROM error data: 0x%02x' % self.data]])
+        else:
+            raise Exception('Invalid state: %s' % self.state)
+
+    # Data collector.
+    def onewire_collect(self, length, val, ss, es):
+        # Storing the sample this sequence begins with.
+        if self.bit_cnt == 1:
+            self.beg = ss
+        self.data = self.data & ~(1 << self.bit_cnt) | (val << self.bit_cnt)
+        self.bit_cnt += 1
+        # Storing the sample this sequence ends with.
+        # In case the full length of the sequence is received, return 1.
+        if self.bit_cnt == length:
+            self.end = es
+            self.data = self.data & ((1 << length) - 1)
+            self.bit_cnt = 0
+            return 1
+        else:
+            return 0
+
+    # Search collector.
+    def onewire_search(self, length, val, ss, es):
+        # Storing the sample this sequence begins with.
+        if (self.bit_cnt == 0) and (self.search == 'P'):
+            self.beg = ss
+
+        if self.search == 'P':
+            # Master receives an original address bit.
+            self.data_p = self.data_p & ~(1 << self.bit_cnt) | \
+                          (val << self.bit_cnt)
+            self.search = 'N'
+        elif self.search == 'N':
+            # Master receives a complemented address bit.
+            self.data_n = self.data_n & ~(1 << self.bit_cnt) | \
+                          (val << self.bit_cnt)
+            self.search = 'D'
+        elif self.search == 'D':
+            # Master transmits an address bit.
+            self.data = self.data & ~(1 << self.bit_cnt) | (val << self.bit_cnt)
+            self.search = 'P'
+            self.bit_cnt += 1
+
+        # Storing the sample this sequence ends with.
+        # In case the full length of the sequence is received, return 1.
+        if self.bit_cnt == length:
+            self.end = es
+            self.data_p = self.data_p & ((1 << length) - 1)
+            self.data_n = self.data_n & ((1 << length) - 1)
+            self.data = self.data & ((1 << length) - 1)
+            self.search = 'P'
+            self.bit_cnt = 0
+            return 1
+        else:
+            return 0
index 6997ed51bd062dda6f22a0e04b9a442ea53ac4ed..5c5913e7e69a8b3497164ad7e8dd880dd71ac3f8 100644 (file)
@@ -20,7 +20,7 @@
 
 pkgdatadir = $(DECODERS_DIR)/pan1321
 
-dist_pkgdata_DATA = __init__.py pan1321.py
+dist_pkgdata_DATA = __init__.py pd.py
 
 CLEANFILES = *.pyc
 
index 155d96141a51d216cfefa026a0e0db51b0bf8967..df48767f070776015ae5b6fc983f3386fbc5d76c 100644 (file)
@@ -25,5 +25,5 @@ Details:
 TODO
 '''
 
-from .pan1321 import *
+from .pd import *
 
diff --git a/decoders/pan1321/pan1321.py b/decoders/pan1321/pan1321.py
deleted file mode 100644 (file)
index 827269d..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-##
-## This file is part of the sigrok project.
-##
-## 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
-## the Free Software Foundation; either version 2 of the License, or
-## (at your option) any later version.
-##
-## This program is distributed in the hope that it will be useful,
-## but WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-## GNU General Public License for more details.
-##
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, write to the Free Software
-## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
-##
-
-# Panasonic PAN1321 Bluetooth module protocol decoder
-
-import sigrokdecode as srd
-
-# ...
-RX = 0
-TX = 1
-
-class Decoder(srd.Decoder):
-    api_version = 1
-    id = 'pan1321'
-    name = 'PAN1321'
-    longname = 'Panasonic PAN1321'
-    desc = 'Bluetooth RF module with Serial Port Profile (SPP).'
-    license = 'gplv2+'
-    inputs = ['uart']
-    outputs = ['pan1321']
-    probes = []
-    optional_probes = []
-    options = {}
-    annotations = [
-        ['Text (verbose)', 'Human-readable text (verbose)'],
-        ['Text', 'Human-readable text'],
-    ]
-
-    def __init__(self, **kwargs):
-        self.cmd = ['', '']
-        self.ss_block = None
-
-    def start(self, metadata):
-        # self.out_proto = self.add(srd.OUTPUT_PROTO, 'pan1321')
-        self.out_ann = self.add(srd.OUTPUT_ANN, 'pan1321')
-
-    def report(self):
-        pass
-
-    def putx(self, data):
-        self.put(self.ss_block, self.es_block, self.out_ann, data)
-
-    def handle_host_command(self, rxtx, s):
-        if s.startswith('AT+JSEC'):
-            pin = s[-4:]
-            self.putx([0, ['Host set the Bluetooth PIN to ' + pin]])
-            self.putx([1, ['PIN = ' + pin]])
-        elif s.startswith('AT+JSLN'):
-            name = s[s.find(',') + 1:]
-            self.putx([0, ['Host set the Bluetooth name to ' + name]])
-            self.putx([1, ['BT name = ' + name]])
-        else:
-            self.putx([0, ['Host sent unsupported command: %s' % s]])
-            self.putx([1, ['Unsupported command: %s' % s]])
-        self.cmd[rxtx] = ''
-
-    def handle_device_reply(self, rxtx, s):
-        if s == 'ROK':
-            self.putx([0, ['Device initialized correctly']])
-            self.putx([1, ['Init']])
-        elif s == 'OK':
-            self.putx([0, ['Device acknowledged last command']])
-            self.putx([1, ['ACK']])
-        elif s.startswith('ERR'):
-            error = s[s.find('=') + 1:]
-            self.putx([0, ['Device sent error code ' + error]])
-            self.putx([1, ['ERR = ' + error]])
-        else:
-            self.putx([0, ['Device sent an unknown reply: %s' % s]])
-            self.putx([1, ['Unknown reply: %s' % s]])
-        self.cmd[rxtx] = ''
-
-    def decode(self, ss, es, data):
-        ptype, rxtx, pdata = data
-
-        # For now, ignore all UART packets except the actual data packets.
-        if ptype != 'DATA':
-            return
-
-        # If this is the start of a command/reply, remember the start sample.
-        if self.cmd[rxtx] == '':
-            self.ss_block = ss
-
-        # Append a new (ASCII) byte to the currently built/parsed command.
-        self.cmd[rxtx] += chr(pdata)
-
-        # Get packets/bytes until an \r\n sequence is found (end of command).
-        if self.cmd[rxtx][-1:] != '\n':
-            return
-
-        # Handle host commands and device replies.
-        # We remove trailing \r\n from the strings before handling them.
-        if rxtx == RX:
-            self.es_block = es
-            self.handle_device_reply(rxtx, self.cmd[rxtx][:-2])
-        elif rxtx == TX:
-            self.es_block = es
-            self.handle_host_command(rxtx, self.cmd[rxtx][:-2])
-        else:
-            raise Exception('Invalid rxtx value: %d' % rxtx)
-
diff --git a/decoders/pan1321/pd.py b/decoders/pan1321/pd.py
new file mode 100644 (file)
index 0000000..827269d
--- /dev/null
@@ -0,0 +1,118 @@
+##
+## This file is part of the sigrok project.
+##
+## 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
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+##
+
+# Panasonic PAN1321 Bluetooth module protocol decoder
+
+import sigrokdecode as srd
+
+# ...
+RX = 0
+TX = 1
+
+class Decoder(srd.Decoder):
+    api_version = 1
+    id = 'pan1321'
+    name = 'PAN1321'
+    longname = 'Panasonic PAN1321'
+    desc = 'Bluetooth RF module with Serial Port Profile (SPP).'
+    license = 'gplv2+'
+    inputs = ['uart']
+    outputs = ['pan1321']
+    probes = []
+    optional_probes = []
+    options = {}
+    annotations = [
+        ['Text (verbose)', 'Human-readable text (verbose)'],
+        ['Text', 'Human-readable text'],
+    ]
+
+    def __init__(self, **kwargs):
+        self.cmd = ['', '']
+        self.ss_block = None
+
+    def start(self, metadata):
+        # self.out_proto = self.add(srd.OUTPUT_PROTO, 'pan1321')
+        self.out_ann = self.add(srd.OUTPUT_ANN, 'pan1321')
+
+    def report(self):
+        pass
+
+    def putx(self, data):
+        self.put(self.ss_block, self.es_block, self.out_ann, data)
+
+    def handle_host_command(self, rxtx, s):
+        if s.startswith('AT+JSEC'):
+            pin = s[-4:]
+            self.putx([0, ['Host set the Bluetooth PIN to ' + pin]])
+            self.putx([1, ['PIN = ' + pin]])
+        elif s.startswith('AT+JSLN'):
+            name = s[s.find(',') + 1:]
+            self.putx([0, ['Host set the Bluetooth name to ' + name]])
+            self.putx([1, ['BT name = ' + name]])
+        else:
+            self.putx([0, ['Host sent unsupported command: %s' % s]])
+            self.putx([1, ['Unsupported command: %s' % s]])
+        self.cmd[rxtx] = ''
+
+    def handle_device_reply(self, rxtx, s):
+        if s == 'ROK':
+            self.putx([0, ['Device initialized correctly']])
+            self.putx([1, ['Init']])
+        elif s == 'OK':
+            self.putx([0, ['Device acknowledged last command']])
+            self.putx([1, ['ACK']])
+        elif s.startswith('ERR'):
+            error = s[s.find('=') + 1:]
+            self.putx([0, ['Device sent error code ' + error]])
+            self.putx([1, ['ERR = ' + error]])
+        else:
+            self.putx([0, ['Device sent an unknown reply: %s' % s]])
+            self.putx([1, ['Unknown reply: %s' % s]])
+        self.cmd[rxtx] = ''
+
+    def decode(self, ss, es, data):
+        ptype, rxtx, pdata = data
+
+        # For now, ignore all UART packets except the actual data packets.
+        if ptype != 'DATA':
+            return
+
+        # If this is the start of a command/reply, remember the start sample.
+        if self.cmd[rxtx] == '':
+            self.ss_block = ss
+
+        # Append a new (ASCII) byte to the currently built/parsed command.
+        self.cmd[rxtx] += chr(pdata)
+
+        # Get packets/bytes until an \r\n sequence is found (end of command).
+        if self.cmd[rxtx][-1:] != '\n':
+            return
+
+        # Handle host commands and device replies.
+        # We remove trailing \r\n from the strings before handling them.
+        if rxtx == RX:
+            self.es_block = es
+            self.handle_device_reply(rxtx, self.cmd[rxtx][:-2])
+        elif rxtx == TX:
+            self.es_block = es
+            self.handle_host_command(rxtx, self.cmd[rxtx][:-2])
+        else:
+            raise Exception('Invalid rxtx value: %d' % rxtx)
+
index 581eb5f2bbe36685dcec3f8c5502c222ca5b9bcf..8757b9cf8214fc4ad4fc29a0fbae230dafe2161b 100644 (file)
@@ -20,7 +20,7 @@
 
 pkgdatadir = $(DECODERS_DIR)/rtc8564
 
-dist_pkgdata_DATA = __init__.py rtc8564.py
+dist_pkgdata_DATA = __init__.py pd.py
 
 CLEANFILES = *.pyc
 
index 56534532b2920dc36463da65627df2438133999e..94fdaeaee07510d4e946da282ebdace8a332c758 100644 (file)
@@ -25,5 +25,5 @@ Details:
 TODO
 '''
 
-from .rtc8564 import *
+from .pd import *
 
diff --git a/decoders/rtc8564/pd.py b/decoders/rtc8564/pd.py
new file mode 100644 (file)
index 0000000..bf5d4b6
--- /dev/null
@@ -0,0 +1,216 @@
+##
+## This file is part of the sigrok project.
+##
+## 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
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+##
+
+# Epson RTC-8564 JE/NB protocol decoder
+
+import sigrokdecode as srd
+
+# Return the specified BCD number (max. 8 bits) as integer.
+def bcd2int(b):
+    return (b & 0x0f) + ((b >> 4) * 10)
+
+class Decoder(srd.Decoder):
+    api_version = 1
+    id = 'rtc8564'
+    name = 'RTC-8564'
+    longname = 'Epson RTC-8564 JE/NB'
+    desc = 'Realtime clock module protocol.'
+    license = 'gplv2+'
+    inputs = ['i2c']
+    outputs = ['rtc8564']
+    probes = []
+    optional_probes = [
+        {'id': 'clkout', 'name': 'CLKOUT', 'desc': 'TODO.'},
+        {'id': 'clkoe', 'name': 'CLKOE', 'desc': 'TODO.'},
+        {'id': 'int', 'name': 'INT#', 'desc': 'TODO.'},
+    ]
+    options = {}
+    annotations = [
+        ['Text', 'Human-readable text'],
+    ]
+
+    def __init__(self, **kwargs):
+        self.state = 'IDLE'
+        self.hours = -1
+        self.minutes = -1
+        self.seconds = -1
+        self.days = -1
+        self.months = -1
+        self.years = -1
+
+    def start(self, metadata):
+        # self.out_proto = self.add(srd.OUTPUT_PROTO, 'rtc8564')
+        self.out_ann = self.add(srd.OUTPUT_ANN, 'rtc8564')
+
+    def report(self):
+        pass
+
+    def putx(self, data):
+        self.put(self.ss, self.es, self.out_ann, data)
+
+    def handle_reg_0x00(self, b): # Control register 1
+        pass
+
+    def handle_reg_0x01(self, b): # Control register 2
+        ti_tp = 1 if (b & (1 << 4)) else 0
+        af = 1 if (b & (1 << 3)) else 0
+        tf = 1 if (b & (1 << 2)) else 0
+        aie = 1 if (b & (1 << 1)) else 0
+        tie = 1 if (b & (1 << 0)) else 0
+
+        ann = ''
+
+        s = 'repeated' if ti_tp else 'single-shot'
+        ann += 'TI/TP = %d: %s operation upon fixed-cycle timer interrupt '\
+               'events\n' % (ti_tp, s)
+        s = '' if af else 'no '
+        ann += 'AF = %d: %salarm interrupt detected\n' % (af, s)
+        s = '' if tf else 'no '
+        ann += 'TF = %d: %sfixed-cycle timer interrupt detected\n' % (tf, s)
+        s = 'enabled' if aie else 'prohibited'
+        ann += 'AIE = %d: INT# pin output %s when an alarm interrupt '\
+               'occurs\n' % (aie, s)
+        s = 'enabled' if tie else 'prohibited'
+        ann += 'TIE = %d: INT# pin output %s when a fixed-cycle interrupt '\
+               'event occurs\n' % (tie, s)
+
+        self.putx([0, [ann]])
+
+    def handle_reg_0x02(self, b): # Seconds / Voltage-low flag
+        self.seconds = bcd2int(b & 0x7f)
+        self.putx([0, ['Seconds: %d' % self.seconds]])
+        vl = 1 if (b & (1 << 7)) else 0
+        self.putx([0, ['Voltage low (VL) bit: %d' % vl]])
+
+    def handle_reg_0x03(self, b): # Minutes
+        self.minutes = bcd2int(b & 0x7f)
+        self.putx([0, ['Minutes: %d' % self.minutes]])
+
+    def handle_reg_0x04(self, b): # Hours
+        self.hours = bcd2int(b & 0x3f)
+        self.putx([0, ['Hours: %d' % self.hours]])
+
+    def handle_reg_0x05(self, b): # Days
+        self.days = bcd2int(b & 0x3f)
+        self.putx([0, ['Days: %d' % self.days]])
+
+    def handle_reg_0x06(self, b): # Day counter
+        pass
+
+    def handle_reg_0x07(self, b): # Months / century
+        # TODO: Handle century bit.
+        self.months = bcd2int(b & 0x1f)
+        self.putx([0, ['Months: %d' % self.months]])
+
+    def handle_reg_0x08(self, b): # Years
+        self.years = bcd2int(b & 0xff)
+        self.putx([0, ['Years: %d' % self.years]])
+
+    def handle_reg_0x09(self, b): # Alarm, minute
+        pass
+
+    def handle_reg_0x0a(self, b): # Alarm, hour
+        pass
+
+    def handle_reg_0x0b(self, b): # Alarm, day
+        pass
+
+    def handle_reg_0x0c(self, b): # Alarm, weekday
+        pass
+
+    def handle_reg_0x0d(self, b): # CLKOUT output
+        pass
+
+    def handle_reg_0x0e(self, b): # Timer setting
+        pass
+
+    def handle_reg_0x0f(self, b): # Down counter for fixed-cycle timer
+        pass
+
+    def decode(self, ss, es, data):
+        cmd, databyte = data
+
+        # Store the start/end samples of this I2C packet.
+        self.ss, self.es = ss, es
+
+        # State machine.
+        if self.state == 'IDLE':
+            # Wait for an I2C START condition.
+            if cmd != 'START':
+                return
+            self.state = 'GET SLAVE ADDR'
+            self.block_start_sample = ss
+        elif self.state == 'GET SLAVE ADDR':
+            # Wait for an address write operation.
+            # TODO: We should only handle packets to the RTC slave (0xa2/0xa3).
+            if cmd != 'ADDRESS WRITE':
+                return
+            self.state = 'GET REG ADDR'
+        elif self.state == 'GET REG ADDR':
+            # Wait for a data write (master selects the slave register).
+            if cmd != 'DATA WRITE':
+                return
+            self.reg = databyte
+            self.state = 'WRITE RTC REGS'
+        elif self.state == 'WRITE RTC REGS':
+            # If we see a Repeated Start here, it's probably an RTC read.
+            if cmd == 'START REPEAT':
+                self.state = 'READ RTC REGS'
+                return
+            # Otherwise: Get data bytes until a STOP condition occurs.
+            if cmd == 'DATA WRITE':
+                handle_reg = getattr(self, 'handle_reg_0x%02x' % self.reg)
+                handle_reg(databyte)
+                self.reg += 1
+                # TODO: Check for NACK!
+            elif cmd == 'STOP':
+                # TODO: Handle read/write of only parts of these items.
+                d = '%02d.%02d.%02d %02d:%02d:%02d' % (self.days, self.months,
+                    self.years, self.hours, self.minutes, self.seconds)
+                self.put(self.block_start_sample, es, self.out_ann,
+                         [0, ['Written date/time: %s' % d]])
+                self.state = 'IDLE'
+            else:
+                pass # TODO
+        elif self.state == 'READ RTC REGS':
+            # Wait for an address read operation.
+            # TODO: We should only handle packets to the RTC slave (0xa2/0xa3).
+            if cmd == 'ADDRESS READ':
+                self.state = 'READ RTC REGS2'
+                return
+            else:
+                pass # TODO
+        elif self.state == 'READ RTC REGS2':
+            if cmd == 'DATA READ':
+                handle_reg = getattr(self, 'handle_reg_0x%02x' % self.reg)
+                handle_reg(databyte)
+                self.reg += 1
+                # TODO: Check for NACK!
+            elif cmd == 'STOP':
+                d = '%02d.%02d.%02d %02d:%02d:%02d' % (self.days, self.months,
+                    self.years, self.hours, self.minutes, self.seconds)
+                self.put(self.block_start_sample, es, self.out_ann,
+                         [0, ['Read date/time: %s' % d]])
+                self.state = 'IDLE'
+            else:
+                pass # TODO?
+        else:
+            raise Exception('Invalid state: %d' % self.state)
+
diff --git a/decoders/rtc8564/rtc8564.py b/decoders/rtc8564/rtc8564.py
deleted file mode 100644 (file)
index bf5d4b6..0000000
+++ /dev/null
@@ -1,216 +0,0 @@
-##
-## This file is part of the sigrok project.
-##
-## 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
-## the Free Software Foundation; either version 2 of the License, or
-## (at your option) any later version.
-##
-## This program is distributed in the hope that it will be useful,
-## but WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-## GNU General Public License for more details.
-##
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, write to the Free Software
-## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
-##
-
-# Epson RTC-8564 JE/NB protocol decoder
-
-import sigrokdecode as srd
-
-# Return the specified BCD number (max. 8 bits) as integer.
-def bcd2int(b):
-    return (b & 0x0f) + ((b >> 4) * 10)
-
-class Decoder(srd.Decoder):
-    api_version = 1
-    id = 'rtc8564'
-    name = 'RTC-8564'
-    longname = 'Epson RTC-8564 JE/NB'
-    desc = 'Realtime clock module protocol.'
-    license = 'gplv2+'
-    inputs = ['i2c']
-    outputs = ['rtc8564']
-    probes = []
-    optional_probes = [
-        {'id': 'clkout', 'name': 'CLKOUT', 'desc': 'TODO.'},
-        {'id': 'clkoe', 'name': 'CLKOE', 'desc': 'TODO.'},
-        {'id': 'int', 'name': 'INT#', 'desc': 'TODO.'},
-    ]
-    options = {}
-    annotations = [
-        ['Text', 'Human-readable text'],
-    ]
-
-    def __init__(self, **kwargs):
-        self.state = 'IDLE'
-        self.hours = -1
-        self.minutes = -1
-        self.seconds = -1
-        self.days = -1
-        self.months = -1
-        self.years = -1
-
-    def start(self, metadata):
-        # self.out_proto = self.add(srd.OUTPUT_PROTO, 'rtc8564')
-        self.out_ann = self.add(srd.OUTPUT_ANN, 'rtc8564')
-
-    def report(self):
-        pass
-
-    def putx(self, data):
-        self.put(self.ss, self.es, self.out_ann, data)
-
-    def handle_reg_0x00(self, b): # Control register 1
-        pass
-
-    def handle_reg_0x01(self, b): # Control register 2
-        ti_tp = 1 if (b & (1 << 4)) else 0
-        af = 1 if (b & (1 << 3)) else 0
-        tf = 1 if (b & (1 << 2)) else 0
-        aie = 1 if (b & (1 << 1)) else 0
-        tie = 1 if (b & (1 << 0)) else 0
-
-        ann = ''
-
-        s = 'repeated' if ti_tp else 'single-shot'
-        ann += 'TI/TP = %d: %s operation upon fixed-cycle timer interrupt '\
-               'events\n' % (ti_tp, s)
-        s = '' if af else 'no '
-        ann += 'AF = %d: %salarm interrupt detected\n' % (af, s)
-        s = '' if tf else 'no '
-        ann += 'TF = %d: %sfixed-cycle timer interrupt detected\n' % (tf, s)
-        s = 'enabled' if aie else 'prohibited'
-        ann += 'AIE = %d: INT# pin output %s when an alarm interrupt '\
-               'occurs\n' % (aie, s)
-        s = 'enabled' if tie else 'prohibited'
-        ann += 'TIE = %d: INT# pin output %s when a fixed-cycle interrupt '\
-               'event occurs\n' % (tie, s)
-
-        self.putx([0, [ann]])
-
-    def handle_reg_0x02(self, b): # Seconds / Voltage-low flag
-        self.seconds = bcd2int(b & 0x7f)
-        self.putx([0, ['Seconds: %d' % self.seconds]])
-        vl = 1 if (b & (1 << 7)) else 0
-        self.putx([0, ['Voltage low (VL) bit: %d' % vl]])
-
-    def handle_reg_0x03(self, b): # Minutes
-        self.minutes = bcd2int(b & 0x7f)
-        self.putx([0, ['Minutes: %d' % self.minutes]])
-
-    def handle_reg_0x04(self, b): # Hours
-        self.hours = bcd2int(b & 0x3f)
-        self.putx([0, ['Hours: %d' % self.hours]])
-
-    def handle_reg_0x05(self, b): # Days
-        self.days = bcd2int(b & 0x3f)
-        self.putx([0, ['Days: %d' % self.days]])
-
-    def handle_reg_0x06(self, b): # Day counter
-        pass
-
-    def handle_reg_0x07(self, b): # Months / century
-        # TODO: Handle century bit.
-        self.months = bcd2int(b & 0x1f)
-        self.putx([0, ['Months: %d' % self.months]])
-
-    def handle_reg_0x08(self, b): # Years
-        self.years = bcd2int(b & 0xff)
-        self.putx([0, ['Years: %d' % self.years]])
-
-    def handle_reg_0x09(self, b): # Alarm, minute
-        pass
-
-    def handle_reg_0x0a(self, b): # Alarm, hour
-        pass
-
-    def handle_reg_0x0b(self, b): # Alarm, day
-        pass
-
-    def handle_reg_0x0c(self, b): # Alarm, weekday
-        pass
-
-    def handle_reg_0x0d(self, b): # CLKOUT output
-        pass
-
-    def handle_reg_0x0e(self, b): # Timer setting
-        pass
-
-    def handle_reg_0x0f(self, b): # Down counter for fixed-cycle timer
-        pass
-
-    def decode(self, ss, es, data):
-        cmd, databyte = data
-
-        # Store the start/end samples of this I2C packet.
-        self.ss, self.es = ss, es
-
-        # State machine.
-        if self.state == 'IDLE':
-            # Wait for an I2C START condition.
-            if cmd != 'START':
-                return
-            self.state = 'GET SLAVE ADDR'
-            self.block_start_sample = ss
-        elif self.state == 'GET SLAVE ADDR':
-            # Wait for an address write operation.
-            # TODO: We should only handle packets to the RTC slave (0xa2/0xa3).
-            if cmd != 'ADDRESS WRITE':
-                return
-            self.state = 'GET REG ADDR'
-        elif self.state == 'GET REG ADDR':
-            # Wait for a data write (master selects the slave register).
-            if cmd != 'DATA WRITE':
-                return
-            self.reg = databyte
-            self.state = 'WRITE RTC REGS'
-        elif self.state == 'WRITE RTC REGS':
-            # If we see a Repeated Start here, it's probably an RTC read.
-            if cmd == 'START REPEAT':
-                self.state = 'READ RTC REGS'
-                return
-            # Otherwise: Get data bytes until a STOP condition occurs.
-            if cmd == 'DATA WRITE':
-                handle_reg = getattr(self, 'handle_reg_0x%02x' % self.reg)
-                handle_reg(databyte)
-                self.reg += 1
-                # TODO: Check for NACK!
-            elif cmd == 'STOP':
-                # TODO: Handle read/write of only parts of these items.
-                d = '%02d.%02d.%02d %02d:%02d:%02d' % (self.days, self.months,
-                    self.years, self.hours, self.minutes, self.seconds)
-                self.put(self.block_start_sample, es, self.out_ann,
-                         [0, ['Written date/time: %s' % d]])
-                self.state = 'IDLE'
-            else:
-                pass # TODO
-        elif self.state == 'READ RTC REGS':
-            # Wait for an address read operation.
-            # TODO: We should only handle packets to the RTC slave (0xa2/0xa3).
-            if cmd == 'ADDRESS READ':
-                self.state = 'READ RTC REGS2'
-                return
-            else:
-                pass # TODO
-        elif self.state == 'READ RTC REGS2':
-            if cmd == 'DATA READ':
-                handle_reg = getattr(self, 'handle_reg_0x%02x' % self.reg)
-                handle_reg(databyte)
-                self.reg += 1
-                # TODO: Check for NACK!
-            elif cmd == 'STOP':
-                d = '%02d.%02d.%02d %02d:%02d:%02d' % (self.days, self.months,
-                    self.years, self.hours, self.minutes, self.seconds)
-                self.put(self.block_start_sample, es, self.out_ann,
-                         [0, ['Read date/time: %s' % d]])
-                self.state = 'IDLE'
-            else:
-                pass # TODO?
-        else:
-            raise Exception('Invalid state: %d' % self.state)
-
index 89bf640db5f09cf7922653b3653d6166f99d7775..0ab762e074d8ec4019630a6283bb1a7a2611b582 100644 (file)
@@ -20,7 +20,7 @@
 
 pkgdatadir = $(DECODERS_DIR)/spi
 
-dist_pkgdata_DATA = __init__.py spi.py
+dist_pkgdata_DATA = __init__.py pd.py
 
 CLEANFILES = *.pyc
 
index fedcc5fbbbd4af3bf33216411a54d8d349d90bb9..1fccbe74dee06292db4ffcd58662b3cce184e134 100644 (file)
@@ -44,5 +44,5 @@ Examples:
 
 '''
 
-from .spi import *
+from .pd import *
 
diff --git a/decoders/spi/pd.py b/decoders/spi/pd.py
new file mode 100644 (file)
index 0000000..1085786
--- /dev/null
@@ -0,0 +1,166 @@
+##
+## This file is part of the sigrok project.
+##
+## Copyright (C) 2011 Gareth McMullin <gareth@blacksphere.co.nz>
+## 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
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+##
+
+# SPI protocol decoder
+
+import sigrokdecode as srd
+
+# Key: (CPOL, CPHA). Value: SPI mode.
+# Clock polarity (CPOL) = 0/1: Clock is low/high when inactive.
+# Clock phase (CPHA) = 0/1: Data is valid on the leading/trailing clock edge.
+spi_mode = {
+    (0, 0): 0, # Mode 0
+    (0, 1): 1, # Mode 1
+    (1, 0): 2, # Mode 2
+    (1, 1): 3, # Mode 3
+}
+
+# Annotation formats
+ANN_HEX = 0
+
+class Decoder(srd.Decoder):
+    api_version = 1
+    id = 'spi'
+    name = 'SPI'
+    longname = 'Serial Peripheral Interface'
+    desc = 'Full-duplex, synchronous, serial bus.'
+    license = 'gplv2+'
+    inputs = ['logic']
+    outputs = ['spi']
+    probes = [
+        {'id': 'miso', 'name': 'MISO',
+         'desc': 'SPI MISO line (Master in, slave out)'},
+        {'id': 'mosi', 'name': 'MOSI',
+         'desc': 'SPI MOSI line (Master out, slave in)'},
+        {'id': 'sck', 'name': 'CLK', 'desc': 'SPI clock line'},
+        {'id': 'cs', 'name': 'CS#', 'desc': 'SPI CS (chip select) line'},
+    ]
+    optional_probes = [] # TODO
+    options = {
+        'cs_polarity': ['CS# polarity', 'active-low'],
+        'cpol': ['Clock polarity', 0],
+        'cpha': ['Clock phase', 0],
+        'bitorder': ['Bit order within the SPI data', 'msb-first'],
+        'wordsize': ['Word size of SPI data', 8], # 1-64?
+    }
+    annotations = [
+        ['Hex', 'SPI data bytes in hex format'],
+    ]
+
+    def __init__(self):
+        self.oldsck = 1
+        self.bitcount = 0
+        self.mosidata = 0
+        self.misodata = 0
+        self.bytesreceived = 0
+        self.samplenum = -1
+        self.cs_was_deasserted_during_data_word = 0
+        self.oldcs = -1
+        self.oldpins = None
+
+    def start(self, metadata):
+        self.out_proto = self.add(srd.OUTPUT_PROTO, 'spi')
+        self.out_ann = self.add(srd.OUTPUT_ANN, 'spi')
+
+    def report(self):
+        return 'SPI: %d bytes received' % self.bytesreceived
+
+    def decode(self, ss, es, data):
+        # TODO: Either MISO or MOSI could be optional. CS# is optional.
+        for (self.samplenum, pins) in data:
+
+            # Ignore identical samples early on (for performance reasons).
+            if self.oldpins == pins:
+                continue
+            self.oldpins, (miso, mosi, sck, cs) = pins, pins
+
+            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.put(self.samplenum, self.samplenum, self.out_ann,
+                         [0, ['CS-CHANGE: %d->%d' % (self.oldcs, cs)]])
+                self.oldcs = cs
+
+            # Ignore sample if the clock pin hasn't changed.
+            if sck == self.oldsck:
+                continue
+
+            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.start_sample = 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
+
+            # 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.bitcount += 1
+
+            # Continue to receive if not enough bits were received, yet.
+            if self.bitcount != ws:
+                continue
+
+            self.put(self.start_sample, self.samplenum, self.out_proto,
+                     ['DATA', self.mosidata, self.misodata])
+            self.put(self.start_sample, self.samplenum, self.out_ann,
+                     [ANN_HEX, ['MOSI: 0x%02x, MISO: 0x%02x' % (self.mosidata,
+                     self.misodata)]])
+
+            if self.cs_was_deasserted_during_data_word:
+                self.put(self.start_sample, self.samplenum, self.out_ann,
+                         [ANN_HEX, ['WARNING: CS# was deasserted during this '
+                         'SPI data byte!']])
+
+            # Reset decoder state.
+            self.mosidata = 0
+            self.misodata = 0
+            self.bitcount = 0
+
+            # Keep stats for summary.
+            self.bytesreceived += 1
+
diff --git a/decoders/spi/spi.py b/decoders/spi/spi.py
deleted file mode 100644 (file)
index 1085786..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-##
-## This file is part of the sigrok project.
-##
-## Copyright (C) 2011 Gareth McMullin <gareth@blacksphere.co.nz>
-## 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
-## the Free Software Foundation; either version 2 of the License, or
-## (at your option) any later version.
-##
-## This program is distributed in the hope that it will be useful,
-## but WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-## GNU General Public License for more details.
-##
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, write to the Free Software
-## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
-##
-
-# SPI protocol decoder
-
-import sigrokdecode as srd
-
-# Key: (CPOL, CPHA). Value: SPI mode.
-# Clock polarity (CPOL) = 0/1: Clock is low/high when inactive.
-# Clock phase (CPHA) = 0/1: Data is valid on the leading/trailing clock edge.
-spi_mode = {
-    (0, 0): 0, # Mode 0
-    (0, 1): 1, # Mode 1
-    (1, 0): 2, # Mode 2
-    (1, 1): 3, # Mode 3
-}
-
-# Annotation formats
-ANN_HEX = 0
-
-class Decoder(srd.Decoder):
-    api_version = 1
-    id = 'spi'
-    name = 'SPI'
-    longname = 'Serial Peripheral Interface'
-    desc = 'Full-duplex, synchronous, serial bus.'
-    license = 'gplv2+'
-    inputs = ['logic']
-    outputs = ['spi']
-    probes = [
-        {'id': 'miso', 'name': 'MISO',
-         'desc': 'SPI MISO line (Master in, slave out)'},
-        {'id': 'mosi', 'name': 'MOSI',
-         'desc': 'SPI MOSI line (Master out, slave in)'},
-        {'id': 'sck', 'name': 'CLK', 'desc': 'SPI clock line'},
-        {'id': 'cs', 'name': 'CS#', 'desc': 'SPI CS (chip select) line'},
-    ]
-    optional_probes = [] # TODO
-    options = {
-        'cs_polarity': ['CS# polarity', 'active-low'],
-        'cpol': ['Clock polarity', 0],
-        'cpha': ['Clock phase', 0],
-        'bitorder': ['Bit order within the SPI data', 'msb-first'],
-        'wordsize': ['Word size of SPI data', 8], # 1-64?
-    }
-    annotations = [
-        ['Hex', 'SPI data bytes in hex format'],
-    ]
-
-    def __init__(self):
-        self.oldsck = 1
-        self.bitcount = 0
-        self.mosidata = 0
-        self.misodata = 0
-        self.bytesreceived = 0
-        self.samplenum = -1
-        self.cs_was_deasserted_during_data_word = 0
-        self.oldcs = -1
-        self.oldpins = None
-
-    def start(self, metadata):
-        self.out_proto = self.add(srd.OUTPUT_PROTO, 'spi')
-        self.out_ann = self.add(srd.OUTPUT_ANN, 'spi')
-
-    def report(self):
-        return 'SPI: %d bytes received' % self.bytesreceived
-
-    def decode(self, ss, es, data):
-        # TODO: Either MISO or MOSI could be optional. CS# is optional.
-        for (self.samplenum, pins) in data:
-
-            # Ignore identical samples early on (for performance reasons).
-            if self.oldpins == pins:
-                continue
-            self.oldpins, (miso, mosi, sck, cs) = pins, pins
-
-            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.put(self.samplenum, self.samplenum, self.out_ann,
-                         [0, ['CS-CHANGE: %d->%d' % (self.oldcs, cs)]])
-                self.oldcs = cs
-
-            # Ignore sample if the clock pin hasn't changed.
-            if sck == self.oldsck:
-                continue
-
-            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.start_sample = 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
-
-            # 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.bitcount += 1
-
-            # Continue to receive if not enough bits were received, yet.
-            if self.bitcount != ws:
-                continue
-
-            self.put(self.start_sample, self.samplenum, self.out_proto,
-                     ['DATA', self.mosidata, self.misodata])
-            self.put(self.start_sample, self.samplenum, self.out_ann,
-                     [ANN_HEX, ['MOSI: 0x%02x, MISO: 0x%02x' % (self.mosidata,
-                     self.misodata)]])
-
-            if self.cs_was_deasserted_during_data_word:
-                self.put(self.start_sample, self.samplenum, self.out_ann,
-                         [ANN_HEX, ['WARNING: CS# was deasserted during this '
-                         'SPI data byte!']])
-
-            # Reset decoder state.
-            self.mosidata = 0
-            self.misodata = 0
-            self.bitcount = 0
-
-            # Keep stats for summary.
-            self.bytesreceived += 1
-
index 74688a3e9c22b1f542ec85534edf5dba6dc9e238..b7ee1f2cc2278318fc9e56d79e2f6fe57a327882 100644 (file)
@@ -20,7 +20,7 @@
 
 pkgdatadir = $(DECODERS_DIR)/transitioncounter
 
-dist_pkgdata_DATA = __init__.py transitioncounter.py
+dist_pkgdata_DATA = __init__.py pd.py
 
 CLEANFILES = *.pyc
 
index f2c3b800cd014d918bb380c7c8f394f261eb2e32..3345da6fbc5a9d708d95369f6c3217d8f30713ff 100644 (file)
@@ -25,5 +25,5 @@ Details:
 TODO
 '''
 
-from .transitioncounter import *
+from .pd import *
 
diff --git a/decoders/transitioncounter/pd.py b/decoders/transitioncounter/pd.py
new file mode 100644 (file)
index 0000000..9506cee
--- /dev/null
@@ -0,0 +1,104 @@
+##
+## This file is part of the sigrok project.
+##
+## Copyright (C) 2010 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
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+##
+
+# Transition counter protocol decoder
+
+import sigrokdecode as srd
+
+class Decoder(srd.Decoder):
+    api_version = 1
+    id = 'transitioncounter'
+    name = 'Transition counter'
+    longname = 'Pin transition counter'
+    desc = 'Counts rising/falling edges in the signal.'
+    license = 'gplv2+'
+    inputs = ['logic']
+    outputs = ['transitioncounts']
+    probes = []
+    optional_probes = []
+    options = {}
+    annotations = [
+        ['TODO', 'TODO'],
+    ]
+
+    def __init__(self, **kwargs):
+        self.channels = -1
+        self.lastsample = None
+
+    def start(self, metadata):
+        # self.out_proto = self.add(srd.OUTPUT_PROTO, 'transitioncounter')
+        self.out_ann = self.add(srd.OUTPUT_ANN, 'transitioncounter')
+
+    def report(self):
+        pass
+
+    def decode(self, ss, es, data):
+
+        for (samplenum, s) in data:
+
+            # ...
+            if self.channels == -1:
+                self.channels = len(s)
+                self.oldbit = [0] * self.channels
+                self.transitions = [0] * self.channels
+                self.rising = [0] * self.channels
+                self.falling = [0] * self.channels
+
+            # Optimization: Skip identical samples (no transitions).
+            if self.lastsample == s:
+                continue
+
+            # Upon the first sample, store the initial values.
+            if self.lastsample == None:
+                self.lastsample = s
+                for i in range(self.channels):
+                    self.oldbit[i] = self.lastsample[i]
+
+            # Iterate over all channels/probes in this sample.
+            # Count rising and falling edges for each channel.
+            for i in range(self.channels):
+                curbit = s[i]
+                # Optimization: Skip identical bits (no transitions).
+                if self.oldbit[i] == curbit:
+                    continue
+                elif (self.oldbit[i] == 0 and curbit == 1):
+                    self.rising[i] += 1
+                elif (self.oldbit[i] == 1 and curbit == 0):
+                    self.falling[i] += 1
+                self.oldbit[i] = curbit
+
+            # Save the current sample as 'lastsample' for the next round.
+            self.lastsample = s
+
+        # Total number of transitions = rising + falling edges.
+        for i in range(self.channels):
+            self.transitions[i] = self.rising[i] + self.falling[i]
+
+        # TODO: Which output format?
+        # TODO: How to only output something after the last chunk of data?
+        outdata = []
+        for i in range(self.channels):
+            outdata.append([self.transitions[i], self.rising[i],
+                            self.falling[i]])
+
+        if outdata != []:
+            # self.put(0, 0, self.out_proto, out_proto)
+            self.put(0, 0, self.out_ann, [0, [str(outdata)]])
+
diff --git a/decoders/transitioncounter/transitioncounter.py b/decoders/transitioncounter/transitioncounter.py
deleted file mode 100644 (file)
index 9506cee..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-##
-## This file is part of the sigrok project.
-##
-## Copyright (C) 2010 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
-## the Free Software Foundation; either version 2 of the License, or
-## (at your option) any later version.
-##
-## This program is distributed in the hope that it will be useful,
-## but WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-## GNU General Public License for more details.
-##
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, write to the Free Software
-## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
-##
-
-# Transition counter protocol decoder
-
-import sigrokdecode as srd
-
-class Decoder(srd.Decoder):
-    api_version = 1
-    id = 'transitioncounter'
-    name = 'Transition counter'
-    longname = 'Pin transition counter'
-    desc = 'Counts rising/falling edges in the signal.'
-    license = 'gplv2+'
-    inputs = ['logic']
-    outputs = ['transitioncounts']
-    probes = []
-    optional_probes = []
-    options = {}
-    annotations = [
-        ['TODO', 'TODO'],
-    ]
-
-    def __init__(self, **kwargs):
-        self.channels = -1
-        self.lastsample = None
-
-    def start(self, metadata):
-        # self.out_proto = self.add(srd.OUTPUT_PROTO, 'transitioncounter')
-        self.out_ann = self.add(srd.OUTPUT_ANN, 'transitioncounter')
-
-    def report(self):
-        pass
-
-    def decode(self, ss, es, data):
-
-        for (samplenum, s) in data:
-
-            # ...
-            if self.channels == -1:
-                self.channels = len(s)
-                self.oldbit = [0] * self.channels
-                self.transitions = [0] * self.channels
-                self.rising = [0] * self.channels
-                self.falling = [0] * self.channels
-
-            # Optimization: Skip identical samples (no transitions).
-            if self.lastsample == s:
-                continue
-
-            # Upon the first sample, store the initial values.
-            if self.lastsample == None:
-                self.lastsample = s
-                for i in range(self.channels):
-                    self.oldbit[i] = self.lastsample[i]
-
-            # Iterate over all channels/probes in this sample.
-            # Count rising and falling edges for each channel.
-            for i in range(self.channels):
-                curbit = s[i]
-                # Optimization: Skip identical bits (no transitions).
-                if self.oldbit[i] == curbit:
-                    continue
-                elif (self.oldbit[i] == 0 and curbit == 1):
-                    self.rising[i] += 1
-                elif (self.oldbit[i] == 1 and curbit == 0):
-                    self.falling[i] += 1
-                self.oldbit[i] = curbit
-
-            # Save the current sample as 'lastsample' for the next round.
-            self.lastsample = s
-
-        # Total number of transitions = rising + falling edges.
-        for i in range(self.channels):
-            self.transitions[i] = self.rising[i] + self.falling[i]
-
-        # TODO: Which output format?
-        # TODO: How to only output something after the last chunk of data?
-        outdata = []
-        for i in range(self.channels):
-            outdata.append([self.transitions[i], self.rising[i],
-                            self.falling[i]])
-
-        if outdata != []:
-            # self.put(0, 0, self.out_proto, out_proto)
-            self.put(0, 0, self.out_ann, [0, [str(outdata)]])
-
index 155bfc989db9bf3c0b3887bae7ab8c49546374f5..61efbd0c8aa9bd60db2c1e14c9c5e64a7363f941 100644 (file)
@@ -20,7 +20,7 @@
 
 pkgdatadir = $(DECODERS_DIR)/uart
 
-dist_pkgdata_DATA = __init__.py uart.py
+dist_pkgdata_DATA = __init__.py pd.py
 
 CLEANFILES = *.pyc
 
index ecba2e1ac04a03893354ee5c2292015488ddd050..23e2dd0398afedb9a61c9eabd35c04b114308f12 100644 (file)
@@ -111,5 +111,5 @@ This is the list of <packet-type>s and their respective <packet-data>:
 The <rxtx> field is 0 for RX packets, 1 for TX packets.
 '''
 
-from .uart import *
+from .pd import *
 
diff --git a/decoders/uart/pd.py b/decoders/uart/pd.py
new file mode 100644 (file)
index 0000000..24551da
--- /dev/null
@@ -0,0 +1,304 @@
+##
+## This file is part of the sigrok project.
+##
+## Copyright (C) 2011-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
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+##
+
+# UART protocol decoder
+
+import sigrokdecode as srd
+
+# Used for differentiating between the two data directions.
+RX = 0
+TX = 1
+
+# Annotation feed formats
+ANN_ASCII = 0
+ANN_DEC = 1
+ANN_HEX = 2
+ANN_OCT = 3
+ANN_BITS = 4
+
+# Given a parity type to check (odd, even, zero, one), the value of the
+# parity bit, the value of the data, and the length of the data (5-9 bits,
+# usually 8 bits) return True if the parity is correct, False otherwise.
+# 'none' is _not_ allowed as value for 'parity_type'.
+def parity_ok(parity_type, parity_bit, data, num_data_bits):
+
+    # Handle easy cases first (parity bit is always 1 or 0).
+    if parity_type == 'zero':
+        return parity_bit == 0
+    elif parity_type == 'one':
+        return parity_bit == 1
+
+    # Count number of 1 (high) bits in the data (and the parity bit itself!).
+    ones = bin(data).count('1') + parity_bit
+
+    # Check for odd/even parity.
+    if parity_type == 'odd':
+        return (ones % 2) == 1
+    elif parity_type == 'even':
+        return (ones % 2) == 0
+    else:
+        raise Exception('Invalid parity type: %d' % parity_type)
+
+class Decoder(srd.Decoder):
+    api_version = 1
+    id = 'uart'
+    name = 'UART'
+    longname = 'Universal Asynchronous Receiver/Transmitter'
+    desc = 'Asynchronous, serial bus.'
+    license = 'gplv2+'
+    inputs = ['logic']
+    outputs = ['uart']
+    probes = [
+        # Allow specifying only one of the signals, e.g. if only one data
+        # direction exists (or is relevant).
+        {'id': 'rx', 'name': 'RX', 'desc': 'UART receive line'},
+        {'id': 'tx', 'name': 'TX', 'desc': 'UART transmit line'},
+    ]
+    optional_probes = []
+    options = {
+        'baudrate': ['Baud rate', 115200],
+        'num_data_bits': ['Data bits', 8], # Valid: 5-9.
+        'parity_type': ['Parity type', 'none'],
+        'parity_check': ['Check parity?', 'yes'], # TODO: Bool supported?
+        'num_stop_bits': ['Stop bit(s)', '1'], # String! 0, 0.5, 1, 1.5.
+        'bit_order': ['Bit order', 'lsb-first'],
+        # TODO: Options to invert the signal(s).
+    }
+    annotations = [
+        ['ASCII', 'Data bytes as ASCII characters'],
+        ['Decimal', 'Databytes as decimal, integer values'],
+        ['Hex', 'Data bytes in hex format'],
+        ['Octal', 'Data bytes as octal numbers'],
+        ['Bits', 'Data bytes in bit notation (sequence of 0/1 digits)'],
+    ]
+
+    def putx(self, rxtx, data):
+        self.put(self.startsample[rxtx], self.samplenum - 1, self.out_ann, data)
+
+    def __init__(self, **kwargs):
+        self.samplenum = 0
+        self.frame_start = [-1, -1]
+        self.startbit = [-1, -1]
+        self.cur_data_bit = [0, 0]
+        self.databyte = [0, 0]
+        self.paritybit = [-1, -1]
+        self.stopbit1 = [-1, -1]
+        self.startsample = [-1, -1]
+        self.state = ['WAIT FOR START BIT', 'WAIT FOR START BIT']
+        self.oldbit = [None, None]
+        self.oldpins = None
+
+    def start(self, metadata):
+        self.samplerate = metadata['samplerate']
+        self.out_proto = self.add(srd.OUTPUT_PROTO, 'uart')
+        self.out_ann = self.add(srd.OUTPUT_ANN, 'uart')
+
+        # The width of one UART bit in number of samples.
+        self.bit_width = \
+            float(self.samplerate) / float(self.options['baudrate'])
+
+    def report(self):
+        pass
+
+    # Return true if we reached the middle of the desired bit, false otherwise.
+    def reached_bit(self, rxtx, bitnum):
+        # bitpos is the samplenumber which is in the middle of the
+        # specified UART bit (0 = start bit, 1..x = data, x+1 = parity bit
+        # (if used) or the first stop bit, and so on).
+        bitpos = self.frame_start[rxtx] + (self.bit_width / 2.0)
+        bitpos += bitnum * self.bit_width
+        if self.samplenum >= bitpos:
+            return True
+        return False
+
+    def reached_bit_last(self, rxtx, bitnum):
+        bitpos = self.frame_start[rxtx] + ((bitnum + 1) * self.bit_width)
+        if self.samplenum >= bitpos:
+            return True
+        return False
+
+    def wait_for_start_bit(self, rxtx, old_signal, signal):
+        # The start bit is always 0 (low). As the idle UART (and the stop bit)
+        # level is 1 (high), the beginning of a start bit is a falling edge.
+        if not (old_signal == 1 and signal == 0):
+            return
+
+        # Save the sample number where the start bit begins.
+        self.frame_start[rxtx] = self.samplenum
+
+        self.state[rxtx] = 'GET START BIT'
+
+    def get_start_bit(self, rxtx, signal):
+        # Skip samples until we're in the middle of the start bit.
+        if not self.reached_bit(rxtx, 0):
+            return
+
+        self.startbit[rxtx] = signal
+
+        # The startbit must be 0. If not, we report an error.
+        if self.startbit[rxtx] != 0:
+            self.put(self.frame_start[rxtx], self.samplenum, self.out_proto,
+                     ['INVALID STARTBIT', rxtx, self.startbit[rxtx]])
+            # TODO: Abort? Ignore rest of the frame?
+
+        self.cur_data_bit[rxtx] = 0
+        self.databyte[rxtx] = 0
+        self.startsample[rxtx] = -1
+
+        self.state[rxtx] = 'GET DATA BITS'
+
+        self.put(self.frame_start[rxtx], self.samplenum, self.out_proto,
+                 ['STARTBIT', rxtx, self.startbit[rxtx]])
+        self.put(self.frame_start[rxtx], self.samplenum, self.out_ann,
+                 [ANN_ASCII, ['Start bit', 'Start', 'S']])
+
+    def get_data_bits(self, rxtx, signal):
+        # Skip samples until we're in the middle of the desired data bit.
+        if not self.reached_bit(rxtx, self.cur_data_bit[rxtx] + 1):
+            return
+
+        # Save the sample number where the data byte starts.
+        if self.startsample[rxtx] == -1:
+            self.startsample[rxtx] = self.samplenum
+
+        # Get the next data bit in LSB-first or MSB-first fashion.
+        if self.options['bit_order'] == 'lsb-first':
+            self.databyte[rxtx] >>= 1
+            self.databyte[rxtx] |= \
+                (signal << (self.options['num_data_bits'] - 1))
+        elif self.options['bit_order'] == 'msb-first':
+            self.databyte[rxtx] <<= 1
+            self.databyte[rxtx] |= (signal << 0)
+        else:
+            raise Exception('Invalid bit order value: %s',
+                            self.options['bit_order'])
+
+        # Return here, unless we already received all data bits.
+        # TODO? Off-by-one?
+        if self.cur_data_bit[rxtx] < self.options['num_data_bits'] - 1:
+            self.cur_data_bit[rxtx] += 1
+            return
+
+        self.state[rxtx] = 'GET PARITY BIT'
+
+        self.put(self.startsample[rxtx], self.samplenum - 1, self.out_proto,
+                 ['DATA', rxtx, self.databyte[rxtx]])
+
+        s = 'RX: ' if (rxtx == RX) else 'TX: '
+        self.putx(rxtx, [ANN_ASCII, [s + chr(self.databyte[rxtx])]])
+        self.putx(rxtx, [ANN_DEC,   [s + str(self.databyte[rxtx])]])
+        self.putx(rxtx, [ANN_HEX,   [s + hex(self.databyte[rxtx]),
+                                     s + hex(self.databyte[rxtx])[2:]]])
+        self.putx(rxtx, [ANN_OCT,   [s + oct(self.databyte[rxtx]),
+                                     s + oct(self.databyte[rxtx])[2:]]])
+        self.putx(rxtx, [ANN_BITS,  [s + bin(self.databyte[rxtx]),
+                                     s + bin(self.databyte[rxtx])[2:]]])
+
+    def get_parity_bit(self, rxtx, signal):
+        # If no parity is used/configured, skip to the next state immediately.
+        if self.options['parity_type'] == 'none':
+            self.state[rxtx] = 'GET STOP BITS'
+            return
+
+        # Skip samples until we're in the middle of the parity bit.
+        if not self.reached_bit(rxtx, self.options['num_data_bits'] + 1):
+            return
+
+        self.paritybit[rxtx] = signal
+
+        self.state[rxtx] = 'GET STOP BITS'
+
+        if parity_ok(self.options['parity_type'], self.paritybit[rxtx],
+                     self.databyte[rxtx], self.options['num_data_bits']):
+            # TODO: Fix range.
+            self.put(self.samplenum, self.samplenum, self.out_proto,
+                     ['PARITYBIT', rxtx, self.paritybit[rxtx]])
+            self.put(self.samplenum, self.samplenum, self.out_ann,
+                     [ANN_ASCII, ['Parity bit', 'Parity', 'P']])
+        else:
+            # TODO: Fix range.
+            # TODO: Return expected/actual parity values.
+            self.put(self.samplenum, self.samplenum, self.out_proto,
+                     ['PARITY ERROR', rxtx, (0, 1)]) # FIXME: Dummy tuple...
+            self.put(self.samplenum, self.samplenum, self.out_ann,
+                     [ANN_ASCII, ['Parity error', 'Parity err', 'PE']])
+
+    # TODO: Currently only supports 1 stop bit.
+    def get_stop_bits(self, rxtx, signal):
+        # Skip samples until we're in the middle of the stop bit(s).
+        skip_parity = 0 if self.options['parity_type'] == 'none' else 1
+        b = self.options['num_data_bits'] + 1 + skip_parity
+        if not self.reached_bit(rxtx, b):
+            return
+
+        self.stopbit1[rxtx] = signal
+
+        # Stop bits must be 1. If not, we report an error.
+        if self.stopbit1[rxtx] != 1:
+            self.put(self.frame_start[rxtx], self.samplenum, self.out_proto,
+                     ['INVALID STOPBIT', rxtx, self.stopbit1[rxtx]])
+            # TODO: Abort? Ignore the frame? Other?
+
+        self.state[rxtx] = 'WAIT FOR START BIT'
+
+        # TODO: Fix range.
+        self.put(self.samplenum, self.samplenum, self.out_proto,
+                 ['STOPBIT', rxtx, self.stopbit1[rxtx]])
+        self.put(self.samplenum, self.samplenum, self.out_ann,
+                 [ANN_ASCII, ['Stop bit', 'Stop', 'P']])
+
+    def decode(self, ss, es, data):
+        # TODO: Either RX or TX could be omitted (optional probe).
+        for (self.samplenum, pins) in data:
+
+            # Note: Ignoring identical samples here for performance reasons
+            # is not possible for this PD, at least not in the current state.
+            # if self.oldpins == pins:
+            #     continue
+            self.oldpins, (rx, tx) = pins, pins
+
+            # First sample: Save RX/TX value.
+            if self.oldbit[RX] == None:
+                self.oldbit[RX] = rx
+                continue
+            if self.oldbit[TX] == None:
+                self.oldbit[TX] = tx
+                continue
+
+            # State machine.
+            for rxtx in (RX, TX):
+                signal = rx if (rxtx == RX) else tx
+
+                if self.state[rxtx] == 'WAIT FOR START BIT':
+                    self.wait_for_start_bit(rxtx, self.oldbit[rxtx], signal)
+                elif self.state[rxtx] == 'GET START BIT':
+                    self.get_start_bit(rxtx, signal)
+                elif self.state[rxtx] == 'GET DATA BITS':
+                    self.get_data_bits(rxtx, signal)
+                elif self.state[rxtx] == 'GET PARITY BIT':
+                    self.get_parity_bit(rxtx, signal)
+                elif self.state[rxtx] == 'GET STOP BITS':
+                    self.get_stop_bits(rxtx, signal)
+                else:
+                    raise Exception('Invalid state: %d' % self.state[rxtx])
+
+                # Save current RX/TX values for the next round.
+                self.oldbit[rxtx] = signal
+
diff --git a/decoders/uart/uart.py b/decoders/uart/uart.py
deleted file mode 100644 (file)
index 24551da..0000000
+++ /dev/null
@@ -1,304 +0,0 @@
-##
-## This file is part of the sigrok project.
-##
-## Copyright (C) 2011-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
-## the Free Software Foundation; either version 2 of the License, or
-## (at your option) any later version.
-##
-## This program is distributed in the hope that it will be useful,
-## but WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-## GNU General Public License for more details.
-##
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, write to the Free Software
-## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
-##
-
-# UART protocol decoder
-
-import sigrokdecode as srd
-
-# Used for differentiating between the two data directions.
-RX = 0
-TX = 1
-
-# Annotation feed formats
-ANN_ASCII = 0
-ANN_DEC = 1
-ANN_HEX = 2
-ANN_OCT = 3
-ANN_BITS = 4
-
-# Given a parity type to check (odd, even, zero, one), the value of the
-# parity bit, the value of the data, and the length of the data (5-9 bits,
-# usually 8 bits) return True if the parity is correct, False otherwise.
-# 'none' is _not_ allowed as value for 'parity_type'.
-def parity_ok(parity_type, parity_bit, data, num_data_bits):
-
-    # Handle easy cases first (parity bit is always 1 or 0).
-    if parity_type == 'zero':
-        return parity_bit == 0
-    elif parity_type == 'one':
-        return parity_bit == 1
-
-    # Count number of 1 (high) bits in the data (and the parity bit itself!).
-    ones = bin(data).count('1') + parity_bit
-
-    # Check for odd/even parity.
-    if parity_type == 'odd':
-        return (ones % 2) == 1
-    elif parity_type == 'even':
-        return (ones % 2) == 0
-    else:
-        raise Exception('Invalid parity type: %d' % parity_type)
-
-class Decoder(srd.Decoder):
-    api_version = 1
-    id = 'uart'
-    name = 'UART'
-    longname = 'Universal Asynchronous Receiver/Transmitter'
-    desc = 'Asynchronous, serial bus.'
-    license = 'gplv2+'
-    inputs = ['logic']
-    outputs = ['uart']
-    probes = [
-        # Allow specifying only one of the signals, e.g. if only one data
-        # direction exists (or is relevant).
-        {'id': 'rx', 'name': 'RX', 'desc': 'UART receive line'},
-        {'id': 'tx', 'name': 'TX', 'desc': 'UART transmit line'},
-    ]
-    optional_probes = []
-    options = {
-        'baudrate': ['Baud rate', 115200],
-        'num_data_bits': ['Data bits', 8], # Valid: 5-9.
-        'parity_type': ['Parity type', 'none'],
-        'parity_check': ['Check parity?', 'yes'], # TODO: Bool supported?
-        'num_stop_bits': ['Stop bit(s)', '1'], # String! 0, 0.5, 1, 1.5.
-        'bit_order': ['Bit order', 'lsb-first'],
-        # TODO: Options to invert the signal(s).
-    }
-    annotations = [
-        ['ASCII', 'Data bytes as ASCII characters'],
-        ['Decimal', 'Databytes as decimal, integer values'],
-        ['Hex', 'Data bytes in hex format'],
-        ['Octal', 'Data bytes as octal numbers'],
-        ['Bits', 'Data bytes in bit notation (sequence of 0/1 digits)'],
-    ]
-
-    def putx(self, rxtx, data):
-        self.put(self.startsample[rxtx], self.samplenum - 1, self.out_ann, data)
-
-    def __init__(self, **kwargs):
-        self.samplenum = 0
-        self.frame_start = [-1, -1]
-        self.startbit = [-1, -1]
-        self.cur_data_bit = [0, 0]
-        self.databyte = [0, 0]
-        self.paritybit = [-1, -1]
-        self.stopbit1 = [-1, -1]
-        self.startsample = [-1, -1]
-        self.state = ['WAIT FOR START BIT', 'WAIT FOR START BIT']
-        self.oldbit = [None, None]
-        self.oldpins = None
-
-    def start(self, metadata):
-        self.samplerate = metadata['samplerate']
-        self.out_proto = self.add(srd.OUTPUT_PROTO, 'uart')
-        self.out_ann = self.add(srd.OUTPUT_ANN, 'uart')
-
-        # The width of one UART bit in number of samples.
-        self.bit_width = \
-            float(self.samplerate) / float(self.options['baudrate'])
-
-    def report(self):
-        pass
-
-    # Return true if we reached the middle of the desired bit, false otherwise.
-    def reached_bit(self, rxtx, bitnum):
-        # bitpos is the samplenumber which is in the middle of the
-        # specified UART bit (0 = start bit, 1..x = data, x+1 = parity bit
-        # (if used) or the first stop bit, and so on).
-        bitpos = self.frame_start[rxtx] + (self.bit_width / 2.0)
-        bitpos += bitnum * self.bit_width
-        if self.samplenum >= bitpos:
-            return True
-        return False
-
-    def reached_bit_last(self, rxtx, bitnum):
-        bitpos = self.frame_start[rxtx] + ((bitnum + 1) * self.bit_width)
-        if self.samplenum >= bitpos:
-            return True
-        return False
-
-    def wait_for_start_bit(self, rxtx, old_signal, signal):
-        # The start bit is always 0 (low). As the idle UART (and the stop bit)
-        # level is 1 (high), the beginning of a start bit is a falling edge.
-        if not (old_signal == 1 and signal == 0):
-            return
-
-        # Save the sample number where the start bit begins.
-        self.frame_start[rxtx] = self.samplenum
-
-        self.state[rxtx] = 'GET START BIT'
-
-    def get_start_bit(self, rxtx, signal):
-        # Skip samples until we're in the middle of the start bit.
-        if not self.reached_bit(rxtx, 0):
-            return
-
-        self.startbit[rxtx] = signal
-
-        # The startbit must be 0. If not, we report an error.
-        if self.startbit[rxtx] != 0:
-            self.put(self.frame_start[rxtx], self.samplenum, self.out_proto,
-                     ['INVALID STARTBIT', rxtx, self.startbit[rxtx]])
-            # TODO: Abort? Ignore rest of the frame?
-
-        self.cur_data_bit[rxtx] = 0
-        self.databyte[rxtx] = 0
-        self.startsample[rxtx] = -1
-
-        self.state[rxtx] = 'GET DATA BITS'
-
-        self.put(self.frame_start[rxtx], self.samplenum, self.out_proto,
-                 ['STARTBIT', rxtx, self.startbit[rxtx]])
-        self.put(self.frame_start[rxtx], self.samplenum, self.out_ann,
-                 [ANN_ASCII, ['Start bit', 'Start', 'S']])
-
-    def get_data_bits(self, rxtx, signal):
-        # Skip samples until we're in the middle of the desired data bit.
-        if not self.reached_bit(rxtx, self.cur_data_bit[rxtx] + 1):
-            return
-
-        # Save the sample number where the data byte starts.
-        if self.startsample[rxtx] == -1:
-            self.startsample[rxtx] = self.samplenum
-
-        # Get the next data bit in LSB-first or MSB-first fashion.
-        if self.options['bit_order'] == 'lsb-first':
-            self.databyte[rxtx] >>= 1
-            self.databyte[rxtx] |= \
-                (signal << (self.options['num_data_bits'] - 1))
-        elif self.options['bit_order'] == 'msb-first':
-            self.databyte[rxtx] <<= 1
-            self.databyte[rxtx] |= (signal << 0)
-        else:
-            raise Exception('Invalid bit order value: %s',
-                            self.options['bit_order'])
-
-        # Return here, unless we already received all data bits.
-        # TODO? Off-by-one?
-        if self.cur_data_bit[rxtx] < self.options['num_data_bits'] - 1:
-            self.cur_data_bit[rxtx] += 1
-            return
-
-        self.state[rxtx] = 'GET PARITY BIT'
-
-        self.put(self.startsample[rxtx], self.samplenum - 1, self.out_proto,
-                 ['DATA', rxtx, self.databyte[rxtx]])
-
-        s = 'RX: ' if (rxtx == RX) else 'TX: '
-        self.putx(rxtx, [ANN_ASCII, [s + chr(self.databyte[rxtx])]])
-        self.putx(rxtx, [ANN_DEC,   [s + str(self.databyte[rxtx])]])
-        self.putx(rxtx, [ANN_HEX,   [s + hex(self.databyte[rxtx]),
-                                     s + hex(self.databyte[rxtx])[2:]]])
-        self.putx(rxtx, [ANN_OCT,   [s + oct(self.databyte[rxtx]),
-                                     s + oct(self.databyte[rxtx])[2:]]])
-        self.putx(rxtx, [ANN_BITS,  [s + bin(self.databyte[rxtx]),
-                                     s + bin(self.databyte[rxtx])[2:]]])
-
-    def get_parity_bit(self, rxtx, signal):
-        # If no parity is used/configured, skip to the next state immediately.
-        if self.options['parity_type'] == 'none':
-            self.state[rxtx] = 'GET STOP BITS'
-            return
-
-        # Skip samples until we're in the middle of the parity bit.
-        if not self.reached_bit(rxtx, self.options['num_data_bits'] + 1):
-            return
-
-        self.paritybit[rxtx] = signal
-
-        self.state[rxtx] = 'GET STOP BITS'
-
-        if parity_ok(self.options['parity_type'], self.paritybit[rxtx],
-                     self.databyte[rxtx], self.options['num_data_bits']):
-            # TODO: Fix range.
-            self.put(self.samplenum, self.samplenum, self.out_proto,
-                     ['PARITYBIT', rxtx, self.paritybit[rxtx]])
-            self.put(self.samplenum, self.samplenum, self.out_ann,
-                     [ANN_ASCII, ['Parity bit', 'Parity', 'P']])
-        else:
-            # TODO: Fix range.
-            # TODO: Return expected/actual parity values.
-            self.put(self.samplenum, self.samplenum, self.out_proto,
-                     ['PARITY ERROR', rxtx, (0, 1)]) # FIXME: Dummy tuple...
-            self.put(self.samplenum, self.samplenum, self.out_ann,
-                     [ANN_ASCII, ['Parity error', 'Parity err', 'PE']])
-
-    # TODO: Currently only supports 1 stop bit.
-    def get_stop_bits(self, rxtx, signal):
-        # Skip samples until we're in the middle of the stop bit(s).
-        skip_parity = 0 if self.options['parity_type'] == 'none' else 1
-        b = self.options['num_data_bits'] + 1 + skip_parity
-        if not self.reached_bit(rxtx, b):
-            return
-
-        self.stopbit1[rxtx] = signal
-
-        # Stop bits must be 1. If not, we report an error.
-        if self.stopbit1[rxtx] != 1:
-            self.put(self.frame_start[rxtx], self.samplenum, self.out_proto,
-                     ['INVALID STOPBIT', rxtx, self.stopbit1[rxtx]])
-            # TODO: Abort? Ignore the frame? Other?
-
-        self.state[rxtx] = 'WAIT FOR START BIT'
-
-        # TODO: Fix range.
-        self.put(self.samplenum, self.samplenum, self.out_proto,
-                 ['STOPBIT', rxtx, self.stopbit1[rxtx]])
-        self.put(self.samplenum, self.samplenum, self.out_ann,
-                 [ANN_ASCII, ['Stop bit', 'Stop', 'P']])
-
-    def decode(self, ss, es, data):
-        # TODO: Either RX or TX could be omitted (optional probe).
-        for (self.samplenum, pins) in data:
-
-            # Note: Ignoring identical samples here for performance reasons
-            # is not possible for this PD, at least not in the current state.
-            # if self.oldpins == pins:
-            #     continue
-            self.oldpins, (rx, tx) = pins, pins
-
-            # First sample: Save RX/TX value.
-            if self.oldbit[RX] == None:
-                self.oldbit[RX] = rx
-                continue
-            if self.oldbit[TX] == None:
-                self.oldbit[TX] = tx
-                continue
-
-            # State machine.
-            for rxtx in (RX, TX):
-                signal = rx if (rxtx == RX) else tx
-
-                if self.state[rxtx] == 'WAIT FOR START BIT':
-                    self.wait_for_start_bit(rxtx, self.oldbit[rxtx], signal)
-                elif self.state[rxtx] == 'GET START BIT':
-                    self.get_start_bit(rxtx, signal)
-                elif self.state[rxtx] == 'GET DATA BITS':
-                    self.get_data_bits(rxtx, signal)
-                elif self.state[rxtx] == 'GET PARITY BIT':
-                    self.get_parity_bit(rxtx, signal)
-                elif self.state[rxtx] == 'GET STOP BITS':
-                    self.get_stop_bits(rxtx, signal)
-                else:
-                    raise Exception('Invalid state: %d' % self.state[rxtx])
-
-                # Save current RX/TX values for the next round.
-                self.oldbit[rxtx] = signal
-
index d95618c8a492789b0481801a002263717d22812f..ca9f532dadbeb64d8851cbccc60f6711e0daf072 100644 (file)
@@ -20,7 +20,7 @@
 
 pkgdatadir = $(DECODERS_DIR)/uart_dump
 
-dist_pkgdata_DATA = __init__.py uart_dump.py
+dist_pkgdata_DATA = __init__.py pd.py
 
 CLEANFILES = *.pyc
 
index 06a6d95d0dc8bc3498daf029d17f59282eb0d954..ea351ab6af6e2a43f2b73fca71d6265c33a0291b 100644 (file)
@@ -25,5 +25,5 @@ Details:
 TODO
 '''
 
-from .uart_dump import *
+from .pd import *
 
diff --git a/decoders/uart_dump/pd.py b/decoders/uart_dump/pd.py
new file mode 100644 (file)
index 0000000..1174832
--- /dev/null
@@ -0,0 +1,110 @@
+##
+## This file is part of the sigrok project.
+##
+## 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
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+##
+
+import sigrokdecode as srd
+import os
+import sys
+
+RX = 0
+TX = 1
+
+class Decoder(srd.Decoder):
+    api_version = 1
+    id = 'uart_dump'
+    name = 'UART dump'
+    longname = 'UART dump'
+    desc = 'Output decoded UART data to a file.'
+    license = 'gplv2+'
+    inputs = ['uart']
+    outputs = [] # TODO?
+    probes = []
+    optional_probes = []
+    options = {
+        'rx': ['Output RX data?', 'yes'],
+        'tx': ['Output TX data?', 'yes'],
+        'filename': ['File name for RX and TX data', '-'],
+        'filename_rx': ['File name for RX data', 'none'],
+        'filename_tx': ['File name for TX data', 'none'],
+    }
+    annotations = []
+
+    def __init__(self, **kwargs):
+        self.f = None
+        self.f_rx = None
+        self.f_tx = None
+
+    def file_open(self, filename):
+        if filename == 'none':
+            return None
+        elif filename == '-':
+            return sys.stdout
+        else:
+            return open(filename, 'w')
+
+    def start(self, metadata):
+        # The user can specify 'filename' (gets both RX and TX data), and/or
+        # 'filename_rx' (for RX data only), and/or 'filename_tx', respectively.
+
+        # Default is to output RX and TX to 'filename', with 'filename_rx' and
+        # 'filename_tx' being unused.
+
+        # If multiple 'filename*' options are specified, the user must NOT
+        # use the same file for any of them.
+
+        # A filename of 'none' is not allowed (has special meaning). A filename
+        # of '-' means 'stdout'.
+
+        self.f = self.file_open(self.options['filename'])
+        self.f_rx = self.file_open(self.options['filename_rx'])
+        self.f_tx = self.file_open(self.options['filename_tx'])
+
+    def report(self):
+        pass
+
+    def decode(self, ss, es, data):
+        ptype, rxtx, pdata = data
+
+        # Ignore all UART packets except the actual data packets (i.e., we
+        # do not print start bits, parity bits, stop bits, errors, and so on).
+        if ptype != 'DATA':
+            return
+
+        # TODO: Configurable format.
+        c = chr(pdata)
+
+        # TODO: Error handling.
+
+        # Output RX and/or TX to 'filename'.
+        if self.f != None:
+            self.f.write(c)
+            self.f.flush()
+
+        # Output RX data to 'filename_rx'.
+        if self.f_rx != None:
+            if self.options['rx'] == 'yes' and rxtx == RX:
+                self.f_rx.write(c)
+                self.f_rx.flush()
+
+        # Output TX data to 'filename_tx'.
+        if self.f_tx != None:
+            if self.options['tx'] == 'yes' and rxtx == TX:
+                self.f_tx.write(c)
+                self.f_tx.flush()
+
diff --git a/decoders/uart_dump/uart_dump.py b/decoders/uart_dump/uart_dump.py
deleted file mode 100644 (file)
index 1174832..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-##
-## This file is part of the sigrok project.
-##
-## 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
-## the Free Software Foundation; either version 2 of the License, or
-## (at your option) any later version.
-##
-## This program is distributed in the hope that it will be useful,
-## but WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-## GNU General Public License for more details.
-##
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, write to the Free Software
-## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
-##
-
-import sigrokdecode as srd
-import os
-import sys
-
-RX = 0
-TX = 1
-
-class Decoder(srd.Decoder):
-    api_version = 1
-    id = 'uart_dump'
-    name = 'UART dump'
-    longname = 'UART dump'
-    desc = 'Output decoded UART data to a file.'
-    license = 'gplv2+'
-    inputs = ['uart']
-    outputs = [] # TODO?
-    probes = []
-    optional_probes = []
-    options = {
-        'rx': ['Output RX data?', 'yes'],
-        'tx': ['Output TX data?', 'yes'],
-        'filename': ['File name for RX and TX data', '-'],
-        'filename_rx': ['File name for RX data', 'none'],
-        'filename_tx': ['File name for TX data', 'none'],
-    }
-    annotations = []
-
-    def __init__(self, **kwargs):
-        self.f = None
-        self.f_rx = None
-        self.f_tx = None
-
-    def file_open(self, filename):
-        if filename == 'none':
-            return None
-        elif filename == '-':
-            return sys.stdout
-        else:
-            return open(filename, 'w')
-
-    def start(self, metadata):
-        # The user can specify 'filename' (gets both RX and TX data), and/or
-        # 'filename_rx' (for RX data only), and/or 'filename_tx', respectively.
-
-        # Default is to output RX and TX to 'filename', with 'filename_rx' and
-        # 'filename_tx' being unused.
-
-        # If multiple 'filename*' options are specified, the user must NOT
-        # use the same file for any of them.
-
-        # A filename of 'none' is not allowed (has special meaning). A filename
-        # of '-' means 'stdout'.
-
-        self.f = self.file_open(self.options['filename'])
-        self.f_rx = self.file_open(self.options['filename_rx'])
-        self.f_tx = self.file_open(self.options['filename_tx'])
-
-    def report(self):
-        pass
-
-    def decode(self, ss, es, data):
-        ptype, rxtx, pdata = data
-
-        # Ignore all UART packets except the actual data packets (i.e., we
-        # do not print start bits, parity bits, stop bits, errors, and so on).
-        if ptype != 'DATA':
-            return
-
-        # TODO: Configurable format.
-        c = chr(pdata)
-
-        # TODO: Error handling.
-
-        # Output RX and/or TX to 'filename'.
-        if self.f != None:
-            self.f.write(c)
-            self.f.flush()
-
-        # Output RX data to 'filename_rx'.
-        if self.f_rx != None:
-            if self.options['rx'] == 'yes' and rxtx == RX:
-                self.f_rx.write(c)
-                self.f_rx.flush()
-
-        # Output TX data to 'filename_tx'.
-        if self.f_tx != None:
-            if self.options['tx'] == 'yes' and rxtx == TX:
-                self.f_tx.write(c)
-                self.f_tx.flush()
-
index 599092bc5c51b5aa82e576960e035be575e4563c..d76c1a455dfabf19c77e735ed382a72dc6f4639a 100644 (file)
@@ -20,7 +20,7 @@
 
 pkgdatadir = $(DECODERS_DIR)/usb_protocol
 
-dist_pkgdata_DATA = __init__.py usb_protocol.py
+dist_pkgdata_DATA = __init__.py pd.py
 
 CLEANFILES = *.pyc
 
index a19304e4efdba842dfbfcbd377fee333f83bd5a3..735e3f8a8f55b30aa3c1e91a108dbb2b656eaab6 100644 (file)
@@ -43,5 +43,5 @@ https://en.wikipedia.org/wiki/USB
 http://www.usb.org/developers/docs/
 '''
 
-from .usb_protocol import *
+from .pd import *
 
diff --git a/decoders/usb_protocol/pd.py b/decoders/usb_protocol/pd.py
new file mode 100644 (file)
index 0000000..b1cd33b
--- /dev/null
@@ -0,0 +1,137 @@
+##
+## This file is part of the sigrok project.
+##
+## Copyright (C) 2011 Gareth McMullin <gareth@blacksphere.co.nz>
+## 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
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+##
+
+# USB (low-speed and full-speed) protocol decoder
+
+import sigrokdecode as srd
+
+# Packet IDs (PIDs).
+# The first 4 bits are the 'packet type' field, the last 4 bits are the
+# 'check field' (each bit in the check field must be the inverse of the resp.
+# bit in the 'packet type' field; if not, that's a 'PID error').
+# For the 4-bit strings, the left-most '1' or '0' is the LSB, i.e. it's sent
+# to the bus first.
+pids = {
+    # Tokens
+    '10000111': ['OUT', 'Address & EP number in host-to-function transaction'],
+    '10010110': ['IN', 'Address & EP number in function-to-host transaction'],
+    '10100101': ['SOF', 'Start-Of-Frame marker & frame number'],
+    '10110100': ['SETUP', 'Address & EP number in host-to-function transaction for SETUP to a control pipe'],
+
+    # Data
+    # Note: DATA2 and MDATA are HS-only.
+    '11000011': ['DATA0', 'Data packet PID even'],
+    '11010010': ['DATA1', 'Data packet PID odd'],
+    '11100001': ['DATA2', 'Data packet PID HS, high bandwidth isosynchronous transaction in a microframe'],
+    '11110000': ['MDATA', 'Data packet PID HS for split and high-bandwidth isosynchronous transactions'],
+
+    # Handshake
+    '01001011': ['ACK', 'Receiver accepts error-free packet'],
+    '01011010': ['NAK', 'Receiver cannot accept or transmitter cannot send'],
+    '01111000': ['STALL', 'EP halted or control pipe request unsupported'],
+    '01101001': ['NYET', 'No response yet from receiver'],
+
+    # Special
+    '00111100': ['PRE', 'Host-issued preamble; enables downstream bus traffic to low-speed devices'],
+    '00111100': ['ERR', 'Split transaction error handshake'],
+    '00011110': ['SPLIT', 'HS split transaction token'],
+    '00101101': ['PING', 'HS flow control probe for a bulk/control EP'],
+    '00001111': ['Reserved', 'Reserved PID'],
+}
+
+def bitstr_to_num(bitstr):
+    if not bitstr:
+        return 0
+    l = list(bitstr)
+    l.reverse()
+    return int(''.join(l), 2)
+
+def packet_decode(packet):
+    sync = packet[:8]
+    pid = packet[8:16]
+    pid = pids.get(pid, (pid, ''))[0]
+
+    # Remove CRC.
+    if pid in ('OUT', 'IN', 'SOF', 'SETUP'):
+        data = packet[16:-5]
+        if pid == 'SOF':
+            data = str(bitstr_to_num(data))
+        else:
+            dev = bitstr_to_num(data[:7])
+            ep = bitstr_to_num(data[7:])
+            data = 'DEV %d EP %d' % (dev, ep)
+    elif pid in ('DATA0', 'DATA1'):
+        data = packet[16:-16]
+        tmp = ''
+        while data:
+            tmp += '%02x ' % bitstr_to_num(data[:8])
+            data = data[8:]
+        data = tmp
+    else:
+        data = packet[16:]
+
+    # The SYNC pattern for low-speed/full-speed is KJKJKJKK (0001).
+    if sync != '00000001':
+        return 'SYNC INVALID: %s' % sync
+
+    return pid + ' ' + data
+
+class Decoder(srd.Decoder):
+    api_version = 1
+    id = 'usb_protocol'
+    name = 'USB protocol'
+    longname = 'Universal Serial Bus (LS/FS) protocol'
+    desc = 'USB 1.x (low-speed and full-speed) serial protocol.'
+    license = 'gplv2+'
+    inputs = ['usb_signalling']
+    outputs = ['usb_protocol']
+    probes = []
+    optional_probes = []
+    options = {
+        'signalling': ['Signalling', 'full-speed'],
+    }
+    annotations = [
+        ['Text', 'Human-readable text']
+    ]
+
+    def __init__(self):
+        self.sym = 'J'
+        self.samplenum = 0
+        self.scount = 0
+        self.packet = ''
+        self.state = 'IDLE'
+
+    def start(self, metadata):
+        self.samplerate = metadata['samplerate']
+        self.out_proto = self.add(srd.OUTPUT_PROTO, 'usb_protocol')
+        self.out_ann = self.add(srd.OUTPUT_ANN, 'usb_protocol')
+
+    def report(self):
+        pass
+
+    def decode(self, ss, es, data):
+        (ptype, pdata) = data
+
+        if ptype == 'PACKET':
+            self.put(0, 0, self.out_ann, [0, [packet_decode(pdata)]])
+
+        # TODO.
+
diff --git a/decoders/usb_protocol/usb_protocol.py b/decoders/usb_protocol/usb_protocol.py
deleted file mode 100644 (file)
index b1cd33b..0000000
+++ /dev/null
@@ -1,137 +0,0 @@
-##
-## This file is part of the sigrok project.
-##
-## Copyright (C) 2011 Gareth McMullin <gareth@blacksphere.co.nz>
-## 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
-## the Free Software Foundation; either version 2 of the License, or
-## (at your option) any later version.
-##
-## This program is distributed in the hope that it will be useful,
-## but WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-## GNU General Public License for more details.
-##
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, write to the Free Software
-## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
-##
-
-# USB (low-speed and full-speed) protocol decoder
-
-import sigrokdecode as srd
-
-# Packet IDs (PIDs).
-# The first 4 bits are the 'packet type' field, the last 4 bits are the
-# 'check field' (each bit in the check field must be the inverse of the resp.
-# bit in the 'packet type' field; if not, that's a 'PID error').
-# For the 4-bit strings, the left-most '1' or '0' is the LSB, i.e. it's sent
-# to the bus first.
-pids = {
-    # Tokens
-    '10000111': ['OUT', 'Address & EP number in host-to-function transaction'],
-    '10010110': ['IN', 'Address & EP number in function-to-host transaction'],
-    '10100101': ['SOF', 'Start-Of-Frame marker & frame number'],
-    '10110100': ['SETUP', 'Address & EP number in host-to-function transaction for SETUP to a control pipe'],
-
-    # Data
-    # Note: DATA2 and MDATA are HS-only.
-    '11000011': ['DATA0', 'Data packet PID even'],
-    '11010010': ['DATA1', 'Data packet PID odd'],
-    '11100001': ['DATA2', 'Data packet PID HS, high bandwidth isosynchronous transaction in a microframe'],
-    '11110000': ['MDATA', 'Data packet PID HS for split and high-bandwidth isosynchronous transactions'],
-
-    # Handshake
-    '01001011': ['ACK', 'Receiver accepts error-free packet'],
-    '01011010': ['NAK', 'Receiver cannot accept or transmitter cannot send'],
-    '01111000': ['STALL', 'EP halted or control pipe request unsupported'],
-    '01101001': ['NYET', 'No response yet from receiver'],
-
-    # Special
-    '00111100': ['PRE', 'Host-issued preamble; enables downstream bus traffic to low-speed devices'],
-    '00111100': ['ERR', 'Split transaction error handshake'],
-    '00011110': ['SPLIT', 'HS split transaction token'],
-    '00101101': ['PING', 'HS flow control probe for a bulk/control EP'],
-    '00001111': ['Reserved', 'Reserved PID'],
-}
-
-def bitstr_to_num(bitstr):
-    if not bitstr:
-        return 0
-    l = list(bitstr)
-    l.reverse()
-    return int(''.join(l), 2)
-
-def packet_decode(packet):
-    sync = packet[:8]
-    pid = packet[8:16]
-    pid = pids.get(pid, (pid, ''))[0]
-
-    # Remove CRC.
-    if pid in ('OUT', 'IN', 'SOF', 'SETUP'):
-        data = packet[16:-5]
-        if pid == 'SOF':
-            data = str(bitstr_to_num(data))
-        else:
-            dev = bitstr_to_num(data[:7])
-            ep = bitstr_to_num(data[7:])
-            data = 'DEV %d EP %d' % (dev, ep)
-    elif pid in ('DATA0', 'DATA1'):
-        data = packet[16:-16]
-        tmp = ''
-        while data:
-            tmp += '%02x ' % bitstr_to_num(data[:8])
-            data = data[8:]
-        data = tmp
-    else:
-        data = packet[16:]
-
-    # The SYNC pattern for low-speed/full-speed is KJKJKJKK (0001).
-    if sync != '00000001':
-        return 'SYNC INVALID: %s' % sync
-
-    return pid + ' ' + data
-
-class Decoder(srd.Decoder):
-    api_version = 1
-    id = 'usb_protocol'
-    name = 'USB protocol'
-    longname = 'Universal Serial Bus (LS/FS) protocol'
-    desc = 'USB 1.x (low-speed and full-speed) serial protocol.'
-    license = 'gplv2+'
-    inputs = ['usb_signalling']
-    outputs = ['usb_protocol']
-    probes = []
-    optional_probes = []
-    options = {
-        'signalling': ['Signalling', 'full-speed'],
-    }
-    annotations = [
-        ['Text', 'Human-readable text']
-    ]
-
-    def __init__(self):
-        self.sym = 'J'
-        self.samplenum = 0
-        self.scount = 0
-        self.packet = ''
-        self.state = 'IDLE'
-
-    def start(self, metadata):
-        self.samplerate = metadata['samplerate']
-        self.out_proto = self.add(srd.OUTPUT_PROTO, 'usb_protocol')
-        self.out_ann = self.add(srd.OUTPUT_ANN, 'usb_protocol')
-
-    def report(self):
-        pass
-
-    def decode(self, ss, es, data):
-        (ptype, pdata) = data
-
-        if ptype == 'PACKET':
-            self.put(0, 0, self.out_ann, [0, [packet_decode(pdata)]])
-
-        # TODO.
-
index 316c62cf1a55d2dd5ef093ab91c23e10d935b3dc..6a54eb326885efb59fb63323ca100ec69d47d5e0 100644 (file)
@@ -20,7 +20,7 @@
 
 pkgdatadir = $(DECODERS_DIR)/usb_signalling
 
-dist_pkgdata_DATA = __init__.py usb_signalling.py
+dist_pkgdata_DATA = __init__.py pd.py
 
 CLEANFILES = *.pyc
 
index 026875c538d210e0244ae241e8f4df5315ad1aa1..98ae8723e90a3451466e36d9b9499e1474186d48 100644 (file)
@@ -51,5 +51,5 @@ https://en.wikipedia.org/wiki/USB
 http://www.usb.org/developers/docs/
 '''
 
-from .usb_signalling import *
+from .pd import *
 
diff --git a/decoders/usb_signalling/pd.py b/decoders/usb_signalling/pd.py
new file mode 100644 (file)
index 0000000..3272cbf
--- /dev/null
@@ -0,0 +1,152 @@
+##
+## This file is part of the sigrok project.
+##
+## Copyright (C) 2011 Gareth McMullin <gareth@blacksphere.co.nz>
+## 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
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+##
+
+# USB signalling (low-speed and full-speed) protocol decoder
+
+import sigrokdecode as srd
+
+# Low-/full-speed symbols (used as states of our state machine, too).
+# Note: Low-speed J and K are inverted compared to the full-speed J and K!
+symbols_ls = {
+        # (<dp>, <dm>): <symbol/state>
+        (0, 0): 'SE0',
+        (1, 0): 'K',
+        (0, 1): 'J',
+        (1, 1): 'SE1',
+}
+symbols_fs = {
+        # (<dp>, <dm>): <symbol/state>
+        (0, 0): 'SE0',
+        (1, 0): 'J',
+        (0, 1): 'K',
+        (1, 1): 'SE1',
+}
+
+class Decoder(srd.Decoder):
+    api_version = 1
+    id = 'usb_signalling'
+    name = 'USB signalling'
+    longname = 'Universal Serial Bus (LS/FS) signalling'
+    desc = 'USB 1.x (low-speed and full-speed) signalling protocol.'
+    license = 'gplv2+'
+    inputs = ['logic']
+    outputs = ['usb_signalling']
+    probes = [
+        {'id': 'dp', 'name': 'D+', 'desc': 'USB D+ signal'},
+        {'id': 'dm', 'name': 'D-', 'desc': 'USB D- signal'},
+    ]
+    optional_probes = []
+    options = {
+        'signalling': ['Signalling', 'full-speed'],
+    }
+    annotations = [
+        ['Text', 'Human-readable text']
+    ]
+
+    def __init__(self):
+        self.sym = 'J' # The "idle" state is J.
+        self.samplenum = 0
+        self.scount = 0
+        self.packet = ''
+        self.syms = []
+        self.oldpins = None
+
+    def start(self, metadata):
+        self.samplerate = metadata['samplerate']
+        self.out_proto = self.add(srd.OUTPUT_PROTO, 'usb_signalling')
+        self.out_ann = self.add(srd.OUTPUT_ANN, 'usb_signalling')
+
+    def report(self):
+        pass
+
+    def decode(self, ss, es, data):
+        for (self.samplenum, pins) in data:
+
+            # Note: self.samplenum is the absolute sample number, whereas
+            # self.scount only counts the number of samples since the
+            # last change in the D+/D- lines.
+            self.scount += 1
+
+            # Ignore identical samples early on (for performance reasons).
+            if self.oldpins == pins:
+                continue
+            self.oldpins, (dp, dm) = pins, pins
+
+            if self.options['signalling'] == 'low-speed':
+                sym = symbols_ls[dp, dm]
+            elif self.options['signalling'] == 'full-speed':
+                sym = symbols_fs[dp, dm]
+
+            self.put(0, 0, self.out_ann, [0, [sym]])
+            self.put(0, 0, self.out_proto, ['SYM', sym])
+
+            # Wait for a symbol change (i.e., change in D+/D- lines).
+            if sym == self.sym:
+                continue
+
+            ## # Debug code:
+            ## self.syms.append(sym + ' ')
+            ## if len(self.syms) == 16:
+            ##     self.put(0, 0, self.out_ann, [0, [''.join(self.syms)]])
+            ##     self.syms = []
+            # continue
+
+            # How many bits since the last transition?
+            if self.packet != '' or self.sym != 'J':
+                if self.options['signalling'] == 'low-speed':
+                    bitrate = 1500000 # 1.5Mb/s (+/- 1.5%)
+                elif self.options['signalling'] == 'full-speed':
+                    bitrate = 12000000 # 12Mb/s (+/- 0.25%)
+                bitcount = int((self.scount - 1) * bitrate / self.samplerate)
+            else:
+                bitcount = 0
+
+            if self.sym == 'SE0':
+                if bitcount == 1:
+                    # End-Of-Packet (EOP)
+                    # self.put(0, 0, self.out_ann,
+                    #          [0, [packet_decode(self.packet), self.packet]])
+                    if self.packet != '': # FIXME?
+                        self.put(0, 0, self.out_ann, [0, ['PACKET: %s' % self.packet]])
+                        self.put(0, 0, self.out_proto, ['PACKET', self.packet])
+                else:
+                    # Longer than EOP, assume reset.
+                    self.put(0, 0, self.out_ann, [0, ['RESET']])
+                    self.put(0, 0, self.out_proto, ['RESET', None])
+                # self.put(0, 0, self.out_ann, [0, [self.packet]])
+                self.scount = 0
+                self.sym = sym
+                self.packet = ''
+                continue
+
+            # Add bits to the packet string.
+            self.packet += '1' * bitcount
+
+            # Handle bit stuffing.
+            if bitcount < 6 and sym != 'SE0':
+                self.packet += '0'
+            elif bitcount > 6:
+                self.put(0, 0, self.out_ann, [0, ['BIT STUFF ERROR']])
+                self.put(0, 0, self.out_proto, ['BIT STUFF ERROR', None])
+
+            self.scount = 0
+            self.sym = sym
+
diff --git a/decoders/usb_signalling/usb_signalling.py b/decoders/usb_signalling/usb_signalling.py
deleted file mode 100644 (file)
index 3272cbf..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-##
-## This file is part of the sigrok project.
-##
-## Copyright (C) 2011 Gareth McMullin <gareth@blacksphere.co.nz>
-## 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
-## the Free Software Foundation; either version 2 of the License, or
-## (at your option) any later version.
-##
-## This program is distributed in the hope that it will be useful,
-## but WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-## GNU General Public License for more details.
-##
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, write to the Free Software
-## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
-##
-
-# USB signalling (low-speed and full-speed) protocol decoder
-
-import sigrokdecode as srd
-
-# Low-/full-speed symbols (used as states of our state machine, too).
-# Note: Low-speed J and K are inverted compared to the full-speed J and K!
-symbols_ls = {
-        # (<dp>, <dm>): <symbol/state>
-        (0, 0): 'SE0',
-        (1, 0): 'K',
-        (0, 1): 'J',
-        (1, 1): 'SE1',
-}
-symbols_fs = {
-        # (<dp>, <dm>): <symbol/state>
-        (0, 0): 'SE0',
-        (1, 0): 'J',
-        (0, 1): 'K',
-        (1, 1): 'SE1',
-}
-
-class Decoder(srd.Decoder):
-    api_version = 1
-    id = 'usb_signalling'
-    name = 'USB signalling'
-    longname = 'Universal Serial Bus (LS/FS) signalling'
-    desc = 'USB 1.x (low-speed and full-speed) signalling protocol.'
-    license = 'gplv2+'
-    inputs = ['logic']
-    outputs = ['usb_signalling']
-    probes = [
-        {'id': 'dp', 'name': 'D+', 'desc': 'USB D+ signal'},
-        {'id': 'dm', 'name': 'D-', 'desc': 'USB D- signal'},
-    ]
-    optional_probes = []
-    options = {
-        'signalling': ['Signalling', 'full-speed'],
-    }
-    annotations = [
-        ['Text', 'Human-readable text']
-    ]
-
-    def __init__(self):
-        self.sym = 'J' # The "idle" state is J.
-        self.samplenum = 0
-        self.scount = 0
-        self.packet = ''
-        self.syms = []
-        self.oldpins = None
-
-    def start(self, metadata):
-        self.samplerate = metadata['samplerate']
-        self.out_proto = self.add(srd.OUTPUT_PROTO, 'usb_signalling')
-        self.out_ann = self.add(srd.OUTPUT_ANN, 'usb_signalling')
-
-    def report(self):
-        pass
-
-    def decode(self, ss, es, data):
-        for (self.samplenum, pins) in data:
-
-            # Note: self.samplenum is the absolute sample number, whereas
-            # self.scount only counts the number of samples since the
-            # last change in the D+/D- lines.
-            self.scount += 1
-
-            # Ignore identical samples early on (for performance reasons).
-            if self.oldpins == pins:
-                continue
-            self.oldpins, (dp, dm) = pins, pins
-
-            if self.options['signalling'] == 'low-speed':
-                sym = symbols_ls[dp, dm]
-            elif self.options['signalling'] == 'full-speed':
-                sym = symbols_fs[dp, dm]
-
-            self.put(0, 0, self.out_ann, [0, [sym]])
-            self.put(0, 0, self.out_proto, ['SYM', sym])
-
-            # Wait for a symbol change (i.e., change in D+/D- lines).
-            if sym == self.sym:
-                continue
-
-            ## # Debug code:
-            ## self.syms.append(sym + ' ')
-            ## if len(self.syms) == 16:
-            ##     self.put(0, 0, self.out_ann, [0, [''.join(self.syms)]])
-            ##     self.syms = []
-            # continue
-
-            # How many bits since the last transition?
-            if self.packet != '' or self.sym != 'J':
-                if self.options['signalling'] == 'low-speed':
-                    bitrate = 1500000 # 1.5Mb/s (+/- 1.5%)
-                elif self.options['signalling'] == 'full-speed':
-                    bitrate = 12000000 # 12Mb/s (+/- 0.25%)
-                bitcount = int((self.scount - 1) * bitrate / self.samplerate)
-            else:
-                bitcount = 0
-
-            if self.sym == 'SE0':
-                if bitcount == 1:
-                    # End-Of-Packet (EOP)
-                    # self.put(0, 0, self.out_ann,
-                    #          [0, [packet_decode(self.packet), self.packet]])
-                    if self.packet != '': # FIXME?
-                        self.put(0, 0, self.out_ann, [0, ['PACKET: %s' % self.packet]])
-                        self.put(0, 0, self.out_proto, ['PACKET', self.packet])
-                else:
-                    # Longer than EOP, assume reset.
-                    self.put(0, 0, self.out_ann, [0, ['RESET']])
-                    self.put(0, 0, self.out_proto, ['RESET', None])
-                # self.put(0, 0, self.out_ann, [0, [self.packet]])
-                self.scount = 0
-                self.sym = sym
-                self.packet = ''
-                continue
-
-            # Add bits to the packet string.
-            self.packet += '1' * bitcount
-
-            # Handle bit stuffing.
-            if bitcount < 6 and sym != 'SE0':
-                self.packet += '0'
-            elif bitcount > 6:
-                self.put(0, 0, self.out_ann, [0, ['BIT STUFF ERROR']])
-                self.put(0, 0, self.out_proto, ['BIT STUFF ERROR', None])
-
-            self.scount = 0
-            self.sym = sym
-