## along with this program; if not, see <http://www.gnu.org/licenses/>.
##
+from common.srdhelper import bitpack_lsb
import sigrokdecode as srd
-'''
-OUTPUT_PYTHON format:
+class Pin:
+ RST, CLK, IO, = range(3)
-Packet:
-[<ptype>, <pdata>]
+class Ann:
+ BIT, ATR, CMD, DATA, RESET, = range(5)
-<ptype>:
- - 'RESET' (Reset/Abort condition)
- - 'ATR' (ATR data from card)
- - 'CMD' (Command from reader)
- - 'DATA' (Data from card)
+class Bin:
+ SEND_DATA, = range(1)
-<pdata> is the data to/from the card
-For 'RESET' <pdata> 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'},
{'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'),
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)