From: Marcus Comstedt Date: Mon, 20 Nov 2017 19:01:24 +0000 (+0100) Subject: Add an initial Maple bus decoder. X-Git-Url: https://sigrok.org/gitaction?a=commitdiff_plain;h=4cd8ac1d40f4c6af1be33033e0bd64b124dfce1e;p=libsigrokdecode.git Add an initial Maple bus decoder. --- diff --git a/decoders/maple_bus/__init__.py b/decoders/maple_bus/__init__.py new file mode 100644 index 0000000..33b90a5 --- /dev/null +++ b/decoders/maple_bus/__init__.py @@ -0,0 +1,25 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2017 Marcus Comstedt +## +## 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 . +## + +''' +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 index 0000000..f558722 --- /dev/null +++ b/decoders/maple_bus/pd.py @@ -0,0 +1,208 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2017 Marcus Comstedt +## +## 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 + +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