]> sigrok.org Git - libsigrokdecode.git/commitdiff
Add an initial Maple bus decoder.
authorMarcus Comstedt <redacted>
Mon, 20 Nov 2017 19:01:24 +0000 (20:01 +0100)
committerUwe Hermann <redacted>
Sat, 9 Dec 2017 12:36:13 +0000 (13:36 +0100)
decoders/maple_bus/__init__.py [new file with mode: 0644]
decoders/maple_bus/pd.py [new file with mode: 0644]

diff --git a/decoders/maple_bus/__init__.py b/decoders/maple_bus/__init__.py
new file mode 100644 (file)
index 0000000..33b90a5
--- /dev/null
@@ -0,0 +1,25 @@
+##
+## This file is part of the libsigrokdecode project.
+##
+## Copyright (C) 2017 Marcus Comstedt <marcus@mc.pp.se>
+##
+## 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 <http://www.gnu.org/licenses/>.
+##
+
+'''
+Maple bus is serial communication protocol used by peripherals for the
+SEGA Dreamcast game console.
+'''
+
+from .pd import Decoder
diff --git a/decoders/maple_bus/pd.py b/decoders/maple_bus/pd.py
new file mode 100644 (file)
index 0000000..f558722
--- /dev/null
@@ -0,0 +1,208 @@
+##
+## This file is part of the libsigrokdecode project.
+##
+## Copyright (C) 2017 Marcus Comstedt <marcus@mc.pp.se>
+##
+## 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 <http://www.gnu.org/licenses/>.
+##
+
+import sigrokdecode as srd
+
+ann = [
+    ['Size', 'L'],
+    ['SrcAP', 'S'],
+    ['DstAP', 'D'],
+    ['Cmd', 'C'],
+    ['Data'],
+    ['Cksum', 'K'],
+]
+
+class Decoder(srd.Decoder):
+    api_version = 3
+    id = 'maple_bus'
+    name = 'Maple bus'
+    longname = 'SEGA Maple bus'
+    desc = 'Maple bus peripheral protocol for SEGA Dreamcast.'
+    license = 'gplv2+'
+    inputs = ['logic']
+    outputs = ['maple_bus']
+    channels = (
+        {'id': 'sdcka', 'name': 'SDCKA', 'desc': 'Data/clock line A'},
+        {'id': 'sdckb', 'name': 'SDCKB', 'desc': 'Data/clock line B'},
+    )
+    annotations = (
+        ('start', 'Start pattern'),
+        ('end', 'End pattern'),
+        ('start-with-crc', 'Start pattern with CRC'),
+        ('occupancy', 'SDCKB occupancy pattern'),
+        ('reset', 'RESET pattern'),
+        ('bit', 'Bit'),
+        ('size', 'Data size'),
+        ('source', 'Source AP'),
+        ('dest', 'Destination AP'),
+        ('command', 'Command'),
+        ('data', 'Data'),
+        ('checksum', 'Checksum'),
+        ('frame-error', 'Frame error'),
+        ('checksum-error', 'Checksum error'),
+        ('size-error', 'Size error'),
+    )
+    annotation_rows = (
+        ('bits', 'Bits', (0, 1, 2, 3, 4, 5)),
+        ('fields', 'Fields', (6, 7, 8, 9, 10, 11)),
+        ('warnings', 'Warnings', (12, 13, 14)),
+    )
+    binary = (
+        ('size', 'Data size'),
+        ('source', 'Source AP'),
+        ('dest', 'Destination AP'),
+        ('command', 'Command code'),
+        ('data', 'Data'),
+        ('checksum', 'Checksum'),
+    )
+
+    def __init__(self):
+        pass
+
+    def start(self):
+        self.out_ann = self.register(srd.OUTPUT_ANN)
+        self.out_binary = self.register(srd.OUTPUT_BINARY)
+        self.pending_bit_pos = None
+
+    def byte_annotation(self, bintype, d):
+        return [bintype + 6,
+            ['%s: %02X' % (name, d) for name in ann[bintype]] + ['%02X' % d]]
+
+    def got_start(self):
+        self.put(self.ss, self.es, self.out_ann, [0, ['Start pattern', 'Start', 'S']])
+
+    def got_end(self):
+        self.put(self.ss, self.es, self.out_ann, [1, ['End pattern', 'End', 'E']])
+        if self.length != self.expected_length + 1:
+            self.put(self.ss, self.es, self.out_ann, [14, ['Size error', 'L error', 'LE']])
+
+    def got_start_with_crc(self):
+        self.put(self.ss, self.es, self.out_ann, [2, ['Start pattern with CRC', 'Start CRC', 'SC']])
+
+    def got_occupancy(self):
+        self.put(self.ss, self.es, self.out_ann, [3, ['SDCKB occupancy pattern', 'Occupancy', 'O']])
+
+    def got_reset(self):
+        self.put(self.ss, self.es, self.out_ann, [4, ['RESET pattern', 'RESET', 'R']])
+
+    def output_pending_bit(self):
+        if self.pending_bit_pos:
+            self.put(self.pending_bit_pos, self.pending_bit_pos, self.out_ann, [5, ['Bit: %d' % self.pending_bit, '%d' % self.pending_bit]])
+
+    def got_bit(self, n):
+        self.output_pending_bit()
+        self.data = self.data * 2 + n
+        self.pending_bit = n
+        self.pending_bit_pos = self.samplenum
+
+    def got_byte(self):
+        self.output_pending_bit()
+        bintype = 4
+        if self.length < 4:
+            if self.length == 0:
+                self.expected_length = 4 * (self.data + 1)
+            bintype = self.length
+        elif self.length == self.expected_length:
+            bintype = 5
+            if self.data != self.checksum:
+                self.put(self.ss, self.es, self.out_ann, [13, ['Cksum error', 'K error', 'KE']])
+        self.length = self.length + 1
+        self.checksum = self.checksum ^ self.data
+        self.put(self.ss, self.es, self.out_ann, self.byte_annotation(bintype, self.data))
+        self.put(self.ss, self.es, self.out_binary, [bintype, bytes([self.data])])
+        self.pending_bit_pos = None
+
+    def frame_error(self):
+        self.put(self.ss, self.es, self.out_ann, [7, ['Frame error', 'F error', 'FE']])
+
+    def handle_start(self):
+        self.wait({0: 'l', 1: 'h'})
+        self.ss = self.samplenum
+        count = 0
+        while True:
+            sdcka, sdckb = self.wait([{1: 'f'}, {0: 'r'}])
+            if self.matched[0]:
+                count = count + 1
+            if self.matched[1]:
+                self.es = self.samplenum
+                if sdckb == 1:
+                    if count == 4:
+                        self.got_start()
+                        return True
+                    elif count == 6:
+                        self.got_start_with_crc()
+                        return True
+                    elif count == 8:
+                        self.got_occupancy()
+                        return False
+                    elif count >= 14:
+                        self.got_reset()
+                        return False
+                self.frame_error()
+                return False
+
+    def handle_byte_or_stop(self):
+        self.ss = self.samplenum
+        self.pending_bit_pos = None
+        initial = True
+        counta = 0
+        countb = 0
+        self.data = 0
+        while countb < 4:
+            sdcka, sdckb = self.wait([{0: 'f'}, {1: 'f'}])
+            self.es = self.samplenum
+            if self.matched[0]:
+                if counta == countb:
+                    self.got_bit(sdckb)
+                    counta = counta + 1
+                elif counta == 1 and countb == 0 and self.data == 0 and sdckb == 0:
+                    self.wait([{0: 'h', 1: 'h'}, {0: 'f'}, {1: 'f'}])
+                    self.es = self.samplenum
+                    if self.matched[0]:
+                        self.got_end()
+                    else:
+                        self.frame_error()
+                    return False
+                else:
+                    self.frame_error()
+                    return False
+            elif self.matched[1]:
+                if counta == countb + 1:
+                    self.got_bit(sdcka)
+                    countb = countb + 1
+                elif counta == 0 and countb == 0 and sdcka == 1 and initial:
+                    self.ss = self.samplenum
+                    initial = False
+                else:
+                    self.frame_error()
+                    return False
+        self.wait({0: 'h'})
+        self.es = self.samplenum
+        self.got_byte()
+        return True
+
+    def decode(self):
+        while True:
+            while not self.handle_start():
+                pass
+            self.length = 0
+            self.expected_length = 4
+            self.checksum = 0
+            while self.handle_byte_or_stop():
+                pass