Arduino_ArcadeSpinner icon indicating copy to clipboard operation
Arduino_ArcadeSpinner copied to clipboard

VAUS Support for NES (e.g.Arkaniod) / Feature Variable Sensitivity & Mouse Buttons

Open nad22 opened this issue 7 months ago • 2 comments

First of all thanks for the great project. I just wanted to ask if you have managed to get the spinner working for NES Games like Arkanoid on a Mister FGPA ? I tried all 3 Modes, but the Core does not accept Spinner inputs (Button A works)

Also, I did some minor modifications to get these 2 Features working:

  • MouseX Mode: Button 0 and Button 1 act as Mouse Left/Right click,... very useful for Atari Games like Krypton Egg
  • MouseX & Mr-Spinner Mode: Button 2 and 3 lower/rise the Mouse/Spinner sensitivity.

Here's the code.

/*

  • Arduino USB Arcade Spinner
  • (C) Wilfried JEANNIARD [https://github.com/willoucom]
  • Based on project by Alexey Melnikov [https://github.com/MiSTer-devel/Retro-Controllers-USB-MiSTer/blob/master/PaddleTwoControllersUSB/PaddleTwoControllersUSB.ino]
  • Based on project by Mikael Norrgård [email protected]
  • GNU GENERAL PUBLIC LICENSE
  • Version 3, 29 June 2007
  • 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 3 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 https://www.gnu.org/licenses/.

*/

///////////////// Customizable settings ///////////////////////// // For debug (check serial monitor) // #define DEBUG

// Spinner pulses per revolution #define SPINNER_PPR 600

// Spinner/Mouse sensitivity // 1 is more sensitive // 999 is less sensitive int spinner_sensitivity = 15; int mouse_sensitivity = 5;

/////////////////////////////////////////////////////////////////

// Pins used by encoder #define pinA 3 #define pinB 2 // Pins used by buttons #define Button0 5 // Left button #define Button1 4 // Right button #define Button2 15 // Small Left: Select/Coin #define Button3 14 // Small Right: Start

////////////////////////////////////////////////////////

// ID for special support in MiSTer // ATT: 20 chars max (including NULL at the end) according to Arduino source code. // Additionally serial number is used to differentiate arduino projects to have different button maps! const char *gp_serial = "MiSTer-A1 Spinner";

#include <Mouse.h> #include "Gamepad.h"

// Create Gamepad Gamepad_ Gamepad; GamepadReport rep;

// Default virtual spinner position int16_t drvpos = 0; // Default real spinner position int16_t r_drvpos = 0; // Default virtual mouse position int16_t m_drvpos = 0;

// Variables for paddle_emu #define SP_MAX ((SPINNER_PPR4270UL)/360) int32_t sp_clamp = SP_MAX/2;

// For emulation bool mouse_emu = 0; bool paddle_emu = 0; bool mr_spinner_emu = 0;

// Interrupt pins of Rotary Encoder void drv_proc() { static int8_t prev = drvpos; int8_t a = digitalRead(pinA); int8_t b = digitalRead(pinB);

int8_t spval = (b << 1) | (b^a); int8_t diff = (prev - spval)&3;

if(diff == 1) { r_drvpos += 1; if(sp_clamp < SP_MAX) sp_clamp++; } if(diff == 3) { r_drvpos -= 1; if(sp_clamp > 0) sp_clamp--; }

drvpos = r_drvpos / spinner_sensitivity; m_drvpos = r_drvpos / mouse_sensitivity;

prev = spval; }

// Run at startup void setup() { #ifdef DEBUG Serial.begin(9600); #endif Gamepad.reset();

// Encoder pinMode(pinA, INPUT_PULLUP); pinMode(pinB, INPUT_PULLUP); // Init encoder reading drv_proc(); // Attach interrupt to each pin of the encoder attachInterrupt(digitalPinToInterrupt(pinA), drv_proc, CHANGE); attachInterrupt(digitalPinToInterrupt(pinB), drv_proc, CHANGE);

// Initialize Button Pins pinMode(Button0, INPUT_PULLUP); pinMode(Button1, INPUT_PULLUP); pinMode(Button2, INPUT_PULLUP); pinMode(Button3, INPUT_PULLUP);

// Enable mouse emulation if (!digitalRead(Button0)) { mouse_emu = !mouse_emu; Mouse.begin(); } // Enable paddle emulation if (!digitalRead(Button1)) { paddle_emu = !paddle_emu; } // Spinner only (AKA mr.Spinner mode) if (!digitalRead(Button2)) { // Announce the device as mr.Spinner (more explanations in the readme file) mr_spinner_emu = !mr_spinner_emu; gp_serial = "MiSTer-S1 Spinner"; }

}

// Main loop void loop() { // Maus-Sensitivität per Button3 (--) und Button2 (++) anpassen static uint32_t lastSensChange = 0; uint32_t now = millis(); if (mouse_emu && now - lastSensChange > 200) { if (!digitalRead(Button3)) { // Jetzt Button3 = empfindlicher if (mouse_sensitivity > 1) { mouse_sensitivity--; lastSensChange = now; } } if (!digitalRead(Button2)) { // Jetzt Button2 = weniger empfindlich if (mouse_sensitivity < 100) { mouse_sensitivity++; lastSensChange = now; } } } // Spinner-Sensitivität per Button3 (--) und Button2 (++) anpassen im mr-spinner Modus static uint32_t lastSpinnerChange = 0; if (mr_spinner_emu && millis() - lastSpinnerChange > 200) { if (!digitalRead(Button3)) { // Button3 = empfindlicher if (spinner_sensitivity > 1) { spinner_sensitivity--; lastSpinnerChange = millis(); } } if (!digitalRead(Button2)) { // Button2 = weniger empfindlich if (spinner_sensitivity < 100) { spinner_sensitivity++; lastSpinnerChange = millis(); } } }

// Default Spinner/Paddle position; rep.paddle = 0; rep.spinner = 0; // Buttons if (mr_spinner_emu) { rep.b0 = !digitalRead(Button0) || !digitalRead(Button1); } else { rep.b0 = !digitalRead(Button0); rep.b1 = !digitalRead(Button1); rep.b2 = !digitalRead(Button2); rep.b3 = !digitalRead(Button3); }

// spinner rotation static uint16_t prev = 0; int16_t val = ((int16_t)(drvpos - prev)); if(val>127) val = 127; else if(val<-127) val = -127; rep.spinner = val; prev += val;

// Paddle Emulation if(paddle_emu) { rep.paddle = ((sp_clamp*255)/SP_MAX); rep.spinner = 0; }

// Mouse Emulation // Mouse Emulation if(mouse_emu) { static uint16_t m_prev = 0; int16_t val = ((int16_t)(m_drvpos - m_prev)); if(val>127) val = 127; else if(val<-127) val = -127; m_prev += val; Mouse.move(val, 0); rep.spinner = 0;

// Maus-Buttons
if (!digitalRead(Button0)) {
  Mouse.press(MOUSE_LEFT);
} else {
  Mouse.release(MOUSE_LEFT);
}

if (!digitalRead(Button1)) {
  Mouse.press(MOUSE_RIGHT);
} else {
  Mouse.release(MOUSE_RIGHT);
}

}

// Only report controller state if it has changed if (memcmp(&Gamepad._GamepadReport, &rep, sizeof(GamepadReport))) { #ifdef DEBUG // Very verbose debug Serial.print(gp_serial); Serial.print(" "); Serial.print(drvpos); Serial.print(" "); Serial.print(mouse_emu); Serial.print(" "); Serial.print(paddle_emu); Serial.print(" "); Serial.print(rep.spinner); Serial.print(" "); Serial.print(rep.paddle); Serial.print(" "); Serial.print(rep.b0); Serial.print(" "); Serial.print(rep.b1); Serial.print(" "); Serial.print(rep.b2); Serial.print(" "); Serial.println(rep.b3); #endif // Send Gamepad changes Gamepad._GamepadReport = rep; Gamepad.send(); } }

nad22 avatar Jun 15 '25 18:06 nad22

thanks for making a fork @nad22 - I tried to flash it to my arduino but got a missing file error (whereas this original branch flashes fine). I couldn't open an issue on your repo tho. Are you still developing your fork?

matijaerceg avatar Oct 24 '25 23:10 matijaerceg

thanks for making a fork @nad22 - I tried to flash it to my arduino but got a missing file error (whereas this original branch flashes fine). I couldn't open an issue on your repo tho. Are you still developing your fork?

Hi! I activated issues,. feel free to post your compile errors,.. i am looking forward to help you. Kind Regards !

nad22 avatar Oct 25 '25 02:10 nad22