From: BenediktO Date: Thu, 2 Jan 2020 18:02:28 +0000 (+0100) Subject: mcp230xx: Add an mcp230xx decoder X-Git-Url: https://sigrok.org/gitaction?a=commitdiff_plain;h=165bc5b75c70d66a5823271ac05220834251f9ff;p=libsigrokdecode.git mcp230xx: Add an mcp230xx decoder --- diff --git a/decoders/mcp230xx/__init__.py b/decoders/mcp230xx/__init__.py new file mode 100644 index 0000000..cee4c79 --- /dev/null +++ b/decoders/mcp230xx/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019 Benedikt Otto +## +## 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 Microchip +8-bit MCP23008 and 16-bit MCP23017 I²C output expander protocol. +''' + +from .pd import Decoder diff --git a/decoders/mcp230xx/pd.py b/decoders/mcp230xx/pd.py new file mode 100644 index 0000000..58a1bce --- /dev/null +++ b/decoders/mcp230xx/pd.py @@ -0,0 +1,143 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019 Benedikt Otto +## +## 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 + +STATE_IDLE, STATE_ADDR, STATE_DATA, STATE_READ_ADDR, STATE_READ_DATA, STATE_STOP = range(6) +UNKNOWN, READ, WRITE = range(3) + +registers = ["IODIR", "IPOL", "GPINTEN", "DEFVAL", "INTCON", "IOCON", "GPPU", "INTF", "INTCAP", "GPIO", "OLAT"] +registers_mcp23017_bank0 = {i: (registers[i // 2] + "AB"[i % 2] if registers[i // 2] != "IOCON" else "IOCON") for i in range(22)} + +registers_mcp23017_bank1 = {(i + 5 if i > 11 else i): (registers[i % 11] + "AB"[i // 11] if registers[i % 11] != "IOCON" else "IOCON") for i in range(22)} + +registers_mcp23008 = {i: registers[i] for i in range(11)} + +class Decoder(srd.Decoder): + api_version = 3 + id = 'mcp230xx' + name = 'MCP230XX' + longname = 'Microchip MCP230XX' + desc = 'MCP230XX 8/16-bit I²C output expanders.' + license = 'gplv2+' + inputs = ['i2c'] + outputs = [] + tags = ['IC'] + + options = ( + {'id': 'type', 'desc': 'Type', 'default': 'MCP23017', + 'values': ('MCP23008', 'MCP23017')}, + ) + + annotations = ( + ('register_read', 'Register read'), + ('register_write', 'Register write'), + ('warning', 'Warning'), + ) + annotation_rows = ( + ('regs', 'Registers', (0, 1)), + ('warnings', 'Warnings', (2,)), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.state = STATE_IDLE + self.iocon = 0 + self.iocon_set = False + + def start(self): + self.out_ann = self.register(srd.OUTPUT_ANN) + + def get_registers(self): + if self.options["type"] == "MCP23008": + return registers_mcp23008 + else: + return registers_mcp23017_bank1 if self.iocon & (1 << 7) else registers_mcp23017_bank0 + + def putx(self, ss, es, data): + self.put(ss, es, self.out_ann, data) + + def checkAddress(self, ss, es, address): + if not address in range(0x20, 0x27 + 1): + self.putx(ss, es, [2, ['Address %02X not MCP230XX compatible' % address]]) + + def handleRead(self, register, data): + if len(data) >= 1: + register = register[0] + for d in data: + registers = self.get_registers() + if not register in registers: + self.putx(d[1], d[2], [2, ['Error: Register %d not accessible' %register]]) + if not self.iocon_set: + self.iocon = d[0] + else: + register_name = registers[register] + if register_name == "IOCON": + self.iocon = d[0] + self.iocon_set = True + self.putx(d[1], d[2], [0, ["Read %s: %02X" % (register_name, d[0]), "R%02X" % d[0]]]) + register += 1 + + def handleWrite(self, data): + if len(data) >= 2: + register = data[0][0] + for d in data[1:]: + registers = self.get_registers() + if not register in registers: + self.putx(d[1], d[2], [2, ['Error: Register %d not accessible' %register]]) + if not self.iocon_set: + self.iocon = d[0] + else: + register_name = registers[register] + if register_name == "IOCON": + self.iocon = d[0] + self.iocon_set = True + self.putx(d[1], d[2], [1, ["Write %s: %02X" % (register_name, d[0]), "W%02X" % d[0]]]) + register += 1 + + def decode(self, ss, es, data): + cmd, databyte = data + if cmd in ('ACK', 'NACK', 'BITS'): # Discard 'ACK' and 'BITS'. + return + if self.state == STATE_IDLE and cmd == 'START': + self.state = STATE_ADDR + self.dataWrite = [] + self.dataRead = [] + elif self.state == STATE_ADDR and cmd == 'ADDRESS WRITE': + self.state = STATE_DATA + self.checkAddress(ss, es, databyte) + elif self.state in [STATE_DATA, STATE_STOP] and cmd == 'DATA WRITE': + self.state = STATE_STOP + self.dataWrite.append((databyte, ss, es)) + elif self.state == STATE_STOP and cmd == "START REPEAT": + self.state = STATE_READ_ADDR + elif self.state == STATE_READ_ADDR and cmd == "ADDRESS READ": + self.state = STATE_READ_DATA + self.checkAddress(ss, es, databyte) + elif self.state in [STATE_READ_DATA, STATE_STOP] and cmd == 'DATA READ': + self.state = STATE_STOP + self.dataRead.append((databyte, ss, es)) + elif self.state == STATE_STOP and cmd == 'STOP': + self.state = STATE_IDLE + if len(self.dataRead) > 0 and len(self.dataWrite) == 1: + self.handleRead(self.dataWrite[0], self.dataRead) + elif len(self.dataWrite) > 0 and self.dataRead == []: + self.handleWrite(self.dataWrite)