From 45c39fc4c6a3a7d7651ba83e24994e452f8b94a4 Mon Sep 17 00:00:00 2001 From: Stephan Thiele Date: Sun, 27 Oct 2019 21:59:17 +0100 Subject: [PATCH] nes_gamepad: implement and add decoder --- decoders/nes_gamepad/__init__.py | 54 ++++++++++++++++ decoders/nes_gamepad/pd.py | 105 +++++++++++++++++++++++++++++++ 2 files changed, 159 insertions(+) create mode 100644 decoders/nes_gamepad/__init__.py create mode 100644 decoders/nes_gamepad/pd.py diff --git a/decoders/nes_gamepad/__init__.py b/decoders/nes_gamepad/__init__.py new file mode 100644 index 0000000..e754374 --- /dev/null +++ b/decoders/nes_gamepad/__init__.py @@ -0,0 +1,54 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019 Stephan Thiele +## +## 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 '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 index 0000000..17c57ca --- /dev/null +++ b/decoders/nes_gamepad/pd.py @@ -0,0 +1,105 @@ +## +## This file is part of the libsigrokdecode project. +## +## Copyright (C) 2019 Stephan Thiele +## +## 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 + +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) -- 2.30.2