Toggle switch act as a button (UnoJoy)

Hi,
I was messing around with the UnoJoy library for some time now to get the hang of it, to eventually, construct a flight sim. But I couldn't get something to function properly, a toggle switch (spst switch). When you hook up a toggle switch to UnoJoy, it registers pressed and released only when it is toggled on and off, which is not something I'm looking for :/. I trying to figure out a way on how to trigger a button press and release as it is put in either of the on/off position (kinda hard to explain..) . And I really don't know how to do this... I search around for it but most results weren't straightforward or they were for a similar library called MegaJoy. I actually did try to implement both libraries (UnoJoy and MegaJoy) but that resulted in conflicting errors between these libraries. This might be a really simple thing for most people but I'm really new to this scene so any help will be deeply appreciated :] . I will link my code and UnoJoy.h in case to build of it.

Code:

#include "UnoJoy.h"

void setup(){
  setupPins();
  setupUnoJoy();
}

void loop(){
  // Always be getting fresh data
  dataForController_t controllerData = getControllerData();
  setControllerData(controllerData);
}
dataForController_t getControllerData(void){
  
  // Set up a place for our controller data
  //  Use the getBlankDataForController() function, since
  //  just declaring a fresh dataForController_t tends
  //  to get you one filled with junk from other, random
  //  values that were in those memory locations before
  dataForController_t controllerData = getBlankDataForController();
  // Since our buttons are all held high and
  //  pulled low when pressed, we use the "!"
  //  operator to invert the readings from the pins
  controllerData.triangleOn = !digitalRead(2);
  controllerData.circleOn = !digitalRead(3);
  controllerData.squareOn = !digitalRead(4);
  controllerData.crossOn = !digitalRead(5);
  controllerData.l3On = digitalRead(6);        //spst switch
  controllerData.r3On = digitalRead(7);           //spst switch
  controllerData.dpadLeftOn = !digitalRead(8);
  controllerData.dpadRightOn = !digitalRead(9);
  controllerData.l1On = !digitalRead(10);
  controllerData.r1On = !digitalRead(11);
  controllerData.l2On = !digitalRead(12);
  controllerData.r2On = digitalRead(13);        //spst switch

  // Set the analog sticks
  //  Since analogRead(pin) returns a 10 bit value,
  //  we need to perform a bit shift operation to
  //  lose the 2 least significant bits and get an
  //  8 bit number that we can use  
  controllerData.leftStickX = analogRead(A0) >> 2;
  controllerData.leftStickY = analogRead(A1) >> 2;
  controllerData.rightStickX = analogRead(A2) >> 2;
  // And return the data!
  return controllerData;
}

void setupPins(void){
  // Set all the digital pins as inputs
  // with the pull-up enabled, except for the 
  // two serial line pins
  for (int i = 2; i <= 12; i++){
    pinMode(i, INPUT);
    digitalWrite(i, HIGH);
  }
  pinMode(A4, INPUT);
  digitalWrite(A4, HIGH);
  pinMode(A5, INPUT);
  digitalWrite(A5, HIGH);
}

UnoJoy.h:

/*  UnoJoy.h
 *   Alan Chatham - 2012
 *    RMIT Exertion Games Lab
 *
 *  This library gives you a standard way to create Arduino code that talks
 *   to the UnoJoy firmware in order to make native USB game controllers.
 *  Functions:
 *   setupUnoJoy()
 *   getBlankDataForController()
 *   setControllerData(dataForController_t dataToSet)
 *
 *   NOTE: You cannot use pins 0 or 1 if you use this code - they are used by the serial communication.
 *         Also, the setupUnoJoy() function starts the serial port at 38400, so if you're using
 *         the serial port to debug and it's not working, this may be your problem.
 *   
 *   === How to use this library ===
 *   If you want, you can move this file into your Arduino/Libraries folder, then use it like a normal library.
 *   However, since you'll need to refer to the details of the dataForController_t struct in this file, I would suggest you use
 *    it by adding it to your Arduino sketch manually (in Arduino, go to Sketch->Add file...)
 *
 *  To use this library to make a controller, you'll need to do 3 things:
 *   Call setupUnoJoy(); in the setup() block
 *   Create and populate a dataForController_t type variable and fill it with your data
 *         The getBlankDataForController() function is good for that.
 *   Call setControllerData(yourData); where yourData is the variable from above,
 *         somewhere in your loop(), once you're ready to push your controller data to the system.
 *         If you forget to call sendControllerData in your loop, your controller won't ever do anything
 *
 *  You can then debug the controller with the included Processing sketch, UnoJoyProcessingVisualizer
 *  
 *  To turn it into an actual USB video game controller, you'll reflash the
 *   Arduino's communication's chip using the instructions found in the 'Firmware' folder,
 *   then unplug and re-plug in the Arduino. 
 * 
 *  Details about the dataForController_t type are below, but in order to create and use it,
 *   you'll declare it like:
 *
 *      dataForController_t sexyControllerData;
 *
 *   and then control button presses and analog stick movement with statements like:
 *      
 *      sexyControllerData.triangleOn = 1;   // Marks the triangle button as pressed
 *      sexyControllerData.squareOn = 0;     // Marks the square button as unpressed
 *      sexyControllerData.leftStickX = 90;  // Analog stick values can range from 0 - 255
 */

#ifndef UNOJOY_H
#define UNOJOY_H
    #include <stdint.h>
    #include <util/atomic.h>
    #include <Arduino.h>

    // This struct is the core of the library.
    //  You'll create an instance of this and manipulate it,
    //  then use the setControllerData function to send that data out.
    //  Don't change this - the order of the fields is important for
    //  the communication between the Arduino and it's communications chip.
	typedef struct dataForController_t
	{
		uint8_t triangleOn : 1;  // Each of these member variables
		uint8_t circleOn : 1;    //  control if a button is off or on
		uint8_t squareOn : 1;    // For the buttons, 
		uint8_t crossOn : 1;     //  0 is off
		uint8_t l1On : 1;        //  1 is on
		uint8_t l2On : 1;        
		uint8_t l3On : 1;        // The : 1 here just tells the compiler
		uint8_t r1On : 1;        //  to only have 1 bit for each variable.
                                 //  This saves a lot of space for our type!
		uint8_t r2On : 1;
		uint8_t r3On : 1;
		uint8_t selectOn : 1;
		uint8_t startOn : 1;
		uint8_t homeOn : 1;
		uint8_t dpadLeftOn : 1;
		uint8_t dpadUpOn : 1;
		uint8_t dpadRightOn : 1;

		uint8_t dpadDownOn : 1;
        uint8_t padding : 7;     // We end with 7 bytes of padding to make sure we get our data aligned in bytes
                                 
		uint8_t leftStickX : 8;  // Each of the analog stick values can range from 0 to 255
		uint8_t leftStickY : 8;  //  0 is fully left or up
		uint8_t rightStickX : 8; //  255 is fully right or down 
		uint8_t rightStickY : 8; //  128 is centered.
                                 // Important - analogRead(pin) returns a 10 bit value, so if you're getting strange
                                 //  results from analogRead, you may need to do (analogRead(pin) >> 2) to get good data
	} dataForController_t;
    
    // Call setupUnoJoy in the setup block of your program.
    //  It sets up the hardware UnoJoy needs to work properly
    void setupUnoJoy(void);
    
    // This sets the controller to reflect the button and
    // joystick positions you input (as a dataForController_t).
    // The controller will just send a zeroed (joysticks centered)
    // signal until you tell it otherwise with this function.
    void setControllerData(dataForController_t);
    
    // This function gives you a quick way to get a fresh
    //  dataForController_t with:
    //    No buttons pressed
    //    Joysticks centered
    // Very useful for starting each loop with a blank controller, for instance.
    // It returns a dataForController_t, so you want to call it like:
    //    myControllerData = getBlankDataForController();
    dataForController_t getBlankDataForController(void);
    
    // You can also call the setup function with an integer argument
    //  declaring how often, in  milliseconds, the buffer should send its data 
    //  via the serial port.  Use it if you need to do a lot of processing and
    //  the serial stuff is messing you up, but it'll make your controller
    //  more laggy.
    // IMPORTANT - you can't make this value greater than 20 or so - the code
    //  on the communications chip times out on each serial read after 25ms.
    //  If you need more time than 20ms, you'll have to alter the code for the
    //  ATmega8u2 as well
    void setupUnoJoy(int);
    
    
//----- End of the interface code you should be using -----//
//----- Below here is the actual implementation of
    
  // This dataForController_t is used to store
  //  the controller data that you want to send
  //  out to the controller.  You shouldn't mess
  //  with this directly - call setControllerData instead
  dataForController_t controllerDataBuffer;

  // This updates the data that the controller is sending out.
  //  The system actually works as following:
  //  The UnoJoy firmware on the ATmega8u2 regularly polls the
  //  Arduino chip for individual bytes of a dataForController_t.
  //  
  void setControllerData(dataForController_t controllerData){
    // Probably unecessary, but this guarantees that the data
    //  gets copied to our buffer all at once.
    ATOMIC_BLOCK(ATOMIC_FORCEON){
      controllerDataBuffer = controllerData;
    }
  }
  
  // serialCheckInterval governs how many ms between
  //  checks to the serial port for data.
  //  It shouldn't go above 20 or so, otherwise you might
  //  get unreliable data transmission to the UnoJoy firmware,
  //  since after it sends a request, it waits 25 ms for a response.
  //  If you really need to make it bigger than that, you'll have to
  //  adjust that timeout in the UnoJoy ATmega8u2 firmware code as well.
  volatile int serialCheckInterval = 1;
  // This is an internal counter variable to count ms between
  //  serial check times
  int serialCheckCounter = 0;
  
  // This is the setup function - it sets up the serial communication
  //  and the timer interrupt for actually sending the data back and forth.
  void setupUnoJoy(void){
    // First, let's zero out our controller data buffer (center the sticks)
    controllerDataBuffer = getBlankDataForController();
  
    // Start the serial port at the specific, low-error rate UnoJoy uses.
    //  If you want to change the rate, you'll have to change it in the
    //  firmware for the ATmega8u2 as well.  250,000 is actually the best rate,
    //  but it's not supported on Macs, breaking the processing debugger.
    Serial.begin(38400);
    
    // Now set up the Timer 0 compare register A
    //  so that Timer0 (used for millis() and such)
    //  also fires an interrupt when it's equal to
    //  128, not just on overflow.
    // This will fire our timer interrupt almost
    //  every 1 ms (1024 us to be exact).
    OCR0A = 128;
    TIMSK0 |= (1 << OCIE0A);
  }
  
  // If you really need to change the serial polling
  //  interval, use this function to initialize UnoJoy.
  //  interval is the polling frequency, in ms.
  void setupUnoJoy(int interval){
    serialCheckInterval = interval;
    setupUnoJoy();
  }
  
  // This interrupt gets called approximately once per ms.
  //  It counts how many ms between serial port polls,
  //  and if it's been long enough, polls the serial
  //  port to see if the UnoJoy firmware requested data.
  //  If it did, it transmits the appropriate data back.
  ISR(TIMER0_COMPA_vect){
    serialCheckCounter++;
    if (serialCheckCounter >= serialCheckInterval){
      serialCheckCounter = 0;
      // If there is incoming data stored in the Arduino serial buffer
      while (Serial.available() > 0) {
        //pinMode(13, OUTPUT);
        //digitalWrite(13, HIGH);
        // Get incoming byte from the ATmega8u2
        byte inByte = Serial.read();
        // That number tells us which byte of the dataForController_t struct
        //  to send out.
        Serial.write(((uint8_t*)&controllerDataBuffer)[inByte]);
        //digitalWrite(13, LOW);
      }
    }
  }
  
  // Returns a zeroed out (joysticks centered) 
  //  dataForController_t variable
  dataForController_t getBlankDataForController(void){
    // Create a dataForController_t
    dataForController_t controllerData;
    // Make the buttons zero
    controllerData.triangleOn = 0;
    controllerData.circleOn = 0;
    controllerData.squareOn = 0;
    controllerData.crossOn = 0;
    controllerData.l1On = 0;
    controllerData.l2On = 0;
    controllerData.l3On = 0;
    controllerData.r1On = 0;
    controllerData.r2On = 0;
    controllerData.r3On = 0;
    controllerData.dpadLeftOn = 0;
    controllerData.dpadUpOn = 0;
    controllerData.dpadRightOn = 0;
    controllerData.dpadDownOn = 0;  
    controllerData.selectOn = 0;
    controllerData.startOn = 0;
    controllerData.homeOn = 0;
    //Set the sticks to 128 - centered
    controllerData.leftStickX = 128;
    controllerData.leftStickY = 128;
    controllerData.rightStickX = 128;
    controllerData.rightStickY = 128;
    // And return the data!
    return controllerData;
  }

#endif

can you explain why?

i'm guessing you have two variables that are exclusive of one another (i.e. only one is true/active when the other isn't) For example

can you explain why?

Well, as I said, I am trying to build a flight sim, and the simulator software only does a certain action only when a button is pressed and released. That would require the toggle switch to be flipped on and off and I need it to be pressed and released when it's toggled in either position.

i'm guessing you have two variables that are exclusive of one and another (i.e only one is true/active when the other isn't) For example

Hmm, I don't think I understand what you mean... The example you showed me is just assigning button mapping to the digital pins on the Arduino (at least what i understand). The reason I removed the '!' on 13 pin, 7 pin, and 6 pin because they are the toggle switch mappings and I made it so that the pressed signal goes when they are toggled on. Anyways, I don't quite seem to understand the question about the variables' exclusiveness.

code can synthesis complementary press/released events when a toggle is switched.

it seems more conventional when checking button events that a singular event occurs. here's a function i use that indicates the button that was pressed

int
chkButtons ()
{
    for (unsigned n = 0; n < sizeof(pinsBut); n++)  {
        byte but = digitalRead (pinsBut [n]);

        if (butState [n] != but)  {
            butState [n] = but;

            delay (10);     // debounce

            if (On == but)
                return n;
        }
    }
    return -1;
}

but in your case, toggling the switch simultaneously produces a press and a release. these events could be captured and processed, but must be cleared afterwards.

    byte but = digitalRead (pin);
    if (butState [pin] != but)  {
        butState [pin] = but;

        if (LOW == but)  {
            controllerData.dpadLeftPressed   = 1;
            controllerData.dpadRightReleased = 1; 
        }
        else  {
            controllerData.dpadLeftRelased   = 1;
            controllerData.dpadRightPressed  = 1; 
        }
    }

yes this seems awkward

I'm sorry if this seems like a very stupid question, but what do you mean by 'butState'?

chkButtons() scans each button pinsBut[] and compares the current value to the previous value, buttonState to determine if the state of the button has changed: either pressed, going from HIGH to LOW, or released, from LOW to HIGH. it does nothing for release.

it reports the first button recognized as pressed (but the assumption is only one button is being pressed at a time). after being pressed, and potentially while still being pressed, a subsequent call to chkButtons() no longer reports a press.

a button press is a single event that needs to be processed when recognized

This is tricky given the structure of your code.

My assumption is that when you flip your toggle switch, you want to quickly send out an "alternate fact", actually two - press and release of a virtual pushbutton.

It looks like you'll need to do something along the lines suggested by @gcjr.

Here's changing pin 7 to do like you want. Compiles, but not tested. My changes/additions will stand out, they in the middle there.



dataForController_t getControllerData(void){
  // Set up a place for our controller data
  //  Use the getBlankDataForController() function, since
  //  just declaring a fresh dataForController_t tends
  //  to get you one filled with junk from other, random
  //  values that were in those memory locations before
  dataForController_t controllerData = getBlankDataForController();
  // Since our buttons are all held high and
  //  pulled low when pressed, we use the "!"
  //  operator to invert the readings from the pins
  controllerData.triangleOn = !digitalRead(2);
  controllerData.circleOn = !digitalRead(3);
  controllerData.squareOn = !digitalRead(4);
  controllerData.crossOn = !digitalRead(5);
  controllerData.l3On = digitalRead(6);        //spst switch
//  controllerData.r3On = digitalRead(7);           //spst switch
  controllerData.dpadLeftOn = !digitalRead(8);
  controllerData.dpadRightOn = !digitalRead(9);
  controllerData.l1On = !digitalRead(10);
  controllerData.r1On = !digitalRead(11);
  controllerData.l2On = !digitalRead(12);
  controllerData.r2On = digitalRead(13);        //spst switch

// change pin 7 from toggle to momentary-like behaviour

  static byte needRelease = false;
  static byte previousSwitch7 = false;

  if (needRelease) {
    controllerData.r3On = false;					// automatically "unpress" the button
    needRelease = false;
  }
  else {
    byte currentSwitch7 = digitalRead(7);           //spst switch

    if (currentSwitch7 != previousSwitch7) {		// did he toggle?
      
      controllerData.r3On = true;					// so "press" the button
      needRelease = true;							// so next time "unpress" the button.

      previousSwitch7 = currentSwitch7;				// so we can tracjk changes
    }
  }

  // Set the analog sticks
  //  Since analogRead(pin) returns a 10 bit value,
  //  we need to perform a bit shift operation to
  //  lose the 2 least significant bits and get an
  //  8 bit number that we can use  
  controllerData.leftStickX = analogRead(A0) >> 2;
  controllerData.leftStickY = analogRead(A1) >> 2;
  controllerData.rightStickX = analogRead(A2) >> 2;
  // And return the data!
  return controllerData;
}

This assumes you are calling getControllerData() fairly often, but not so often that you will be catching any contact bounce the toggle switch might have.

HTH

a7

My assumption is that when you flip your toggle switch, you want to quickly send out an "alternate fact", actually two - press and release of a virtual pushbutton.

Yes! This is exactly what I'm trying to do!

But, unfortunately, the code did not work as expected. The toggle switch did not pick up at all... Not quite sure why it didn't work :/. But you were right, did it did compile without errors or warnings.

Edit: Changing the controllerData false/true to 0/1 did no effect either...

I’ll take a harder look at my stab L8R. Not at my work station.

For right now, how exactly have you wired the switch, is it on 7, and maybe you should use INPUT_PULLUP if you haven’t used a pull up resistor externally.

And you changed to whatever or are checking in on “controllerData.r3On”.

You cou,d hand draw at least a partial schematic showing the kind of switch and how you’ve hooked it up.

Also I assume that switch once did do something albeit not what you want ed?

One more thing (Columbo!), how fast are you in fact looping in loop? It is possible I got it right but the two “facts” are being delivered so fast that whomever is receiving them discards it as a glitch... I have a few ideas for how to handle that if.

a7

OK, my logic seems fine, so it might be other issues as I wondered about previously.

Here's a ruthlessly hacked version of you sketch. I did not alter UnoJoy.h.

Look for my Serial.print statements.

For me here, I see


           virtual pushbutton UP...

           and DOWN.

when I close the switch and again when I open the switch. I'm using a SPST switch on pin 7, changed your setup to use INPUT_PULLUP and just skipped the call to whomever is to receive that data package.
#include "UnoJoy.h"

void setup(){
// elsewhere  Serial.begin(38400); // <-- must be

  setupPins();

  setupUnoJoy();

  Serial.println("OP's code stripped for logic test\n");

}

void loop(){
  // Always be getting fresh data
  dataForController_t controllerData = getControllerData();

// forget about sending the data along, just print it to see the toggle
//  setControllerData(controllerData);

// keep an eye on that variable - use 20 in the delay below if
// you comment these print lines:
  Serial.print("controllerData.r3On = ");
  Serial.println(controllerData.r3On ? "ON" : "OFF");

  delay(200); // just slow this down for a logic check
}

dataForController_t getControllerData(void){
  // Set up a place for our controller data

  dataForController_t controllerData = getBlankDataForController();

  //  Use the getBlankDataForController() function, since
  //  just declaring a fresh dataForController_t tends
  //  to get you one filled with junk from other, random
  //  values that were in those memory locations before

  // Since our buttons are all held high and
  //  pulled low when pressed, we use the "!"
  //  operator to invert the readings from the pins
  controllerData.triangleOn = !digitalRead(2);
  controllerData.circleOn = !digitalRead(3);
  controllerData.squareOn = !digitalRead(4);
  controllerData.crossOn = !digitalRead(5);
  controllerData.l3On = digitalRead(6);        //spst switch
//  controllerData.r3On = digitalRead(7);           //spst switch
  controllerData.dpadLeftOn = !digitalRead(8);
  controllerData.dpadRightOn = !digitalRead(9);
  controllerData.l1On = !digitalRead(10);
  controllerData.r1On = !digitalRead(11);
  controllerData.l2On = !digitalRead(12);
  controllerData.r2On = digitalRead(13);        //spst switch


  static byte needRelease = false;
  static byte previousSwitch7 = true;        // normally high switch!

  if (needRelease) {
    controllerData.r3On = false;					// "unpress" the button
    needRelease = false;
    Serial.println("\n           and DOWN.");
  }
  else {
    byte currentSwitch7 = digitalRead(7);           //spst switch

    if (currentSwitch7 != previousSwitch7) {		// press
      previousSwitch7 = currentSwitch7;				// so we can tracjk changes
      
      controllerData.r3On = true;					// "press" the button
      needRelease = true;							// so next time "unpress" the button.

      Serial.println("\n           virtual pushbutton UP...");
    }
  }

  // Set the analog sticks
  //  Since analogRead(pin) returns a 10 bit value,
  //  we need to perform a bit shift operation to
  //  lose the 2 least significant bits and get an
  //  8 bit number that we can use  
  controllerData.leftStickX = analogRead(A0) >> 2;
  controllerData.leftStickY = analogRead(A1) >> 2;
  controllerData.rightStickX = analogRead(A2) >> 2;
  // And return the data!
  return controllerData;
}

void setupPins(void){
  // Set all the digital pins as inputs
  // with the pull-up enabled, except for the 
  // two serial line pins
  for (int i = 2; i <= 12; i++){
    pinMode(i, INPUT_PULLUP);
    digitalWrite(i, HIGH);
  }
  pinMode(A4, INPUT);
  digitalWrite(A4, HIGH);
  pinMode(A5, INPUT);
  digitalWrite(A5, HIGH);
}

See if you can get this hacked version to function.

Here's the first few lines, I closed, then opened, the switch:

OP's code stripped for logic test

controllerData.r3On = OFF
controllerData.r3On = OFF
controllerData.r3On = OFF
controllerData.r3On = OFF
controllerData.r3On = OFF
controllerData.r3On = OFF

           virtual pushbutton UP...
controllerData.r3On = ON

           and DOWN.
controllerData.r3On = OFF
controllerData.r3On = OFF

           virtual pushbutton UP...
controllerData.r3On = ON

           and DOWN.
controllerData.r3On = OFF
controllerData.r3On = OFF
controllerData.r3On = OFF
controllerData.r3On = OFF

a7

Whoa, It works! On the serial monitor, every time I toggle it on it shows as on the off and vice versa. But, when I put the arduino to HID mode and open an external button testing software, it just presses random buttons and releases... Strange. GIF Preview: external-button-testing-software - Album on Imgur . This strange phenomenon happens on itself after like 1.5 seconds and happens anyways when I toggle the switch... Anyways regarding the serial monitor, it works!

For right now, how exactly have you wired the switch, is it on 7, and maybe you should use INPUT_PULLUP if you haven’t used a pull up resistor externally.

I have a 3 prong toggle switch. One goes to 5v, the second goes to ground, third goes to pin 7. Can confirm, it works.

And you changed to whatever or are checking in on “controllerData.r3On”.

I have seen multiple people do controllerData.r3On = 1/0; instead of controllerData.r3On = true/false;. But maybe your method also works :P.

Also I assume that switch once did do something albeit not what you want ed?

Yes, when switch on, it just stays on instead of monmentarily turning on and off like I wanted.

I have an amendment to the hack we can try on a hunch I have, but if you are saying you are getting janky behaviour even if you don't mess with the switch there must be some other problem, and it makes no sense to pursue my theory.

The hack may have inadvertently damaged other logic. There is nothing I can see that would account for anything time based (1.5 seconds) in particular.

Try placing

controllerData.r3On = flase;		// keep the button pressed

just before
 // And return the data!

to completely ignore that switch.

If everything else still works, we've got a mystery. If it doesn't, well, the mystery is yours, but my hack has been exonerated, so to speak.

The video you shared is not easy to follow, and it looks like it loops. If you do another, do a very deliberate test, and perhaps place it on youtube or somewhere it can be single-stepped with time markings, or tell me that imgur can do that and I'll figure out how.

What is your button testing HID diagnostic program called? Or is that your program?

I am on MacOS. If there is an HID diagnostic tool I will try it.

After breakfast and some life. :wink:

BTW - the switch wiring you have is fine. And 0/1, flase/true and LOW/HIGH are all more or less interchangeable, so besides finding switches and buttons operated exactly opposite to what one expected, this won't be how you fix any problems with using one over the other.

a7

Try placing... just before... to completely ignore that switch.

Ok, I did that, but no result...

If everything else still works, we've got a mystery. If it doesn't, well, the mystery is yours, but my hack has been exonerated, so to speak.

Well, nothing else works as it seems... I might hook some other input components (buttons, etc) to test it out but for now, really no result.

What is your button testing HID diagnostic program called? Or is that your program?
I am on MacOS. If there is an HID diagnostic tool I will try it.

The software I was using in the gif was the VKB Button Tester (also known as 'VKB_btntester'), which is, as it says a button tester. There are more of course. There are: Joystick Testers (by Pointy); VKB Joystick Tester (VKB_JoyTester); DIView and (only windows) joy.cpl (built-in). All of these are .exe meaning for windows but I'm sure with a simple search you can find yourself one for MacOS :).

The video you shared is not easy to follow, and it looks like it loops. If you do another, do a very deliberate test, and perhaps place it on youtube or somewhere it can be single-stepped with time markings, or tell me that imgur can do that and I'll figure out how.

Well, I'll try..

Don’t worry about the video, prolly not important.

I’ll look for a tester program or mebbe even fire up my Parallax Windoze. It adds a layer of potential problems with USB but I have been lucky enough.

When you say

Well, nothing else works as it seems... 

I want to be sure you mean you are experiencing problems with your project that have nothing to do whatsoever with the new switch-as-pushbutton stuff.

That would mean your original code had problems before you/we started messing with thing you’ve come here asking for help about.

If so, obvsly these other issues shou,d be found in your original code. I am confident that the hack can work, or we can learn why it just isn’t going to.

This isn’t a hugely complicated program, so.

a7

I did found a tool for the MacOS and as it happens I have a Trinket-based short-cut button box plugged in just now…

Actually running your code will be a bit more of a chore, so Imma drop it for the moment until we on the same page as far as what is and isn't working yet.

a7

I want to be sure you mean you are experiencing problems with your project that have nothing to do whatsoever with the new switch-as-pushbutton stuff.

I am sure that it's to do with the software side of things.

That would mean your original code had problems before you/we started messing with thing you’ve come here asking for help about.

Nope, the original code works great actually! Except for the part where I have to toggle it twice.

Edit: also I just rewired the switch to pin 9 for easier access, so that would be amazing if you can moving it to 9. cheers!

(btw sorry for the late reply, i had school work...)

If you did the thing with pin 7 just before the return statement, it should have restored all the original functionality (except, obvsly, whatever pin 7 did or didn't do).

So that it is more broken now is… impossible.

Please post one current full *.ino that has my hack AND the

controllerData.r3On = flase;		// keep the button pressed

which should remove it from consideration.

I assume we all just leaving the *.h file as is, so I'll use the one I got from the top post.

TBH it sounds like you slipped up somewhere, there is no way my stuff should cause anything unrelated to pin 7 to suddenly stop working.

So that's please post What you are testing now.

If you are 100 percent certain that your code in the very first post works fine (except of course the thing we are trying to add), say so, again.

If you are not sure, post also the code you have that works fine but has not been modified by me.

Sry if I sound quite certain about this, I am not. It is just a complete mystery, illogical Mr. Spock might say and typically there turns up to be a good reason, a solid explanation.

Just now it does not seem like I can run the sketch in the true USB HID circumstances. The tool I found is not instantly clear on what it does and how to work with it. Not unwilling to try, but not next.

Next is trying to see why the unhacking of my hack doesn't land you back at square zero as it should.

Don't worry about time away, there is life outside of the forum, even for me, so.

a7

1 Like

Heres the current .ino file:

//alto777 edit

//note: i changed pin 7 stuff to pin 9


#include "UnoJoy.h"

void setup(){
// elsewhere  Serial.begin(38400); // <-- must be

  setupPins();

  setupUnoJoy();

  Serial.println("OP's code stripped for logic test\n");

}

void loop(){
  // Always be getting fresh data
  dataForController_t controllerData = getControllerData();

// forget about sending the data along, just print it to see the toggle
//  setControllerData(controllerData);

// keep an eye on that variable - use 20 in the delay below if
// you comment these print lines:
  Serial.print("controllerData.dpadRightOn = ");
  Serial.println(controllerData.dpadRightOn ? "ON" : "OFF");

  delay(200); // just slow this down for a logic check
}

dataForController_t getControllerData(void){
  // Set up a place for our controller data

  dataForController_t controllerData = getBlankDataForController();

  //  Use the getBlankDataForController() function, since
  //  just declaring a fresh dataForController_t tends
  //  to get you one filled with junk from other, random
  //  values that were in those memory locations before

  // Since our buttons are all held high and
  //  pulled low when pressed, we use the "!"
  //  operator to invert the readings from the pins
  controllerData.triangleOn = !digitalRead(2);
  controllerData.circleOn = !digitalRead(3);
  controllerData.squareOn = !digitalRead(4);
  controllerData.crossOn = !digitalRead(5);
  controllerData.l3On = !digitalRead(6);
  controllerData.r3On = !digitalRead(7);
  controllerData.dpadLeftOn = !digitalRead(8);
//  controllerData.dpadRightOn = !digitalRead(9);  //the spst switch
  controllerData.l1On = !digitalRead(10);
  controllerData.r1On = !digitalRead(11);
  controllerData.l2On = !digitalRead(12);
  controllerData.r2On = !digitalRead(13);
    // Set the analog sticks
  //  Since analogRead(pin) returns a 10 bit value,
  //  we need to perform a bit shift operation to
  //  lose the 2 least significant bits and get an
  //  8 bit number that we can use  
  controllerData.leftStickX = analogRead(A0) >> 2;
  controllerData.leftStickY = analogRead(A1) >> 2;
  controllerData.rightStickX = analogRead(A2) >> 2;


  static byte needRelease = false;
  static byte previousSwitch9 = true;        // normally high switch!

  if (needRelease) {
    controllerData.dpadRightOn = false;          // "unpress" the button
    needRelease = false;
    Serial.println("\n           and DOWN.");
  }
  else {
    byte currentSwitch9 = digitalRead(9);           //spst switch

    if (currentSwitch9 != previousSwitch9) {    // press
      previousSwitch9 = currentSwitch9;       // so we can tracjk changes
      
      controllerData.dpadRightOn = true;         // "press" the button
      needRelease = true;             // so next time "unpress" the button.

      Serial.println("\n           virtual pushbutton UP...");
    }
  }

  controllerData.dpadRightOn = 0;       //just in case.
  controllerData.dpadRightOn = false;
  // And return the data!
  return controllerData;
}

void setupPins(void){
  // Set all the digital pins as inputs
  // with the pull-up enabled, except for the 
  // two serial line pins
  for (int i = 2; i <= 12; i++){
    pinMode(i, INPUT_PULLUP);
    digitalWrite(i, HIGH);
  }
  pinMode(A4, INPUT);
  digitalWrite(A4, HIGH);
  pinMode(A5, INPUT);
  digitalWrite(A5, HIGH);
}

/*
//original (works good)
  
#include "UnoJoy.h"

void setup(){
  setupPins();
  setupUnoJoy();
}

void setupPins(void){
  // Set all the digital pins as inputs
  // with the pull-up enabled, except for the 
  // two serial line pins
  for (int i = 2; i <= 12; i++){
    pinMode(i, INPUT);
    digitalWrite(i, HIGH);
  }
  pinMode(A4, INPUT);
  digitalWrite(A4, HIGH);
  pinMode(A5, INPUT);
  digitalWrite(A5, HIGH);
}

void loop(){
  // Always be getting fresh data
  dataForController_t controllerData = getControllerData();
  setControllerData(controllerData);

}

dataForController_t getControllerData(void){
  // Set up a place for our controller data
  //  Use the getBlankDataForController() function, since
  //  just declaring a fresh dataForController_t tends
  //  to get you one filled with junk from other, random
  //  values that were in those memory locations before
  dataForController_t controllerData = getBlankDataForController();
  // Since our buttons are all held high and
  //  pulled low when pressed, we use the "!"
  //  operator to invert the readings from the pins
  controllerData.triangleOn = !digitalRead(5);
  controllerData.circleOn = !digitalRead(4);
  controllerData.squareOn = !digitalRead(2);
  controllerData.crossOn = !digitalRead(3);
  controllerData.l3On = digitalRead(6);        //spst switch
  controllerData.r3On = digitalRead(7);           //spst switch
  controllerData.dpadLeftOn = !digitalRead(8);
  controllerData.dpadRightOn = !digitalRead(9);
  controllerData.l1On = !digitalRead(10);
  controllerData.r1On = !digitalRead(11);
  controllerData.l2On = !digitalRead(12);
  controllerData.r2On = digitalRead(13);        //spst switch

  // Set the analog sticks
  //  Since analogRead(pin) returns a 10 bit value,
  //  we need to perform a bit shift operation to
  //  lose the 2 least significant bits and get an
  //  8 bit number that we can use  
  controllerData.leftStickX = analogRead(A0) >> 2;
  controllerData.leftStickY = analogRead(A1) >> 2;
  controllerData.rightStickX = analogRead(A2) >> 2;
  // And return the data!
  return controllerData;
}
*/

Ok.

Since you concatenated the new and old versions and made a bunch of other changes in the code(s) and even put comments into that giant single window of code

I have spent a fair fraction of the time I have for this to come to the weak conclusion that:

  1. there is nothing wrong with my hack
  2. there is nothing about my hack that should break anything else
  3. my way of turning off the hack should, logically, remove it just as if you had deleted all the lines it consists in

I am weak in my conclusion because of all the editing you made me do to be ale to compare old and new… I tend to screw up when I am editing.

In the future place code tags around EACH *.ino by itself if multiple *.inos are under the microscope.

Put any comments about them in the post text NOT in the program text.

Don't make cosmetic changes or move lines around. Leave me the least possibility of introducing my own errors! I am good at introducing errors!

Srsly, we looking for a stray semicolon-like thing now. Please do not make it harder.

Having said that, I'm tapped out. I can't explain your experiences. I will look more later, but @boredforlifetime and @alto777 need other eyes on this, a fresh look so to speak.

Say yes or no: The original code works well. If you quick flip your toggle switch up and down, you get a behaviour that you wish would happen when you flip it up, and again when you flip it down.

I think the answer is "yes". If the answer is yes, I am fresh out of ideas as my hack, as far as I am able to determine, does exactly fix that up.

a7