From: Kevin Redon Date: Thu, 19 Oct 2017 07:08:42 +0000 (+0200) Subject: ds2432: Add a Maxim DS2432 protocol decoder. X-Git-Url: https://sigrok.org/gitweb/?a=commitdiff_plain;h=444960cc19c62edab0b259c06b03fa096f9d5a72;p=libsigrokdecode.git ds2432: Add a Maxim DS2432 protocol decoder. This fixes (parts of) bug #1019. --- diff --git a/decoders/ds2432/__init__.py b/decoders/ds2432/__init__.py new file mode 100644 index 0000000..7664b5b --- /dev/null +++ b/decoders/ds2432/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2017 Kevin Redon +## +## 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 'onewire_network' PD and decodes the +Maxim DS2432 (1-Wire 1Kbit protected EEPROM with SHA-1 engine) protocol. +''' + +from .pd import Decoder diff --git a/decoders/ds2432/pd.py b/decoders/ds2432/pd.py new file mode 100644 index 0000000..269a23e --- /dev/null +++ b/decoders/ds2432/pd.py @@ -0,0 +1,248 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2017 Kevin Redon +## +## 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 + +# Dictionary of FUNCTION commands and their names. +commands = { + 0x0f: 'Write scratchpad', + 0xaa: 'Read scratchpad', + 0x55: 'Copy scratchpad', + 0xf0: 'Read memory', + 0x5a: 'Load first secret', + 0x33: 'Compute next secret', + 0xa5: 'Read authenticated page', +} + +# Maxim DS2432 family code, present at the end of the ROM code. +family_code = 0x33 + +# Calculate the CRC-16 checksum. +# Initial value: 0x0000, xor-in: 0x0000, polynom 0x8005, xor-out: 0xffff. +def crc16(byte_array): + reverse = 0xa001 # Use the reverse polynom to make algo simpler. + crc = 0x0000 # Initial value. + # Reverse CRC calculation. + for byte in byte_array: + for bit in range(8): + if (byte ^ crc) & 1: + crc = (crc >> 1) ^ reverse + else: + crc >>= 1 + byte >>= 1 + crc ^= 0xffff # Invert CRC. + return crc + +class Decoder(srd.Decoder): + api_version = 3 + id = 'ds2432' + name = 'DS2432' + longname = 'Maxim DS2432 1-Wire 1k-Bit Protected EEPROM with SHA-1 Engine' + desc = '1-Wire 1k-Bit Protected EEPROM with SHA-1 Engine.' + license = 'gplv2+' + inputs = ['onewire_network'] + outputs = ['ds2432'] + annotations = ( + ('text', 'Human-readable text'), + ) + + def __init__(self): + # Bytes for function command. + self.bytes = [] + + 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 decode(self, ss, es, data): + code, val = data + + if code == 'RESET/PRESENCE': + self.ss, self.es = ss, es + self.putx([0, ['Reset/presence: %s' + % ('true' if val else 'false')]]) + self.bytes = [] + elif code == 'ROM': + self.ss, self.es = ss, es + self.putx([0, ['ROM: 0x%016x (family code %s to 0x%02x)' + % (val, 'matches' if family_code == (val & 0xff) + else 'does not match', family_code), + 'ROM: 0x%016x (family code %s)' + % (val, 'match' if family_code == (val & 0xff) + else 'mismatch')]]) + self.bytes = [] + elif code == 'DATA': + self.bytes.append(val) + if 1 == len(self.bytes): + self.ss, self.es = ss, es + if val not in commands: + self.putx([0, ['Unrecognized command: 0x%02x' % val]]) + else: + self.putx([0, ['Function command: %s (0x%02x)' + % (commands[val], val)]]) + elif 0x0f == self.bytes[0]: # Write scratchpad + if 2 == len(self.bytes): + self.ss = ss + elif 3 == len(self.bytes): + self.es = es + self.putx([0, ['Target address: 0x%04x' + % ((self.bytes[2] << 8) + self.bytes[1])]]) + elif 4 == len(self.bytes): + self.ss = ss + elif 11 == len(self.bytes): + self.es = es + self.putx([0, ['Data: ' + (','.join(format(n, '#04x') + for n in self.bytes[3:11]))]]) + elif 12 == len(self.bytes): + self.ss = ss + elif 13 == len(self.bytes): + self.es = es + self.putx([0, ['CRC: ' + + ('ok' if crc16(self.bytes[0:11]) == (self.bytes[11] + + (self.bytes[12] << 8)) else 'error')]]) + elif 0xaa == self.bytes[0]: # Read scratchpad + if 2 == len(self.bytes): + self.ss = ss + elif 3 == len(self.bytes): + self.es = es + self.putx([0, ['Target address: 0x%04x' + % ((self.bytes[2] << 8) + self.bytes[1])]]) + elif 4 == len(self.bytes): + self.ss, self.es = ss, es + self.putx([0, ['Data status (E/S): 0x%02x' + % (self.bytes[3])]]) + elif 5 == len(self.bytes): + self.ss = ss + elif 12 == len(self.bytes): + self.es = es + self.putx([0, ['Data: ' + (','.join(format(n, '#04x') + for n in self.bytes[4:12]))]]) + elif 13 == len(self.bytes): + self.ss = ss + elif 14 == len(self.bytes): + self.es = es + self.putx([0, ['CRC: ' + + ('ok' if crc16(self.bytes[0:12]) == (self.bytes[12] + + (self.bytes[13] << 8)) else 'error')]]) + elif 0x5a == self.bytes[0]: # Load first secret + if 2 == len(self.bytes): + self.ss = ss + elif 4 == len(self.bytes): + self.es = es + self.putx([0, ['Authorization pattern (TA1, TA2, E/S): ' + + (','.join(format(n, '#04x') + for n in self.bytes[1:4]))]]) + elif 4 < len(self.bytes): + self.ss, self.es = ss, es + if (0xaa == self.bytes[-1] or 0x55 == self.bytes[-1]): + self.putx([0, ['End of operation']]) + elif 0x33 == self.bytes[0]: # Compute next secret + if 2 == len(self.bytes): + self.ss = ss + elif 3 == len(self.bytes): + self.es = es + self.putx([0, ['Target address: 0x%04x' + % ((self.bytes[2] << 8) + self.bytes[1])]]) + elif 3 < len(self.bytes): + self.ss, self.es = ss, es + if (0xaa == self.bytes[-1] or 0x55 == self.bytes[-1]): + self.putx([0, ['End of operation']]) + elif 0x55 == self.bytes[0]: # Copy scratchpad + if 2 == len(self.bytes): + self.ss = ss + elif 4 == len(self.bytes): + self.es = es + self.putx([0, ['Authorization pattern (TA1, TA2, E/S): ' + + (','.join(format(n, '#04x') + for n in self.bytes[1:4]))]]) + elif 5 == len(self.bytes): + self.ss = ss + elif 24 == len(self.bytes): + self.es = es + self.putx([0, ['Message authentication code: ' + + (','.join(format(n, '#04x') + for n in self.bytes[4:24])), + 'MAC: ' + + (','.join(format(n, '#04x') + for n in self.bytes[4:24])), + ]]) + elif 24 < len(self.bytes): + self.ss, self.es = ss, es + if (0xaa == self.bytes[-1] or 0x55 == self.bytes[-1]): + self.putx([0, ['Operation succeeded']]) + elif (0 == self.bytes[-1]): + self.putx([0, ['Operation failed']]) + elif 0xa5 == self.bytes[0]: # Read authenticated page + if 2 == len(self.bytes): + self.ss = ss + elif 3 == len(self.bytes): + self.es = es + self.putx([0, ['Target address: 0x%04x' + % ((self.bytes[2] << 8) + self.bytes[1])]]) + elif 4 == len(self.bytes): + self.ss = ss + elif 35 == len(self.bytes): + self.es = es + self.putx([0, ['Data: ' + (','.join(format(n, '#04x') + for n in self.bytes[3:35]))]]) + elif 36 == len(self.bytes): + self.ss, self.es = ss, es + self.putx([0, ['Padding: ' + + ('ok' if 0xff == self.bytes[-1] else 'error')]]) + elif 37 == len(self.bytes): + self.ss = ss + elif 38 == len(self.bytes): + self.es = es + self.putx([0, ['CRC: ' + + ('ok' if crc16(self.bytes[0:36]) == (self.bytes[36] + + (self.bytes[37] << 8)) else 'error')]]) + elif 39 == len(self.bytes): + self.ss = ss + elif 58 == len(self.bytes): + self.es = es + self.putx([0, ['Message authentication code: ' + + (','.join(format(n, '#04x') + for n in self.bytes[38:58])), + 'MAC: ' + + (','.join(format(n, '#04x') + for n in self.bytes[38:58])), + ]]) + elif 59 == len(self.bytes): + self.ss = ss + elif 60 == len(self.bytes): + self.es = es + self.putx([0, ['MAC CRC: ' + + ('ok' if crc16(self.bytes[38:58]) == (self.bytes[58] + + (self.bytes[59] << 8)) else 'error')]]) + elif 60 < len(self.bytes): + self.ss, self.es = ss, es + if (0xaa == self.bytes[-1] or 0x55 == self.bytes[-1]): + self.putx([0, ['Operation completed']]) + elif 0xf0 == self.bytes[0]: # Read memory + if 2 == len(self.bytes): + self.ss = ss + elif 3 == len(self.bytes): + self.es = es + self.putx([0, ['Target address: 0x%04x' + % ((self.bytes[2] << 8) + self.bytes[1])]]) + elif 3 < len(self.bytes): + self.ss, self.es = ss, es + self.putx([0, ['Data: 0x%02x' % (self.bytes[-1])]])