X-Git-Url: https://sigrok.org/gitweb/?p=libsigrokdecode.git;a=blobdiff_plain;f=decoders%2Fi2c%2Fpd.py;h=0aed1ffe505a3a95e4167ebc0d4003869e1e04fe;hp=40baf44e572e47f7fe8b1c5db66fdcec93da5d99;hb=a250a66dddc795295d7758f09d40463ddaf62eb8;hpb=0eeeb544e1ea3cef9669f98e7c0b19b8f73a9236 diff --git a/decoders/i2c/pd.py b/decoders/i2c/pd.py index 40baf44..0aed1ff 100644 --- a/decoders/i2c/pd.py +++ b/decoders/i2c/pd.py @@ -1,7 +1,7 @@ ## -## This file is part of the sigrok project. +## This file is part of the libsigrokdecode project. ## -## Copyright (C) 2010-2011 Uwe Hermann +## Copyright (C) 2010-2013 Uwe Hermann ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by @@ -21,33 +21,46 @@ # 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 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. +''' +Protocol output format: + +I2C packet: +[, ] + + is one of: + - 'START' (START condition) + - 'START REPEAT' (Repeated START condition) + - 'ADDRESS READ' (Slave address, read) + - 'ADDRESS WRITE' (Slave address, write) + - 'DATA READ' (Data, read) + - 'DATA WRITE' (Data, write) + - 'STOP' (STOP condition) + - 'ACK' (ACK bit) + - 'NACK' (NACK bit) + + is the data or address byte associated with the 'ADDRESS*' and 'DATA*' +command. Slave addresses do not include bit 0 (the READ/WRITE indication bit). +For example, a slave address field could be 0x51 (instead of 0xa2). +For 'START', 'START REPEAT', 'STOP', 'ACK', and 'NACK' is None. +''' + +# CMD: [annotation-type-index, long annotation, short annotation] 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'], + 'START': [0, 'Start', 'S'], + 'START REPEAT': [1, 'Start repeat', 'Sr'], + 'STOP': [2, 'Stop', 'P'], + 'ACK': [3, 'ACK', 'A'], + 'NACK': [4, 'NACK', 'N'], + 'ADDRESS READ': [5, 'Address read', 'AR'], + 'ADDRESS WRITE': [6, 'Address write', 'AW'], + 'DATA READ': [7, 'Data read', 'DR'], + 'DATA WRITE': [8, 'Data write', 'DW'], } class Decoder(srd.Decoder): @@ -65,17 +78,19 @@ class Decoder(srd.Decoder): ] optional_probes = [] options = { - 'addressing': ['Slave addressing (in bits)', 7], # 7 or 10 + 'address_format': ['Displayed slave address format', 'shifted'], } 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'], + ['Start', 'Start condition'], + ['Repeat start', 'Repeat start condition'], + ['Stop', 'Stop condition'], + ['ACK', 'ACK'], + ['NACK', 'NACK'], + ['Address read', 'Address read'], + ['Address write', 'Address write'], + ['Data read', 'Data read'], + ['Data write', 'Data write'], + ['Warnings', 'Human-readable warnings'], ] def __init__(self, **kwargs): @@ -86,9 +101,9 @@ class Decoder(srd.Decoder): self.wr = -1 self.is_repeat_start = 0 self.state = 'FIND START' - self.oldscl = None - self.oldsda = None - self.oldpins = None + self.oldscl = 1 + self.oldsda = 1 + self.oldpins = [1, 1] def start(self, metadata): self.out_proto = self.add(srd.OUTPUT_PROTO, 'i2c') @@ -97,6 +112,12 @@ class Decoder(srd.Decoder): def report(self): pass + def putx(self, data): + self.put(self.startsample, self.samplenum, self.out_ann, data) + + def putp(self, data): + self.put(self.startsample, self.samplenum, self.out_proto, data) + def is_start_condition(self, scl, sda): # START condition (S): SDA = falling, SCL = high if (self.oldsda == 1 and sda == 0) and scl == 1: @@ -117,12 +138,9 @@ class Decoder(srd.Decoder): 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.putp([cmd, None]) + self.putx([proto[cmd][0], proto[cmd][1:]]) self.state = 'FIND ADDRESS' self.bitcount = self.databyte = 0 self.is_repeat_start = 1 @@ -145,16 +163,12 @@ class Decoder(srd.Decoder): # 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]]) - + d = 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.options['address_format'] == 'shifted': + d = d >> 1 if self.state == 'FIND ADDRESS' and self.wr == 1: cmd = 'ADDRESS WRITE' @@ -165,9 +179,9 @@ class Decoder(srd.Decoder): 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]]) + self.putp([cmd, d]) + self.putx([proto[cmd][0], ['%s: %02X' % (proto[cmd][1], d), + '%s: %02X' % (proto[cmd][2], d), '%02X' % d]]) # Done with this packet. self.startsample = -1 @@ -176,28 +190,22 @@ class Decoder(srd.Decoder): 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]]]) + cmd = 'NACK' if (sda == 1) else 'ACK' + self.putp([cmd, None]) + self.putx([proto[cmd][0], proto[cmd][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]]]) - + cmd = 'STOP' + self.putp([cmd, None]) + self.putx([proto[cmd][0], proto[cmd][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: @@ -206,12 +214,6 @@ class Decoder(srd.Decoder): 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.