From: Mickael Bosch Date: Tue, 2 Jul 2019 14:31:12 +0000 (+0200) Subject: Add an NXP PCA9571 decoder. X-Git-Url: https://sigrok.org/gitweb/?p=libsigrokdecode.git;a=commitdiff_plain;h=70d258a5e53bb0cbdafe2277bb712bd12a2cc8cf Add an NXP PCA9571 decoder. --- diff --git a/decoders/pca9571/__init__.py b/decoders/pca9571/__init__.py new file mode 100644 index 0000000..28152d9 --- /dev/null +++ b/decoders/pca9571/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019 Mickael Bosch +## +## 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, see . +## + +''' +This decoder stacks on top of the 'i2c' PD and decodes the NXP Semiconductors +PCA9571 8-bit I²C output expander protocol. +''' + +from .pd import Decoder diff --git a/decoders/pca9571/pd.py b/decoders/pca9571/pd.py new file mode 100644 index 0000000..3832653 --- /dev/null +++ b/decoders/pca9571/pd.py @@ -0,0 +1,102 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019 Mickael Bosch +## +## 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, see . +## + +import sigrokdecode as srd + +NUM_OUTPUT_CHANNELS = 8 + +# TODO: Other I²C functions: general call / reset address, device ID address. + +class Decoder(srd.Decoder): + api_version = 3 + id = 'pca9571' + name = 'NXP PCA9571' + longname = 'NXP Semiconductors PCA9571' + desc = 'NXP PCA9571 8-bit I²C output expander.' + license = 'gplv2+' + inputs = ['i2c'] + outputs = [] + tags = ['Embedded/industrial', 'IC'] + annotations = ( + ('register', 'Register type'), + ('value', 'Register value'), + ('warning', 'Warning messages'), + ) + annotation_rows = ( + ('regs', 'Registers', (0, 1)), + ('warnings', 'Warnings', (2,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.state = 'IDLE' + self.last_write = 0xFF # Chip port default state is high. + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def putx(self, data): + self.put(self.ss, self.es, self.out_ann, data) + + def handle_io(self, b): + if self.state == 'READ DATA': + operation = ['Outputs read', 'R'] + if b != self.last_write: + self.putx([2, ['Warning: read value and last write value ' + '(%02X) are different' % self.last_write]]) + else: + operation = ['Outputs set', 'W'] + self.last_write = b + self.putx([1, [operation[0] + ': %02X' % b, + operation[1] + ': %02X' % b]]) + + def check_correct_chip(self, addr): + if addr != 0x25: + self.putx([2, ['Warning: I²C slave 0x%02X not a PCA9571 ' + 'compatible chip.' % addr]]) + return False + return True + + def decode(self, ss, es, data): + cmd, databyte = data + self.ss, self.es = ss, es + + # State machine. + if cmd in ('ACK', 'BITS'): # Discard 'ACK' and 'BITS'. + pass + elif cmd in ('START', 'START REPEAT'): # Start a communication. + self.state = 'GET SLAVE ADDR' + elif cmd in ('NACK', 'STOP'): # Reset the state machine. + self.state = 'IDLE' + elif cmd in ('ADDRESS READ', 'ADDRESS WRITE'): + if ((self.state == 'GET SLAVE ADDR') and + self.check_correct_chip(databyte)): + if cmd == 'ADDRESS READ': + self.state = 'READ DATA' + else: + self.state = 'WRITE DATA' + else: + self.state = 'IDLE' + elif cmd in ('DATA READ', 'DATA WRITE'): + if self.state in ('READ DATA', 'WRITE DATA'): + self.handle_io(databyte) + else: + self.state = 'IDLE'