From: Federico Cerutti Date: Sat, 4 Jan 2020 10:48:35 +0000 (+0100) Subject: sle44xx: introduce decoder for Siemens memory cards X-Git-Url: https://sigrok.org/gitweb/?p=libsigrokdecode.git;a=commitdiff_plain;h=7e87b2f7522312d5dda5231c1de75fb6bbbdf60c;hp=296c29a33b9894b27686e56cb4368d61c7c815aa sle44xx: introduce decoder for Siemens memory cards Introduce an initial implementation of the SLE44xx protocol decoder for Siemens/Infineon SLE 4418/28/32/42 memory cards. ATR (Answer To Reset), command and data bytes get displayed, and RESET/abort events are marked. Extracted data bytes are made available as binary output. --- diff --git a/decoders/sle44xx/__init__.py b/decoders/sle44xx/__init__.py new file mode 100644 index 0000000..1bc7189 --- /dev/null +++ b/decoders/sle44xx/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019 Federico Cerutti +## +## 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 . +## + +''' +SLE 4418/28/32/42 implement a 2-wire protocol (CLK and I/O) for comunication +along the RST signal which is used to abort unnecessarily long memory reads. +''' + +from .pd import Decoder diff --git a/decoders/sle44xx/pd.py b/decoders/sle44xx/pd.py new file mode 100644 index 0000000..62bcdcf --- /dev/null +++ b/decoders/sle44xx/pd.py @@ -0,0 +1,171 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019 Federico Cerutti +## +## 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 + +''' +OUTPUT_PYTHON format: + +Packet: +[, ] + +: + - 'RESET' (Reset/Abort condition) + - 'ATR' (ATR data from card) + - 'CMD' (Command from reader) + - 'DATA' (Data from card) + + is the data to/from the card +For 'RESET' is None. +''' + +# CMD: [annotation-type-index, long annotation, short annotation] +proto = { + 'RESET': [0, 'Reset', 'R'], + 'ATR': [1, 'ATR', 'ATR'], + 'CMD': [2, 'Command', 'C'], + 'DATA': [3, 'Data', 'D'], +} + +class Decoder(srd.Decoder): + api_version = 3 + id = 'sle44xx' + name = 'SLE 44xx' + longname = 'SLE44xx protocol' + desc = 'SLE 4418/28/32/42 memory card serial protocol' + license = 'gplv2+' + inputs = ['logic'] + outputs = ['sle44xx'] + channels = ( + {'id': 'rst', 'name': 'RST', 'desc': 'Reset line'}, + {'id': 'clk', 'name': 'CLK', 'desc': 'Clock line'}, + {'id': 'io', 'name': 'I/O', 'desc': 'I/O data line'}, + ) + annotations = ( + ('reset', 'Reset'), + ('atr', 'ATR'), + ('cmd', 'Command'), + ('data', 'Data exchange'), + ('bit', 'Bit'), + ) + annotation_rows = ( + ('bits', 'Bits', (4,)), + ('data', 'Data', (1, 2, 3)), + ('interrupts', 'Interrupts', (0,)), + ) + binary = ( + ('send-data', 'Send data'), + ) + + def __init__(self): + self.reset() + + def reset(self): + self.ss = self.es = self.ss_byte = -1 + self.bitcount = 0 + self.databyte = 0 + self.bits = [] + self.cmd = 'RESET' + + def metadata(self, key, value): + if key == srd.SRD_CONF_SAMPLERATE: + self.samplerate = value + + def start(self): + self.out_python = self.register(srd.OUTPUT_PYTHON) + self.out_ann = self.register(srd.OUTPUT_ANN) + self.out_binary = self.register(srd.OUTPUT_BINARY) + + def putx(self, data): + self.put(self.ss, self.es, self.out_ann, data) + + def putp(self, data): + self.put(self.ss, self.es, self.out_python, data) + + def putb(self, data): + self.put(self.ss, self.es, self.out_binary, data) + + def handle_reset(self, pins): + self.ss, self.es = self.samplenum, self.samplenum + cmd = 'RESET' # No need to set the global self.cmd as this command is atomic + self.putp([cmd, None]) + self.putx([proto[cmd][0], proto[cmd][1:]]) + self.bitcount = self.databyte = 0 + self.bits = [] + self.cmd = 'ATR' # Next data bytes will be ATR + + def handle_command(self, pins): + rst, clk, io = pins + self.ss, self.es = self.samplenum, self.samplenum + # If I/O is rising -> command START + # if I/O is falling -> command STOP and response data incoming + self.cmd = 'CMD' if (io == 0) else 'DATA' + self.bitcount = self.databyte = 0 + self.bits = [] + + # Gather 8 bits of data + def handle_data(self, pins): + rst, clk, io = pins + + # Data is transmitted LSB-first. + self.databyte |= (io << self.bitcount) + + # Remember the start of the first data/address bit. + if self.bitcount == 0: + self.ss_byte = self.samplenum + + # Store individual bits and their start/end samplenumbers. + # In the list, index 0 represents the LSB (SLE44xx transmits LSB-first). + self.bits.insert(0, [io, self.samplenum, self.samplenum]) + if self.bitcount > 0: + self.bits[1][2] = self.samplenum + if self.bitcount == 7: + self.bitwidth = self.bits[1][2] - self.bits[2][2] + self.bits[0][2] += self.bitwidth + + # Return if we haven't collected all 8 bits, yet. + if self.bitcount < 7: + self.bitcount += 1 + return + + self.ss, self.es = self.ss_byte, self.samplenum + self.bitwidth + + self.putb([0, bytes([self.databyte])]) + + for bit in self.bits: + self.put(bit[1], bit[2], self.out_ann, [4, ['%d' % bit[0]]]) + + self.putx([proto[self.cmd][0], ['%s: %02X' % (proto[self.cmd][1], self.databyte), + '%s: %02X' % (proto[self.cmd][2], self.databyte), '%02X' % self.databyte]]) + + # Done with this packet. + self.bitcount = self.databyte = 0 + self.bits = [] + + def decode(self): + while True: + pins = self.wait([{0: 'r'}, {0: 'l', 1: 'r'}, {1: 'h', 2: 'f'}, {1: 'h', 2: 'r'}]) + if self.matched[0]: # RESET condition (R): RST = rising + self.handle_reset(pins) + elif self.matched[1]: # Incoming data (D): RST = low, CLK = rising. + self.handle_data(pins) + elif self.matched[2]: # Command mode START: CLK = high, I/O = falling. + self.handle_command(pins) + elif self.matched[3]: # Command mode STOP: CLK = high, I/O = rising. + self.handle_command(pins) \ No newline at end of file