pkgdatadir = $(DECODERS_DIR)/dcf77
-dist_pkgdata_DATA = __init__.py dcf77.py
+dist_pkgdata_DATA = __init__.py pd.py
CLEANFILES = *.pyc
http://en.wikipedia.org/wiki/DCF77
'''
-from .dcf77 import *
+from .pd import *
+++ /dev/null
-##
-## 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
-
--- /dev/null
+##
+## 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
+
pkgdatadir = $(DECODERS_DIR)/edid
-dist_pkgdata_DATA = __init__.py edid.py pnpids.txt
+dist_pkgdata_DATA = __init__.py pd.py pnpids.txt
CLEANFILES = *.pyc
https://en.wikipedia.org/wiki/Extended_display_identification_data
'''
-from .edid import *
+from .pd import *
+++ /dev/null
-##
-## 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)
-
--- /dev/null
+##
+## 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)
+
pkgdatadir = $(DECODERS_DIR)/i2c
-dist_pkgdata_DATA = __init__.py i2c.py
+dist_pkgdata_DATA = __init__.py pd.py
CLEANFILES = *.pyc
'''
-from .i2c import *
+from .pd import *
+++ /dev/null
-##
-## 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
-
--- /dev/null
+##
+## 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
+
pkgdatadir = $(DECODERS_DIR)/i2cdemux
-dist_pkgdata_DATA = __init__.py i2cdemux.py
+dist_pkgdata_DATA = __init__.py pd.py
CLEANFILES = *.pyc
containing only I2C packets for one specific I2C slave.
'''
-from .i2cdemux import *
+from .pd import *
+++ /dev/null
-##
-## 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.
-
--- /dev/null
+##
+## 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.
+
pkgdatadir = $(DECODERS_DIR)/i2cfilter
-dist_pkgdata_DATA = __init__.py i2cfilter.py
+dist_pkgdata_DATA = __init__.py pd.py
CLEANFILES = *.pyc
of the I2C session will be output.
'''
-from .i2cfilter import *
+from .pd import *
+++ /dev/null
-##
-## 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.
-
--- /dev/null
+##
+## 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.
+
pkgdatadir = $(DECODERS_DIR)/i2s
-dist_pkgdata_DATA = __init__.py i2s.py
+dist_pkgdata_DATA = __init__.py pd.py
CLEANFILES = *.pyc
http://en.wikipedia.org/wiki/I2s
'''
-from .i2s import *
+from .pd import *
+++ /dev/null
-##
-## 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
-
--- /dev/null
+##
+## 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
+
pkgdatadir = $(DECODERS_DIR)/jtag
-dist_pkgdata_DATA = __init__.py jtag.py
+dist_pkgdata_DATA = __init__.py pd.py
CLEANFILES = *.pyc
http://focus.ti.com/lit/an/ssya002c/ssya002c.pdf
'''
-from .jtag import *
+from .pd import *
+++ /dev/null
-##
-## 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
-
--- /dev/null
+##
+## 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
+
pkgdatadir = $(DECODERS_DIR)/jtag_stm32
-dist_pkgdata_DATA = __init__.py jtag_stm32.py
+dist_pkgdata_DATA = __init__.py pd.py
CLEANFILES = *.pyc
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 *
+++ /dev/null
-##
-## 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)
-
--- /dev/null
+##
+## 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)
+
pkgdatadir = $(DECODERS_DIR)/lm75
-dist_pkgdata_DATA = __init__.py lm75.py
+dist_pkgdata_DATA = __init__.py pd.py
CLEANFILES = *.pyc
TODO.
'''
-from .lm75 import *
+from .pd import *
+++ /dev/null
-##
-## 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)
-
--- /dev/null
+##
+## 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)
+
pkgdatadir = $(DECODERS_DIR)/lpc
-dist_pkgdata_DATA = __init__.py lpc.py
+dist_pkgdata_DATA = __init__.py pd.py
CLEANFILES = *.pyc
TODO
'''
-from .lpc import *
+from .pd import *
+++ /dev/null
-##
-## 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)
-
--- /dev/null
+##
+## 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)
+
pkgdatadir = $(DECODERS_DIR)/maxim_ds28ea00
-dist_pkgdata_DATA = __init__.py maxim_ds28ea00.py
+dist_pkgdata_DATA = __init__.py pd.py
CLEANFILES = *.pyc
TODO
'''
-from .maxim_ds28ea00 import *
+from .pd import *
+++ /dev/null
-##
-## 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)
-
--- /dev/null
+##
+## 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)
+
pkgdatadir = $(DECODERS_DIR)/mlx90614
-dist_pkgdata_DATA = __init__.py mlx90614.py
+dist_pkgdata_DATA = __init__.py pd.py
CLEANFILES = *.pyc
TODO
'''
-from .mlx90614 import *
+from .pd import *
+++ /dev/null
-##
-## 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)
-
--- /dev/null
+##
+## 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)
+
pkgdatadir = $(DECODERS_DIR)/mx25lxx05d
-dist_pkgdata_DATA = __init__.py mx25lxx05d.py
+dist_pkgdata_DATA = __init__.py pd.py
CLEANFILES = *.pyc
http://www.macronix.com/QuickPlace/hq/PageLibrary4825740B00298A3B.nsf/h_Index/3F21BAC2E121E17848257639003A3146/$File/MX25L1605D-3205D-6405D-1.5.pdf
'''
-from .mx25lxx05d import *
+from .pd import *
+++ /dev/null
-##
-## 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
-
--- /dev/null
+##
+## 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
+
pkgdatadir = $(DECODERS_DIR)/mxc6225xu
-dist_pkgdata_DATA = __init__.py mxc6225xu.py
+dist_pkgdata_DATA = __init__.py pd.py
CLEANFILES = *.pyc
TODO
'''
-from .mxc6225xu import *
+from .pd import *
+++ /dev/null
-##
-## 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)
-
--- /dev/null
+##
+## 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)
+
pkgdatadir = $(DECODERS_DIR)/nunchuk
-dist_pkgdata_DATA = __init__.py nunchuk.py
+dist_pkgdata_DATA = __init__.py pd.py
CLEANFILES = *.pyc
https://www.sparkfun.com/products/9281
'''
-from .nunchuk import *
+from .pd import *
+++ /dev/null
-##
-## 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)
-
--- /dev/null
+##
+## 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)
+
pkgdatadir = $(DECODERS_DIR)/onewire_link
-dist_pkgdata_DATA = __init__.py onewire_link.py
+dist_pkgdata_DATA = __init__.py pd.py
CLEANFILES = *.pyc
- Maybe add support for interrupts, check if this feature is deprecated.
'''
-from .onewire_link import *
+from .pd import *
+++ /dev/null
-##
-## 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)
--- /dev/null
+##
+## 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)
pkgdatadir = $(DECODERS_DIR)/onewire_network
-dist_pkgdata_DATA = __init__.py onewire_network.py
+dist_pkgdata_DATA = __init__.py pd.py
CLEANFILES = *.pyc
- Add reporting original/complement address values from the search algorithm.
'''
-from .onewire_network import *
+from .pd import *
+++ /dev/null
-##
-## 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
--- /dev/null
+##
+## 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
pkgdatadir = $(DECODERS_DIR)/pan1321
-dist_pkgdata_DATA = __init__.py pan1321.py
+dist_pkgdata_DATA = __init__.py pd.py
CLEANFILES = *.pyc
TODO
'''
-from .pan1321 import *
+from .pd import *
+++ /dev/null
-##
-## 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)
-
--- /dev/null
+##
+## 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)
+
pkgdatadir = $(DECODERS_DIR)/rtc8564
-dist_pkgdata_DATA = __init__.py rtc8564.py
+dist_pkgdata_DATA = __init__.py pd.py
CLEANFILES = *.pyc
TODO
'''
-from .rtc8564 import *
+from .pd import *
--- /dev/null
+##
+## 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)
+
+++ /dev/null
-##
-## 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)
-
pkgdatadir = $(DECODERS_DIR)/spi
-dist_pkgdata_DATA = __init__.py spi.py
+dist_pkgdata_DATA = __init__.py pd.py
CLEANFILES = *.pyc
'''
-from .spi import *
+from .pd import *
--- /dev/null
+##
+## 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
+
+++ /dev/null
-##
-## 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
-
pkgdatadir = $(DECODERS_DIR)/transitioncounter
-dist_pkgdata_DATA = __init__.py transitioncounter.py
+dist_pkgdata_DATA = __init__.py pd.py
CLEANFILES = *.pyc
TODO
'''
-from .transitioncounter import *
+from .pd import *
--- /dev/null
+##
+## 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)]])
+
+++ /dev/null
-##
-## 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)]])
-
pkgdatadir = $(DECODERS_DIR)/uart
-dist_pkgdata_DATA = __init__.py uart.py
+dist_pkgdata_DATA = __init__.py pd.py
CLEANFILES = *.pyc
The <rxtx> field is 0 for RX packets, 1 for TX packets.
'''
-from .uart import *
+from .pd import *
--- /dev/null
+##
+## 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
+
+++ /dev/null
-##
-## 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
-
pkgdatadir = $(DECODERS_DIR)/uart_dump
-dist_pkgdata_DATA = __init__.py uart_dump.py
+dist_pkgdata_DATA = __init__.py pd.py
CLEANFILES = *.pyc
TODO
'''
-from .uart_dump import *
+from .pd import *
--- /dev/null
+##
+## 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()
+
+++ /dev/null
-##
-## 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()
-
pkgdatadir = $(DECODERS_DIR)/usb_protocol
-dist_pkgdata_DATA = __init__.py usb_protocol.py
+dist_pkgdata_DATA = __init__.py pd.py
CLEANFILES = *.pyc
http://www.usb.org/developers/docs/
'''
-from .usb_protocol import *
+from .pd import *
--- /dev/null
+##
+## 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.
+
+++ /dev/null
-##
-## 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.
-
pkgdatadir = $(DECODERS_DIR)/usb_signalling
-dist_pkgdata_DATA = __init__.py usb_signalling.py
+dist_pkgdata_DATA = __init__.py pd.py
CLEANFILES = *.pyc
http://www.usb.org/developers/docs/
'''
-from .usb_signalling import *
+from .pd import *
--- /dev/null
+##
+## 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
+
+++ /dev/null
-##
-## 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
-