X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;f=decoders%2Fsle44xx%2Fpd.py;h=775ee3c8a8fb78c9d29aa826a683e480e5da1885;hb=e4f70391abbb153364a534d45a59026961ce1b1f;hp=e897b13b7b8be1d2901cf79edc9c733cf42e1a80;hpb=ead003186fc788e9f330264c85668e2690896bce;p=libsigrokdecode.git diff --git a/decoders/sle44xx/pd.py b/decoders/sle44xx/pd.py index e897b13..775ee3c 100644 --- a/decoders/sle44xx/pd.py +++ b/decoders/sle44xx/pd.py @@ -17,41 +17,44 @@ ## along with this program; if not, see . ## +from common.srdhelper import bitpack_lsb import sigrokdecode as srd -''' -OUTPUT_PYTHON format: +class Pin: + RST, CLK, IO, = range(3) -Packet: -[, ] +class Ann: + BIT, ATR, CMD, DATA, RESET, = range(5) -: - - 'RESET' (Reset/Abort condition) - - 'ATR' (ATR data from card) - - 'CMD' (Command from reader) - - 'DATA' (Data from card) +class Bin: + SEND_DATA, = range(1) - is the data to/from the card -For 'RESET' is None. -''' - -# CMD: [annotation-type-index, long annotation, short annotation] +# CMD: [annotation class index, annotation texts for zoom levels] proto = { - 'RESET': [0, 'Reset', 'R'], - 'ATR': [1, 'ATR', 'ATR'], - 'CMD': [2, 'Command', 'C'], - 'DATA': [3, 'Data', 'D'], + 'BIT': [Ann.BIT, '{bit}',], + 'ATR': [Ann.ATR, 'Answer To Reset: {data:02x}', 'ATR: {data:02x}', '{data:02x}',], + 'CMD': [Ann.CMD, 'Command: {data:02x}', 'Cmd: {data:02x}', '{data:02x}',], + 'DATA': [Ann.DATA, 'Data: {data:02x}', '{data:02x}',], + 'RESET': [Ann.RESET, 'Reset', 'R',], } +def lookup_proto_ann_txt(cmd, variables): + ann = proto.get(cmd, None) + if ann is None: + return None, [] + cls, texts = ann[0], ann[1:] + texts = [t.format(**variables) for t in texts] + return cls, texts + class Decoder(srd.Decoder): api_version = 3 id = 'sle44xx' name = 'SLE 44xx' - longname = 'SLE44xx protocol' + longname = 'SLE44xx memory card' desc = 'SLE 4418/28/32/42 memory card serial protocol' license = 'gplv2+' inputs = ['logic'] - outputs = ['sle44xx'] + outputs = [] tags = ['Memory'] channels = ( {'id': 'rst', 'name': 'RST', 'desc': 'Reset line'}, @@ -59,16 +62,16 @@ class Decoder(srd.Decoder): {'id': 'io', 'name': 'I/O', 'desc': 'I/O data line'}, ) annotations = ( - ('reset', 'Reset'), + ('bit', 'Bit'), ('atr', 'ATR'), ('cmd', 'Command'), ('data', 'Data exchange'), - ('bit', 'Bit'), + ('reset', 'Reset'), ) annotation_rows = ( - ('bits', 'Bits', (4,)), - ('fields', 'Fields', (1, 2, 3)), - ('interrupts', 'Interrupts', (0,)), + ('bits', 'Bits', (Ann.BIT,)), + ('fields', 'Fields', (Ann.ATR, Ann.CMD, Ann.DATA)), + ('interrupts', 'Interrupts', (Ann.RESET,)), ) binary = ( ('send-data', 'Send data'), @@ -79,94 +82,106 @@ class Decoder(srd.Decoder): def reset(self): self.ss = self.es = self.ss_byte = -1 - self.bitcount = 0 - self.databyte = 0 self.bits = [] - self.cmd = 'RESET' + self.cmd = None 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.cmd = 'RESET' + cls, texts = lookup_proto_ann_txt(self.cmd, {}) + self.putx([cls, texts]) self.bits = [] - self.cmd = 'ATR' # Next data bytes will be ATR + # Next data bytes will be Answer To Reset. + self.cmd = 'ATR' def handle_command(self, pins): rst, clk, io = pins self.ss, self.es = self.samplenum, self.samplenum + # XXX Is the comment inverted? # 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.cmd = 'CMD' if io == 0 else 'DATA' 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: + # Remember the start of the first data/address bit. Collect + # bits in LSB first order. "Estimate" the bit's width at first, + # update end times as better data becomes available. + # TODO This estimation logic is imprecise and fragile. A single + # slightly stretched clock period throws off the following bit + # annotation. Better look for more reliable conditions. Available + # documentation suggests bit values are valid during high CLK. + if not self.bits: 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 + bit_val = io + bit_ss = self.samplenum + bit_es = bit_ss # self.bitwidth is not known yet. + if self.bits: + self.bits[-1][2] = bit_ss + self.bits.append([bit_val, bit_ss, bit_es]) + if len(self.bits) < 8: return + bitwidth = self.bits[-1][1] - self.bits[-2][1] + self.bits[-1][2] += bitwidth - self.ss, self.es = self.ss_byte, self.samplenum + self.bitwidth + # Get the data byte value, and byte's ss/es. + databyte = bitpack_lsb(self.bits, 0) + self.ss_byte = self.bits[0][1] + self.es_byte = self.bits[-1][2] - self.putb([0, bytes([self.databyte])]) + self.ss, self.es = self.ss_byte, self.es_byte + self.putb([Bin.SEND_DATA, bytes([databyte])]) - for bit in self.bits: - self.put(bit[1], bit[2], self.out_ann, [4, ['%d' % bit[0]]]) + # TODO Present bit values earlier. As soon as their es is known. + for bit_val, bit_ss, bit_es in self.bits: + cls, texts = lookup_proto_ann_txt('BIT', {'bit': bit_val}) + self.put(bit_ss, bit_es, self.out_ann, [cls, texts]) - 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]]) + cls, texts = lookup_proto_ann_txt(self.cmd, {'data': databyte}) + if cls: + self.putx([cls, texts]) # 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 + # Signal conditions tracked by the protocol decoder: + # - RESET condition (R): RST = rising + # - Incoming data (D): RST = low, CLK = rising. + # TODO Add "RST low, CLK fall" for "end of DATA" here? + # - Command mode START: CLK = high, I/O = falling. + # - Command mode STOP: CLK = high, I/O = rising. + (COND_RESET, COND_DATA, COND_CMD_START, COND_CMD_STOP,) = range(4) + conditions = [ + {Pin.RST: 'r'}, + {Pin.RST: 'l', Pin.CLK: 'r'}, + {Pin.CLK: 'h', Pin.IO: 'f'}, + {Pin.CLK: 'h', Pin.IO: 'r'}, + ] + pins = self.wait(conditions) + if self.matched[COND_RESET]: self.handle_reset(pins) - elif self.matched[1]: # Incoming data (D): RST = low, CLK = rising. + elif self.matched[COND_DATA]: self.handle_data(pins) - elif self.matched[2]: # Command mode START: CLK = high, I/O = falling. + elif self.matched[COND_CMD_START]: self.handle_command(pins) - elif self.matched[3]: # Command mode STOP: CLK = high, I/O = rising. + elif self.matched[COND_CMD_STOP]: self.handle_command(pins)