X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=decoders%2Fi2c%2Fpd.py;h=60e9c452cd711524de5d0561f4d4d86e4d9700d4;hb=a929afa618be52072786b51f1b9ea7be03edcd49;hp=2500ae4cc6e036a7620a1dd5e2c0c830a3b05af7;hpb=d94ff143ef7725388299ef9bd3be7ebc60e0dd2e;p=libsigrokdecode.git diff --git a/decoders/i2c/pd.py b/decoders/i2c/pd.py index 2500ae4..60e9c45 100644 --- a/decoders/i2c/pd.py +++ b/decoders/i2c/pd.py @@ -21,17 +21,35 @@ # 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 +''' +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': [0, 'Start', 'S'], @@ -60,7 +78,6 @@ class Decoder(srd.Decoder): ] optional_probes = [] options = { - 'addressing': ['Slave addressing (in bits)', 7], # 7 or 10 'address_format': ['Displayed slave address format', 'shifted'], } annotations = [ @@ -75,8 +92,15 @@ class Decoder(srd.Decoder): ['Data write', 'Data write'], ['Warnings', 'Human-readable warnings'], ] + binary = ( + 'Address read', + 'Address write', + 'Data read', + 'Data write', + ) def __init__(self, **kwargs): + self.samplerate = None self.startsample = -1 self.samplenum = None self.bitcount = 0 @@ -87,13 +111,19 @@ class Decoder(srd.Decoder): self.oldscl = 1 self.oldsda = 1 self.oldpins = [1, 1] + self.pdu_start = None + self.pdu_bits = 0 - def start(self, metadata): - self.out_proto = self.add(srd.OUTPUT_PROTO, 'i2c') - self.out_ann = self.add(srd.OUTPUT_ANN, 'i2c') + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value - def report(self): - pass + def start(self): + self.out_proto = self.register(srd.OUTPUT_PYTHON) + self.out_ann = self.register(srd.OUTPUT_ANN) + self.out_binary = self.add(srd.OUTPUT_BINARY) + self.out_bitrate = self.register(srd.OUTPUT_META, + meta=(int, 'Bitrate', 'Bitrate from Start bit to Stop bit')) def putx(self, data): self.put(self.startsample, self.samplenum, self.out_ann, data) @@ -101,6 +131,9 @@ class Decoder(srd.Decoder): def putp(self, data): self.put(self.startsample, self.samplenum, self.out_proto, data) + def putb(self, data): + self.put(self.startsample, self.samplenum, self.out_binary, 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: @@ -121,6 +154,8 @@ class Decoder(srd.Decoder): def found_start(self, scl, sda): self.startsample = self.samplenum + self.pdu_start = self.samplenum + self.pdu_bits = 0 cmd = 'START REPEAT' if (self.is_repeat_start == 1) else 'START' self.putp([cmd, None]) self.putx([proto[cmd][0], proto[cmd][1:]]) @@ -153,18 +188,24 @@ class Decoder(srd.Decoder): if self.options['address_format'] == 'shifted': d = d >> 1 + bin_class = -1 if self.state == 'FIND ADDRESS' and self.wr == 1: cmd = 'ADDRESS WRITE' + bin_class = 1 elif self.state == 'FIND ADDRESS' and self.wr == 0: cmd = 'ADDRESS READ' + bin_class = 0 elif self.state == 'FIND DATA' and self.wr == 1: cmd = 'DATA WRITE' + bin_class = 3 elif self.state == 'FIND DATA' and self.wr == 0: cmd = 'DATA READ' + bin_class = 2 self.putp([cmd, d]) self.putx([proto[cmd][0], ['%s: %02X' % (proto[cmd][1], d), '%s: %02X' % (proto[cmd][2], d), '%02X' % d]]) + self.putb((bin_class, bytes([d]))) # Done with this packet. self.startsample = -1 @@ -181,6 +222,11 @@ class Decoder(srd.Decoder): self.state = 'FIND DATA' def found_stop(self, scl, sda): + # Meta bitrate + elapsed = 1 / float(self.samplerate) * (self.samplenum - self.pdu_start + 1) + bitrate = int(1 / elapsed * self.pdu_bits) + self.put(self.startsample, self.samplenum, self.out_bitrate, bitrate) + self.startsample = self.samplenum cmd = 'STOP' self.putp([cmd, None]) @@ -190,6 +236,8 @@ class Decoder(srd.Decoder): self.wr = -1 def decode(self, ss, es, data): + if self.samplerate is None: + raise Exception("Cannot decode without samplerate.") for (self.samplenum, pins) in data: # Ignore identical samples early on (for performance reasons). @@ -197,6 +245,8 @@ class Decoder(srd.Decoder): continue self.oldpins, (scl, sda) = pins, pins + self.pdu_bits += 1 + # TODO: Wait until the bus is idle (SDA = SCL = 1) first? # State machine.