diff --git a/CD32ControllerUSB/CD32ControllerUSB.ino b/CD32ControllerUSB/CD32ControllerUSB.ino index 977e56f..9a5cf89 100644 --- a/CD32ControllerUSB/CD32ControllerUSB.ino +++ b/CD32ControllerUSB/CD32ControllerUSB.ino @@ -21,6 +21,7 @@ * */ +#include #include "Gamepad.h" // ATT: 20 chars max (including NULL at the end) according to Arduino source code. @@ -28,6 +29,8 @@ const char *gp_serial = "CD32/C= to USB"; #define BUTTON_READ_DELAY 100 // Button read delay in µs +#define MODE_CD32 0 +#define MODE_3BUTTON 42 // Controller DB9 pins (looking face-on to the end of the plug): // @@ -72,9 +75,11 @@ uint8_t buttonsPrev = 0; // Timing uint32_t microsButtons = 0; +uint32_t millisStart = 0; // CD32 controller detection uint8_t detection = 0; +uint8_t mode = MODE_CD32; void setup() { @@ -87,59 +92,69 @@ void setup() PORTD |= B10011101; // high to enable internal pull-up DDRF &= ~B11000000; // input PORTF |= B11000000; // high to enable internal pull-up + + delay(500); + startupConfig(); } -void loop() +void loop() { while(1) { // Read X and Y axes axes = ~(PIND & B00011101); - // See if enough time has passed since last button read - if(micros() - microsButtons > BUTTON_READ_DELAY) + if(mode == MODE_CD32) { - // Set pin 6 (clock, PD7) and pin 5 (latch, PF7) as output low - PORTD &= ~B10000000; // low to disable internal pull-up (will become low when set as output) - DDRD |= B10000000; // output - PORTF &= ~B10000000; // low to disable internal pull-up (will become low when set as output) - DDRF |= B10000000; // output - delayMicroseconds(40); + // See if enough time has passed since last button read + if(micros() - microsButtons > BUTTON_READ_DELAY) + { + // Set pin 6 (clock, PD7) and pin 5 (latch, PF7) as output low + PORTD &= ~B10000000; // low to disable internal pull-up (will become low when set as output) + DDRD |= B10000000; // output + PORTF &= ~B10000000; // low to disable internal pull-up (will become low when set as output) + DDRF |= B10000000; // output + delayMicroseconds(40); - // Clear buttons - buttons = 0; + // Clear buttons + buttons = 0; - // Read buttons - (PINF & B01000000) ? buttons &= ~B00000010 : buttons |= B00000010; // Blue (2) - sendClock(); - (PINF & B01000000) ? buttons &= ~B00000001 : buttons |= B00000001; // Red (1) - sendClock(); - (PINF & B01000000) ? buttons &= ~B00001000 : buttons |= B00001000; // Yellow (4) - sendClock(); - (PINF & B01000000) ? buttons &= ~B00000100 : buttons |= B00000100; // Green (3) - sendClock(); - (PINF & B01000000) ? buttons &= ~B00100000 : buttons |= B00100000; // RTrig (6) - sendClock(); - (PINF & B01000000) ? buttons &= ~B00010000 : buttons |= B00010000; // LTrig (5) - sendClock(); - (PINF & B01000000) ? buttons &= ~B01000000 : buttons |= B01000000; // Play (7) - sendClock(); - (PINF & B01000000) ? detection |= B00000001 : detection &= ~B00000001; // First detection bit (should be 1) - sendClock(); - (PINF & B01000000) ? detection |= B00000010 : detection &= ~B00000010; // Second detection bit (should be 0) + // Read buttons + (PINF & B01000000) ? buttons &= ~B00000010 : buttons |= B00000010; // Blue (2) + sendClock(); + (PINF & B01000000) ? buttons &= ~B00000001 : buttons |= B00000001; // Red (1) + sendClock(); + (PINF & B01000000) ? buttons &= ~B00001000 : buttons |= B00001000; // Yellow (4) + sendClock(); + (PINF & B01000000) ? buttons &= ~B00000100 : buttons |= B00000100; // Green (3) + sendClock(); + (PINF & B01000000) ? buttons &= ~B00100000 : buttons |= B00100000; // RTrig (6) + sendClock(); + (PINF & B01000000) ? buttons &= ~B00010000 : buttons |= B00010000; // LTrig (5) + sendClock(); + (PINF & B01000000) ? buttons &= ~B01000000 : buttons |= B01000000; // Play (7) + sendClock(); + (PINF & B01000000) ? detection |= B00000001 : detection &= ~B00000001; // First detection bit (should be 1) + sendClock(); + (PINF & B01000000) ? detection |= B00000010 : detection &= ~B00000010; // Second detection bit (should be 0) - // Set pin 5 (latch, PF7) and pin 6 (clock, PD7) as input with pull-ups - DDRF &= ~B10000000; // input - PORTF |= B10000000; // high to enable internal pull-up - DDRD &= ~B10000000; // input - PORTD |= B10000000; // high to enable internal pull-up - delayMicroseconds(40); + // Set pin 5 (latch, PF7) and pin 6 (clock, PD7) as input with pull-ups + DDRF &= ~B10000000; // input + PORTF |= B10000000; // high to enable internal pull-up + DDRD &= ~B10000000; // input + PORTD |= B10000000; // high to enable internal pull-up + delayMicroseconds(40); - // Was a CD32 gamepad detected? If not, read button 1 and 2 "normally". - if(detection != B0000001) - buttons = ~( ((PIND & B10000000) >> 7) | ((PINF & B01000000) >> 5) | B11111100 ); - - microsButtons = micros(); + // Was a CD32 gamepad detected? If not, read button 1 and 2 "normally". + if(detection != B0000001) + buttons = ~( ((PIND & B10000000) >> 7) | ((PINF & B01000000) >> 5) | B11111100 ); + + microsButtons = micros(); + } } - + else + { + buttons = ~( ((PIND & B10000000) >> 7) | ((PINF & B11000000) >> 5) | B11111000 ); + } + // Has any buttons changed state? if (buttons != buttonsPrev) { @@ -163,7 +178,7 @@ void loop() Gamepad.send(); usbUpdate = false; } -} +}} void sendClock() { @@ -173,3 +188,28 @@ void sendClock() PORTD &= ~B10000000; // Disable pull-up delayMicroseconds(40); } + +void startupConfig() +{ + // Read current mode from eeprom + mode = EEPROM.read(0); + if(mode != MODE_3BUTTON) + mode = MODE_CD32; + + // Get time + millisStart = millis(); + + // Wait as long as button 1 is pressed + while(!(PIND & B10000000)) + { + if(millis() - millisStart > 5000) // Button 1 has been pressed for more than 5 seconds + { + // Toggle mode and save to EEPROM + (mode == MODE_3BUTTON) ? mode = MODE_CD32 : mode = MODE_3BUTTON; + EEPROM.update(0,mode); + return; + } + } + + return; +} \ No newline at end of file diff --git a/NeoGeoControllerUSB/Gamepad.cpp b/NeoGeoControllerUSB/Gamepad.cpp new file mode 100644 index 0000000..490af9f --- /dev/null +++ b/NeoGeoControllerUSB/Gamepad.cpp @@ -0,0 +1,156 @@ +/* Gamepad.cpp + * + * Based on the advanced HID library for Arduino: + * https://github.com/NicoHood/HID + * Copyright (c) 2014-2015 NicoHood + * + * Copyright (c) 2020 Mikael Norrgård + * + * 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 . + * + */ +#include "Gamepad.h" + +static const uint8_t _hidReportDescriptor[] PROGMEM = { + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x04, // USAGE (Joystick) + 0xa1, 0x01, // COLLECTION (Application) + 0xa1, 0x00, // COLLECTION (Physical) + + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x0c, // USAGE_MAXIMUM (Button 12) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x0c, // REPORT_COUNT (12) + 0x75, 0x01, // REPORT_SIZE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + 0x95, 0x01, // REPORT_COUNT (1) ; pad out the bits into a number divisible by 8 + 0x75, 0x04, // REPORT_SIZE (4) + 0x81, 0x03, // INPUT (Const,Var,Abs) + + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x01, // USAGE (pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x15, 0xff, // LOGICAL_MINIMUM (-1) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x95, 0x02, // REPORT_COUNT (2) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xc0, // END_COLLECTION + + 0xc0, // END_COLLECTION + 0xc0, // END_COLLECTION +}; + +Gamepad_::Gamepad_(void) : PluggableUSBModule(1, 1, epType), protocol(HID_REPORT_PROTOCOL), idle(1) +{ + epType[0] = EP_TYPE_INTERRUPT_IN; + PluggableUSB().plug(this); +} + +int Gamepad_::getInterface(uint8_t* interfaceCount) +{ + *interfaceCount += 1; // uses 1 + HIDDescriptor hidInterface = { + D_INTERFACE(pluggedInterface, 1, USB_DEVICE_CLASS_HUMAN_INTERFACE, HID_SUBCLASS_NONE, HID_PROTOCOL_NONE), + D_HIDREPORT(sizeof(_hidReportDescriptor)), + D_ENDPOINT(USB_ENDPOINT_IN(pluggedEndpoint), USB_ENDPOINT_TYPE_INTERRUPT, USB_EP_SIZE, 0x01) + }; + return USB_SendControl(0, &hidInterface, sizeof(hidInterface)); +} + +int Gamepad_::getDescriptor(USBSetup& setup) +{ + // Check if this is a HID Class Descriptor request + if (setup.bmRequestType != REQUEST_DEVICETOHOST_STANDARD_INTERFACE) { return 0; } + if (setup.wValueH != HID_REPORT_DESCRIPTOR_TYPE) { return 0; } + + // In a HID Class Descriptor wIndex cointains the interface number + if (setup.wIndex != pluggedInterface) { return 0; } + + // Reset the protocol on reenumeration. Normally the host should not assume the state of the protocol + // due to the USB specs, but Windows and Linux just assumes its in report mode. + protocol = HID_REPORT_PROTOCOL; + + return USB_SendControl(TRANSFER_PGM, _hidReportDescriptor, sizeof(_hidReportDescriptor)); +} + +bool Gamepad_::setup(USBSetup& setup) +{ + if (pluggedInterface != setup.wIndex) { + return false; + } + + uint8_t request = setup.bRequest; + uint8_t requestType = setup.bmRequestType; + + if (requestType == REQUEST_DEVICETOHOST_CLASS_INTERFACE) + { + if (request == HID_GET_REPORT) { + // TODO: HID_GetReport(); + return true; + } + if (request == HID_GET_PROTOCOL) { + // TODO: Send8(protocol); + return true; + } + } + + if (requestType == REQUEST_HOSTTODEVICE_CLASS_INTERFACE) + { + if (request == HID_SET_PROTOCOL) { + protocol = setup.wValueL; + return true; + } + if (request == HID_SET_IDLE) { + idle = setup.wValueL; + return true; + } + if (request == HID_SET_REPORT) + { + } + } + + return false; +} + +void Gamepad_::reset() +{ + _GamepadReport.X = 0; + _GamepadReport.Y = 0; + _GamepadReport.buttons = 0; + this->send(); +} + +void Gamepad_::send() +{ + USB_Send(pluggedEndpoint | TRANSFER_RELEASE, &_GamepadReport, sizeof(GamepadReport)); +} + +uint8_t Gamepad_::getShortName(char *name) +{ + if(!next) + { + strcpy(name, gp_serial); + return strlen(name); + } + return 0; +} diff --git a/NeoGeoControllerUSB/Gamepad.h b/NeoGeoControllerUSB/Gamepad.h new file mode 100644 index 0000000..968bc4e --- /dev/null +++ b/NeoGeoControllerUSB/Gamepad.h @@ -0,0 +1,60 @@ +/* Gamepad.h + * + * Based on the advanced HID library for Arduino: + * https://github.com/NicoHood/HID + * Copyright (c) 2014-2015 NicoHood + * + * Copyright (c) 2020 Mikael Norrgård + * + * 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 . + * + */ + +#pragma once + +#include "HID.h" + +extern const char* gp_serial; + +typedef struct { + uint16_t buttons : 12; + int8_t X; + int8_t Y; +} GamepadReport; + + +class Gamepad_ : public PluggableUSBModule +{ + private: + uint8_t reportId; + + protected: + int getInterface(uint8_t* interfaceCount); + int getDescriptor(USBSetup& setup); + uint8_t getShortName(char *name); + bool setup(USBSetup& setup); + + uint8_t epType[1]; + uint8_t protocol; + uint8_t idle; + + public: + GamepadReport _GamepadReport; + Gamepad_(void); + void reset(void); + void send(); +}; diff --git a/NeoGeoControllerUSB/NeoGeoControllerUSB.ino b/NeoGeoControllerUSB/NeoGeoControllerUSB.ino new file mode 100644 index 0000000..e8c4248 --- /dev/null +++ b/NeoGeoControllerUSB/NeoGeoControllerUSB.ino @@ -0,0 +1,169 @@ +/* NeoGeo Controller to USB + * Author: Mikael Norrgård + * + * Copyright (c) 2020 Mikael Norrgård + * + * 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 . + * + */ + +#include "Gamepad.h" + +#define DEBOUNCE 0 // 1=Diddly-squat-Delay-Debouncing™ activated, 0=Debounce deactivated +#define DEBOUNCE_TIME 10 // Debounce time in milliseconds +//#define DEBUG // Enables debugging (sends debug data to usb serial) + +const char *gp_serial = "NeoGeo to USB"; + +Gamepad_ Gamepad; // Set up USB HID gamepad +bool usbUpdate = false; // Should gamepad data be sent to USB? +bool debounce = DEBOUNCE; // Debounce? +uint8_t pin; // Used in for loops +uint32_t millisNow = 0; // Used for Diddly-squat-Delay-Debouncing™ + +uint8_t axesDirect = 0x0f; +uint8_t axes = 0x0f; +uint8_t axesPrev = 0x0f; +uint8_t axesBits[4] = {0x10,0x20,0x40,0x80}; +uint32_t axesMillis[4]; + +uint16_t buttonsDirect = 0; +uint16_t buttons = 0; +uint16_t buttonsPrev = 0; +uint16_t buttonsBits[12] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x100,0x200,0x400,0x800}; +uint32_t buttonsMillis[12]; + +#ifdef DEBUG + char buf[16]; + uint32_t millisSent = 0; +#endif + +void setup() +{ + // Axes + DDRF &= ~B11110000; // Set A0-A3 as inputs + PORTF |= B11110000; // Enable internal pull-up resistors + + // Buttons + DDRD &= ~B10011111; // Set PD0-PD4 and PD7 as inputs + PORTD |= B10011111; // Enable internal pull-up resistors + DDRB &= ~B01111110; // Set PB1-PB6 as inputs + PORTB |= B01111110; // Enable internal pull-up resistors + + // Debounce selector switch (currently disabled) + DDRE &= ~B01000000; // Pin 7 as input + PORTE |= B01000000; // Enable internal pull-up resistor + + // Initialize debouncing timestamps + for(pin=0; pin<4; pin++) + axesMillis[pin]=0; + for(pin=0; pin<12; pin++) + buttonsMillis[pin]=0; + + #ifdef DEBUG + Serial.begin(115200); + #endif +} + +void loop() +{ + // Get current time, the millis() function should take about 2µs to complete + millisNow = millis(); + + for(uint8_t i=0; i<10; i++) // One iteration (when debounce is enabled) takes approximately 35µs to complete, so we don't need to check the time between every iteration + { + // Read axis and button inputs (bitwise NOT results in a 1 when button/axis pressed) + axesDirect = ~(PINF & B11110000); + buttonsDirect = ~((PIND & B00011111) | ((PIND & B10000000) << 4) | ((PINB & B01111110) << 4)); + + if(debounce) + { + // Debounce axes + for(pin=0; pin<4; pin++) + { + // Check if the current pin state is different to the stored state and that enough time has passed since last change + if((axesDirect & axesBits[pin]) != (axes & axesBits[pin]) && (millisNow - axesMillis[pin]) > DEBOUNCE_TIME) + { + // Toggle the pin, we can safely do this because we know the current state is different to the stored state + axes ^= axesBits[pin]; + // Update the timestamp for the pin + axesMillis[pin] = millisNow; + } + } + + // Debounce buttons + for(pin=0; pin<12; pin++) + { + // Check if the current pin state is different to the stored state and that enough time has passed since last change + if((buttonsDirect & buttonsBits[pin]) != (buttons & buttonsBits[pin]) && (millisNow - buttonsMillis[pin]) > DEBOUNCE_TIME) + { + // Toggle the pin, we can safely do this because we know the current state is different to the stored state + buttons ^= buttonsBits[pin]; + // Update the timestamp for the pin + buttonsMillis[pin] = millisNow; + } + } + } + else + { + axes = axesDirect; + buttons = buttonsDirect; + } + + // Has axis inputs changed? + if(axes != axesPrev) + { + // UP + DOWN = UP, SOCD (Simultaneous Opposite Cardinal Directions) Cleaner + if(axes & B10000000) + Gamepad._GamepadReport.Y = -1; + else if(axes & B01000000) + Gamepad._GamepadReport.Y = 1; + else + Gamepad._GamepadReport.Y = 0; + // UP + DOWN = NEUTRAL + //Gamepad._GamepadReport.Y = ((axes & B01000000)>>6) - ((axes & B10000000)>>7); + // LEFT + RIGHT = NEUTRAL + Gamepad._GamepadReport.X = ((axes & B00010000)>>4) - ((axes & B00100000)>>5); + axesPrev = axes; + usbUpdate = true; + } + + // Has button inputs changed? + if(buttons != buttonsPrev) + { + Gamepad._GamepadReport.buttons = buttons; + buttonsPrev = buttons; + usbUpdate = true; + } + + // Should gamepad data be sent to USB? + if(usbUpdate) + { + Gamepad.send(); + usbUpdate = false; + + #ifdef DEBUG + sprintf(buf, "%06lu: %d%d%d%d", millisNow-millisSent, ((axes & 0x10)>>4), ((axes & 0x20)>>5), ((axes & 0x40)>>6), ((axes & 0x80)>>7) ); + Serial.print(buf); + sprintf(buf, " %d%d%d%d", (buttons & 0x01), ((buttons & 0x02)>>1), ((buttons & 0x04)>>2), ((buttons & 0x08)>>3) ); + Serial.println(buf); + millisSent = millisNow; + #endif + } + } + +} diff --git a/PCEngineControllerUSB/README.md b/PCEngineControllerUSB/README.md index 487a67f..9614d48 100644 --- a/PCEngineControllerUSB/README.md +++ b/PCEngineControllerUSB/README.md @@ -1,9 +1,7 @@ # DaemonBite PC Engine / TurboGrafx-16 Controllers To USB Adapter ## Introduction -This is a simple to build adapter for connecting PC Engine / TurboGrafx-16 controllers to USB. - -NOTE: This adapter is in BETA and not yet properly tested. +This is a simple to build adapter for connecting PC Engine / TurboGrafx-16 controllers to USB with turbo functionality support. The input lag for this adapter is minimal (should be less 1ms average connected to MiSTer). diff --git a/SegaControllerUSB/Gamepad.cpp b/SegaControllerUSB/Gamepad.cpp index 879fe2f..77bf764 100644 --- a/SegaControllerUSB/Gamepad.cpp +++ b/SegaControllerUSB/Gamepad.cpp @@ -34,12 +34,16 @@ static const uint8_t _hidReportDescriptor[] PROGMEM = { 0x05, 0x09, // USAGE_PAGE (Button) 0x19, 0x01, // USAGE_MINIMUM (Button 1) - 0x29, 0x08, // USAGE_MAXIMUM (Button 8) + 0x29, 0x09, // USAGE_MAXIMUM (Button 9) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x01, // LOGICAL_MAXIMUM (1) - 0x95, 0x08, // REPORT_COUNT (8) + 0x95, 0x09, // REPORT_COUNT (9) 0x75, 0x01, // REPORT_SIZE (1) 0x81, 0x02, // INPUT (Data,Var,Abs) + + 0x95, 0x01, // REPORT_COUNT (1) ; pad out the bits into a number divisible by 8 + 0x75, 0x07, // REPORT_SIZE (7) + 0x81, 0x03, // INPUT (Const,Var,Abs) 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x01, // USAGE (pointer) diff --git a/SegaControllerUSB/Gamepad.h b/SegaControllerUSB/Gamepad.h index d2bd4c0..a68575e 100644 --- a/SegaControllerUSB/Gamepad.h +++ b/SegaControllerUSB/Gamepad.h @@ -34,23 +34,9 @@ extern const char* gp_serial; // The numbers after colon are bit fields, meaning how many bits the field uses. // Remove those if there are problems typedef struct { - union - { - struct { - bool b0: 1 ; - bool b1: 1 ; - bool b2: 1 ; - bool b3: 1 ; - bool b4: 1 ; - bool b5: 1 ; - bool b6: 1 ; - bool b7: 1 ; - }; - uint8_t buttons; - }; - int8_t X ; - int8_t Y ; - + uint16_t buttons; + int8_t X; + int8_t Y; } GamepadReport; diff --git a/SegaControllerUSB/SegaController32U4.cpp b/SegaControllerUSB/SegaController32U4.cpp index 1937869..b04e1e1 100644 --- a/SegaControllerUSB/SegaController32U4.cpp +++ b/SegaControllerUSB/SegaController32U4.cpp @@ -62,7 +62,7 @@ word SegaController32U4::getStateMD() // 3 HI C B Right Left Down Up (Read B, C and directions in this cycle) // 4 LO Start A 0 0 0 0 (Check for six button controller in this cycle) // 5 HI C B Mode X Y Z (Read X,Y,Z and Mode in this cycle) - // 6 LO --- --- --- --- --- --- + // 6 LO --- --- --- --- --- Home (Home only for 8bitdo wireless gamepads) // 7 HI --- --- --- --- --- --- // Set the select pin low/high @@ -139,7 +139,10 @@ word SegaController32U4::getStateMD() } else { - _ignoreCycles--; + if(_ignoreCycles-- == 2) // Decrease the ignore cycles counter and read 8bitdo home in first "ignored" cycle, this cycle is unused on normal 6-button controllers + { + (bitRead(_inputReg1, DB9_PIN1_BIT) == LOW) ? _currentState |= SC_BTN_HOME : _currentState &= ~SC_BTN_HOME; + } } return _currentState; diff --git a/SegaControllerUSB/SegaController32U4.h b/SegaControllerUSB/SegaController32U4.h index e02684f..f1996be 100644 --- a/SegaControllerUSB/SegaController32U4.h +++ b/SegaControllerUSB/SegaController32U4.h @@ -42,23 +42,23 @@ enum { - SC_CTL_ON = 1, // The controller is connected (not used) - SC_BTN_UP = 2, - SC_BTN_DOWN = 4, - SC_BTN_LEFT = 8, - SC_BTN_RIGHT = 16, - SC_BTN_A = 32, - SC_BTN_B = 64, - SC_BTN_C = 128, - SC_BTN_X = 256, - SC_BTN_Y = 512, - SC_BTN_Z = 1024, - SC_BTN_START = 2048, - SC_BTN_MODE = 4096, - SC_BIT_UP = 1, - SC_BIT_DOWN = 2, - SC_BIT_LEFT = 3, - SC_BIT_RIGHT = 4, + SC_BTN_UP = 1, + SC_BTN_DOWN = 2, + SC_BTN_LEFT = 4, + SC_BTN_RIGHT = 8, + SC_BTN_A = 16, + SC_BTN_B = 32, + SC_BTN_C = 64, + SC_BTN_X = 128, + SC_BTN_Y = 256, + SC_BTN_Z = 512, + SC_BTN_START = 1024, + SC_BTN_MODE = 2048, + SC_BTN_HOME = 4096, + SC_BIT_SH_UP = 0, + SC_BIT_SH_DOWN = 1, + SC_BIT_SH_LEFT = 2, + SC_BIT_SH_RIGHT = 3, DB9_PIN1_BIT = 7, DB9_PIN2_BIT = 6, DB9_PIN3_BIT = 5, diff --git a/SegaControllerUSB/SegaControllerUSB.ino b/SegaControllerUSB/SegaControllerUSB.ino index fa846da..0e71fa7 100644 --- a/SegaControllerUSB/SegaControllerUSB.ino +++ b/SegaControllerUSB/SegaControllerUSB.ino @@ -58,20 +58,20 @@ void setup() { } -void loop() +void loop() { while(1) { currentState = controller.getStateMD(); sendState(); -} +}} void sendState() { // Only report controller state if it has changed if (currentState != lastState) { - Gamepad._GamepadReport.buttons = currentState >> 5; - Gamepad._GamepadReport.Y = ((currentState & SC_BTN_DOWN) >> SC_BIT_DOWN) - ((currentState & SC_BTN_UP) >> SC_BIT_UP); - Gamepad._GamepadReport.X = ((currentState & SC_BTN_RIGHT) >> SC_BIT_RIGHT) - ((currentState & SC_BTN_LEFT) >> SC_BIT_LEFT); + Gamepad._GamepadReport.buttons = currentState >> 4; + Gamepad._GamepadReport.Y = ((currentState & SC_BTN_DOWN) >> SC_BIT_SH_DOWN) - ((currentState & SC_BTN_UP) >> SC_BIT_SH_UP); + Gamepad._GamepadReport.X = ((currentState & SC_BTN_RIGHT) >> SC_BIT_SH_RIGHT) - ((currentState & SC_BTN_LEFT) >> SC_BIT_SH_LEFT); Gamepad.send(); lastState = currentState; } diff --git a/SegaTwoControllersUSB/Gamepad.cpp b/SegaTwoControllersUSB/Gamepad.cpp index 879fe2f..77bf764 100644 --- a/SegaTwoControllersUSB/Gamepad.cpp +++ b/SegaTwoControllersUSB/Gamepad.cpp @@ -34,12 +34,16 @@ static const uint8_t _hidReportDescriptor[] PROGMEM = { 0x05, 0x09, // USAGE_PAGE (Button) 0x19, 0x01, // USAGE_MINIMUM (Button 1) - 0x29, 0x08, // USAGE_MAXIMUM (Button 8) + 0x29, 0x09, // USAGE_MAXIMUM (Button 9) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x01, // LOGICAL_MAXIMUM (1) - 0x95, 0x08, // REPORT_COUNT (8) + 0x95, 0x09, // REPORT_COUNT (9) 0x75, 0x01, // REPORT_SIZE (1) 0x81, 0x02, // INPUT (Data,Var,Abs) + + 0x95, 0x01, // REPORT_COUNT (1) ; pad out the bits into a number divisible by 8 + 0x75, 0x07, // REPORT_SIZE (7) + 0x81, 0x03, // INPUT (Const,Var,Abs) 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x01, // USAGE (pointer) diff --git a/SegaTwoControllersUSB/Gamepad.h b/SegaTwoControllersUSB/Gamepad.h index d2bd4c0..a68575e 100644 --- a/SegaTwoControllersUSB/Gamepad.h +++ b/SegaTwoControllersUSB/Gamepad.h @@ -34,23 +34,9 @@ extern const char* gp_serial; // The numbers after colon are bit fields, meaning how many bits the field uses. // Remove those if there are problems typedef struct { - union - { - struct { - bool b0: 1 ; - bool b1: 1 ; - bool b2: 1 ; - bool b3: 1 ; - bool b4: 1 ; - bool b5: 1 ; - bool b6: 1 ; - bool b7: 1 ; - }; - uint8_t buttons; - }; - int8_t X ; - int8_t Y ; - + uint16_t buttons; + int8_t X; + int8_t Y; } GamepadReport; diff --git a/SegaTwoControllersUSB/SegaControllers32U4.cpp b/SegaTwoControllersUSB/SegaControllers32U4.cpp index 2e6dfc6..c9180cf 100644 --- a/SegaTwoControllersUSB/SegaControllers32U4.cpp +++ b/SegaTwoControllersUSB/SegaControllers32U4.cpp @@ -89,7 +89,7 @@ void SegaControllers32U4::readState() // 3 HI C B Right Left Down Up (Read B, C and directions in this cycle) // 4 LO Start A 0 0 0 0 (Check for six button controller in this cycle) // 5 HI C B Mode X Y Z (Read X,Y,Z and Mode in this cycle) -// 6 LO --- --- --- --- --- --- +// 6 LO --- --- --- --- --- Home (Home only for 8bitdo wireless gamepads) // 7 HI --- --- --- --- --- --- void SegaControllers32U4::readPort1() @@ -157,7 +157,10 @@ void SegaControllers32U4::readPort1() } else { - _ignoreCycles[0]--; + if(_ignoreCycles[0]-- == 2) // Decrease the ignore cycles counter and read 8bitdo home in first "ignored" cycle, this cycle is unused on normal 6-button controllers + { + (bitRead(_inputReg1, DB9_PIN1_BIT1) == LOW) ? currentState[0] |= SC_BTN_HOME : currentState[0] &= ~SC_BTN_HOME; + } } } @@ -226,7 +229,10 @@ void SegaControllers32U4::readPort2() } else { - _ignoreCycles[1]--; + if(_ignoreCycles[1]-- == 2) // Decrease the ignore cycles counter and read 8bitdo home in first "ignored" cycle, this cycle is unused on normal 6-button controllers + { + (bitRead(_inputReg3, DB9_PIN1_BIT2) == LOW) ? currentState[1] |= SC_BTN_HOME : currentState[1] &= ~SC_BTN_HOME; + } } } diff --git a/SegaTwoControllersUSB/SegaControllers32U4.h b/SegaTwoControllersUSB/SegaControllers32U4.h index 4260bdf..0626b23 100644 --- a/SegaTwoControllersUSB/SegaControllers32U4.h +++ b/SegaTwoControllersUSB/SegaControllers32U4.h @@ -30,23 +30,23 @@ enum { - SC_CTL_ON = 1, // The controller is connected (not used) - SC_BTN_UP = 2, - SC_BTN_DOWN = 4, - SC_BTN_LEFT = 8, - SC_BTN_RIGHT = 16, - SC_BTN_A = 32, - SC_BTN_B = 64, - SC_BTN_C = 128, - SC_BTN_X = 256, - SC_BTN_Y = 512, - SC_BTN_Z = 1024, - SC_BTN_START = 2048, - SC_BTN_MODE = 4096, - SC_BIT_UP = 1, - SC_BIT_DOWN = 2, - SC_BIT_LEFT = 3, - SC_BIT_RIGHT = 4, + SC_BTN_UP = 1, + SC_BTN_DOWN = 2, + SC_BTN_LEFT = 4, + SC_BTN_RIGHT = 8, + SC_BTN_A = 16, + SC_BTN_B = 32, + SC_BTN_C = 64, + SC_BTN_X = 128, + SC_BTN_Y = 256, + SC_BTN_Z = 512, + SC_BTN_START = 1024, + SC_BTN_MODE = 2048, + SC_BTN_HOME = 4096, + SC_BIT_SH_UP = 0, + SC_BIT_SH_DOWN = 1, + SC_BIT_SH_LEFT = 2, + SC_BIT_SH_RIGHT = 3, SC_PIN1_BIT = 0, SC_PIN2_BIT = 1, SC_PIN3_BIT = 2, diff --git a/SegaTwoControllersUSB/SegaTwoControllersUSB.ino b/SegaTwoControllersUSB/SegaTwoControllersUSB.ino index 7a49ced..77d0e69 100644 --- a/SegaTwoControllersUSB/SegaTwoControllersUSB.ino +++ b/SegaTwoControllersUSB/SegaTwoControllersUSB.ino @@ -79,9 +79,9 @@ void sendState(byte gp) // Only report controller state if it has changed if (controllers.currentState[gp] != lastState[gp]) { - Gamepad[gp]._GamepadReport.buttons = controllers.currentState[gp] >> 5; - Gamepad[gp]._GamepadReport.Y = ((controllers.currentState[gp] & SC_BTN_DOWN) >> SC_BIT_DOWN) - ((controllers.currentState[gp] & SC_BTN_UP) >> SC_BIT_UP); - Gamepad[gp]._GamepadReport.X = ((controllers.currentState[gp] & SC_BTN_RIGHT) >> SC_BIT_RIGHT) - ((controllers.currentState[gp] & SC_BTN_LEFT) >> SC_BIT_LEFT); + Gamepad[gp]._GamepadReport.buttons = controllers.currentState[gp] >> 4; + Gamepad[gp]._GamepadReport.Y = ((controllers.currentState[gp] & SC_BTN_DOWN) >> SC_BIT_SH_DOWN) - ((controllers.currentState[gp] & SC_BTN_UP) >> SC_BIT_SH_UP); + Gamepad[gp]._GamepadReport.X = ((controllers.currentState[gp] & SC_BTN_RIGHT) >> SC_BIT_SH_RIGHT) - ((controllers.currentState[gp] & SC_BTN_LEFT) >> SC_BIT_SH_LEFT); Gamepad[gp].send(); lastState[gp] = controllers.currentState[gp]; }