nes_gamepad: implement and add decoder
authorStephan Thiele <stephan.thiele@mailbox.org>
Sun, 27 Oct 2019 20:59:17 +0000 (21:59 +0100)
committerUwe Hermann <uwe@hermann-uwe.de>
Sat, 30 Nov 2019 08:33:36 +0000 (09:33 +0100)
decoders/nes_gamepad/__init__.py [new file with mode: 0644]
decoders/nes_gamepad/pd.py [new file with mode: 0644]

diff --git a/decoders/nes_gamepad/__init__.py b/decoders/nes_gamepad/__init__.py
new file mode 100644 (file)
index 0000000..e754374
--- /dev/null
@@ -0,0 +1,54 @@
+##
+## This file is part of the libsigrokdecode project.
+##
+## Copyright (C) 2019 Stephan Thiele <stephan.thiele@mailbox.org>
+##
+## 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/>.
+##
+
+'''
+This decoder stacks on top of the 'spi' PD and decodes the button states
+of an NES gamepad.
+
+The SPI decoder needs to be configured as follows:
+
+Clock polarity = 1
+Clock phase    = 0
+Bit order      = msb-first
+Word size      = 8
+
+Chip-select is not used and must not be assigned to any channel.
+
+Hardware setup is as follows:
+        ___
+   GND |o  \
+   CUP |o o| VCC
+ OUT 0 |o o| D3
+    D1 |o o| D4
+       -----
+NES Gamepad Connector
+
+VCC   - Power 5V
+GND   - Ground
+CUP   - Shift register clock (CLK)
+OUT 0 - Shift register latch (optional)
+D1    - Gamepad data (MOSI)
+D3    - Data (unused)
+D4    - Data (unused)
+
+Data pins D3 and D4 are not used by the standard gamepad but
+by special controllers like the Nintento Zapper light gun.
+'''
+
+from .pd import Decoder
diff --git a/decoders/nes_gamepad/pd.py b/decoders/nes_gamepad/pd.py
new file mode 100644 (file)
index 0000000..17c57ca
--- /dev/null
@@ -0,0 +1,105 @@
+##
+## This file is part of the libsigrokdecode project.
+##
+## Copyright (C) 2019 Stephan Thiele <stephan.thiele@mailbox.org>
+##
+## 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
+
+class Decoder(srd.Decoder):
+    api_version = 3
+    id = 'nes_gamepad'
+    name = 'NES gamepad'
+    longname = 'Nintendo Entertainment System gamepad'
+    desc = 'NES gamepad button states.'
+    license = 'gplv2+'
+    inputs = ['spi']
+    outputs = []
+    tags = ['Retro computing']
+    options = (
+        # Currently only the standard controller is supported. This might be
+        # extended by special controllers like the Nintendo Zapper light gun.
+        {'id': 'variant', 'desc': 'Gamepad variant',
+            'default': 'Standard gamepad', 'values': ('Standard gamepad',)},
+    )
+    annotations = (
+        ('button', 'Button states'),
+        ('no-press', 'No button press'),
+        ('not-connected', 'Gamepad unconnected')
+    )
+    annotation_rows = (
+        ('buttons', 'Button states', (0,)),
+        ('no-press', 'No button press', (1,)),
+        ('not-connected', 'Gamepad unconnected', (2,)),
+    )
+
+    def __init__(self):
+        self.reset()
+
+    def reset(self):
+        self.variant = None
+        self.ss_block = None
+        self.es_block = None
+
+    def start(self):
+        self.out_ann = self.register(srd.OUTPUT_ANN)
+        self.variant = self.options['variant']
+
+    def putx(self, data):
+        self.put(self.ss_block, self.es_block, self.out_ann, data)
+
+    def handle_data(self, value):
+        if value == 0xFF:
+          self.putx([1, ['No button is pressed']])
+          return
+
+        if value == 0x00:
+          self.putx([2, ['Gamepad is not connected']])
+          return
+
+        buttons = [
+            'A',
+            'B',
+            'Select',
+            'Start',
+            'North',
+            'South',
+            'West',
+            'East'
+        ]
+
+        bits = format(value, '08b')
+        button_str = ''
+
+        for b in enumerate(bits):
+            button_index = b[0]
+            button_is_pressed = b[1] == '0'
+
+            if button_is_pressed:
+                if button_str != '':
+                    button_str += ' + '
+                button_str += buttons[button_index]
+
+        self.putx([0, ['%s' % button_str]])
+
+    def decode(self, ss, es, data):
+        ptype, mosi, miso = data
+        self.ss_block, self.es_block = ss, es
+
+        if ptype != 'DATA':
+          return
+
+        self.handle_data(miso)