Can USB Mode be joystick only? showing up as multiple devices.

Status
Not open for further replies.

cegan09

New member
I'm using a teensy LC as a controller input with a raspberry Pi4 and retropie. I have two analog sticks and a slew of regular buttons. Right now I'm just picking usb type: keyboard+mouse+joystick, however the Pi sees it as several devices and in turn retropie thinks there are two gamepads. All my buttons work, but the analog sticks do not. When plugged into a windows 10 machine everything works fine, analog sticks respond along with buttons.

I can't find a solution, I have looked. I'm curious if there is a way to set the USB mode to joystick only instead of the multiple devices? Or if that is even related.

teensyduino 1.53 installed, if that matters.

The code is just standard bounce code for buttons and joystick commands. The loop is running Joystick.X(analogRead(6)); 4 times on the 4 axis, and then there are rising and falling edge commands to deal with sending buttons. Full code at the end.

If I run cat /proc/bus/input/devices I get the following output

Code:
pi@retropie:~ $ cat /proc/bus/input/devices
I: Bus=0003 Vendor=16c0 Product=0482 Version=0111
N: Name="Teensyduino Keyboard/Mouse/Joystick"
P: Phys=usb-0000:01:00.0-1.4/input0
S: Sysfs=/devices/platform/scb/fd500000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0/usb1/1-1/1-1.4/1-1.4:1.0/0003:16C0:0482.0001/input/input0
U: Uniq=8855790
H: Handlers=sysrq kbd leds event0
B: PROP=0
B: EV=120013
B: KEY=7 ff800000 7ff e0b2ffdf 1cfffff ffffffff fffffffe
B: MSC=10
B: LED=1f

I: Bus=0003 Vendor=16c0 Product=0482 Version=0111
N: Name="Teensyduino Keyboard/Mouse/Joystick Mouse"
P: Phys=usb-0000:01:00.0-1.4/input1
S: Sysfs=/devices/platform/scb/fd500000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0/usb1/1-1/1-1.4/1-1.4:1.1/0003:16C0:0482.0002/input/input1
U: Uniq=8855790
H: Handlers=mouse0 event1 js0
B: PROP=0
B: EV=1f
B: KEY=ff0000 0 0 0 0 0 0 0 0
B: REL=1943
B: ABS=3
B: MSC=10

I: Bus=0003 Vendor=16c0 Product=0482 Version=0111
N: Name="Teensyduino Keyboard/Mouse/Joystick"
P: Phys=usb-0000:01:00.0-1.4/input3
S: Sysfs=/devices/platform/scb/fd500000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0/usb1/1-1/1-1.4/1-1.4:1.3/0003:16C0:0482.0004/input/input2
U: Uniq=8855790
H: Handlers=event2 js1
B: PROP=0
B: EV=1b
B: KEY=ffff 0 0 0 0 0 0 0 0 0 0 0 0 ffff 0 0 0 0 0 0 0 0 0
B: ABS=30067
B: MSC=10

I: Bus=0003 Vendor=16c0 Product=0482 Version=0111
N: Name="Teensyduino Keyboard/Mouse/Joystick"
P: Phys=usb-0000:01:00.0-1.4/input4
S: Sysfs=/devices/platform/scb/fd500000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0/usb1/1-1/1-1.4/1-1.4:1.4/0003:16C0:0482.0005/input/input3
U: Uniq=8855790
H: Handlers=kbd event3 js2
B: PROP=0
B: EV=1f
B: KEY=300ff 0 0 0 0 4c3ffff 17aff32d bfd44456 0 c000000 1 130ffb 8b17c000 677bfa d951dfed 9ed680 4400 0 10000002
B: REL=1040
B: ABS=101 101ff
B: MSC=10

Quite lost at this point, any help making this show up as a single device would be great.



Full code on the teensy. You can ignore the power stuff, I'm also using the teensy to watch a GPIO pin on the pi to know when it shut down and then the other pin is controlling my power circuit to let it kill power to the whole device once the pi is shutdown.

Code:
#include <Bounce.h>


const int pwrcheck = 24;
const int pwroff = 25;
int boot = 0;
const int waittime = 60000;
int timenow = 0;
int pwrread = 1;
const int checktime = 5000;
int checknow = 0;


// Create Bounce objects for each button.  The Bounce object
// automatically deals with contact chatter or "bounce", and
// it makes detecting changes very simple.

Bounce button2 = Bounce(2, 10);  // which is appropriate for
Bounce button3 = Bounce(3, 10);  // most mechanical pushbuttons
Bounce button4 = Bounce(4, 10);
Bounce button5 = Bounce(5, 10);
Bounce button6 = Bounce(6, 10);
Bounce button7 = Bounce(7, 10);
Bounce button8 = Bounce(8, 10);
Bounce button9 = Bounce(9, 10);
Bounce button10 = Bounce(10, 10);
Bounce button11 = Bounce(11, 10);  // 10 = 10 ms debounce time
Bounce button12 = Bounce(12, 10);  // which is appropriate for
Bounce button13 = Bounce(13, 10);  // most mechanical pushbuttons
Bounce button14 = Bounce(14, 10);
Bounce button15 = Bounce(15, 10);
Bounce button16 = Bounce(16, 10);
Bounce button17 = Bounce(17, 10);
Bounce button18 = Bounce(18, 10);
Bounce button19 = Bounce(19, 10);


void setup() {
  pinMode(2, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);
  pinMode(4, INPUT_PULLUP);
  pinMode(5, INPUT_PULLUP);
  pinMode(6, INPUT_PULLUP);
  pinMode(7, INPUT_PULLUP);
  pinMode(8, INPUT_PULLUP);
  pinMode(9, INPUT_PULLUP);
  pinMode(10, INPUT_PULLUP);
  pinMode(11, INPUT_PULLUP);
  pinMode(12, INPUT_PULLUP);
  pinMode(13, INPUT_PULLUP);
  pinMode(14, INPUT_PULLUP);
  pinMode(15, INPUT_PULLUP);
  pinMode(16, INPUT_PULLUP);
  pinMode(17, INPUT_PULLUP);
  pinMode(18, INPUT_PULLUP);
  pinMode(19, INPUT_PULLUP);

  pinMode(pwrcheck, INPUT);
  pinMode(pwroff, OUTPUT);
  digitalWrite(pwroff, LOW);
  timenow = millis();

}

void loop() {
  // read analog inputs and set X-Y position
  Joystick.X(analogRead(6));
  Joystick.Y(analogRead(7));
  Joystick.Z(analogRead(8));
  Joystick.Zrotate(analogRead(9));

  // Update all the buttons.  There should not be any long
  // delays in loop(), so this runs repetitively at a rate
  // faster than the buttons could be pressed and released.
  button2.update();
  button3.update();
  button4.update();
  button5.update();
  button6.update();
  button7.update();
  button8.update();
  button9.update();
  button10.update();
  button11.update();
  button12.update();
  button13.update();
  button14.update();
  button15.update();
  button16.update();
  button17.update();
  button18.update();
  button19.update();

  // Check each button for "falling" edge.
  // Update the Joystick buttons only upon changes.
  // falling = high (not pressed - voltage from pullup resistor)
  //           to low (pressed - button connects pin to ground)
  if (button2.fallingEdge()) {
    Joystick.button(3, 1);
  }
  if (button3.fallingEdge()) {
    Joystick.button(4, 1);
  }
  if (button4.fallingEdge()) {
    Joystick.button(5, 1);
  }
  if (button5.fallingEdge()) {
    Joystick.button(6, 1);
  }
  if (button6.fallingEdge()) {
    Joystick.button(7, 1);
  }
  if (button7.fallingEdge()) {
    Joystick.button(8, 1);
  }
  if (button8.fallingEdge()) {
    Joystick.button(9, 1);
  }
  if (button9.fallingEdge()) {
    Joystick.button(10, 1);
  }
  if (button10.fallingEdge()) {
    Joystick.button(11, 1);
  }
  if (button11.fallingEdge()) {
    Joystick.button(12, 1);
  }
  if (button12.fallingEdge()) {
    Joystick.button(13, 1);
  }
  if (button13.fallingEdge()) {
    Joystick.button(14, 1);
  }
  if (button14.fallingEdge()) {
    Joystick.button(15, 1);
  }
  if (button15.fallingEdge()) {
    Joystick.button(16, 1);
  }
  if (button16.fallingEdge()) {
    Joystick.button(17, 1);
  }
  if (button17.fallingEdge()) {
    Joystick.button(18, 1);
  }
  if (button18.fallingEdge()) {
    Joystick.button(19, 1);
  }
  if (button19.fallingEdge()) {
    Joystick.button(20, 1);
  }
  // Check each button for "rising" edge
  // Update the Joystick buttons only upon changes.
  // rising = low (pressed - button connects pin to ground)
  //          to high (not pressed - voltage from pullup resistor)
  if (button2.risingEdge()) {
    Joystick.button(3, 0);
  }
  if (button3.risingEdge()) {
    Joystick.button(4, 0);
  }
  if (button4.risingEdge()) {
    Joystick.button(5, 0);
  }
  if (button5.risingEdge()) {
    Joystick.button(6, 0);
  }
  if (button6.risingEdge()) {
    Joystick.button(7, 0);
  }
  if (button7.risingEdge()) {
    Joystick.button(8, 0);
  }
  if (button8.risingEdge()) {
    Joystick.button(9, 0);
  }
  if (button9.risingEdge()) {
    Joystick.button(10, 0);
  }
  if (button10.risingEdge()) {
    Joystick.button(11, 0);
  }
  if (button11.risingEdge()) {
    Joystick.button(12, 0);
  }
  if (button12.risingEdge()) {
    Joystick.button(13, 0);
  }
  if (button13.risingEdge()) {
    Joystick.button(14, 0);
  }
  if (button14.risingEdge()) {
    Joystick.button(15, 0);
  }
  if (button15.risingEdge()) {
    Joystick.button(16, 0);
  }
  if (button16.risingEdge()) {
    Joystick.button(17, 0);
  }
  if (button17.risingEdge()) {
    Joystick.button(18, 0);
  }
  if (button18.risingEdge()) {
    Joystick.button(19, 0);
  }
  if (button19.risingEdge()) {
    Joystick.button(20, 0);
  }  
  if (millis()- timenow > waittime && boot == 0){
  boot = 1;
  checknow = millis();
}

if (boot == 1 && millis() - checknow > checktime){
  pwrread = digitalRead(pwrcheck);
  if (pwrread == 0){
    digitalWrite(pwroff, HIGH);
  }
  checknow = millis();
}
}
 
Hello, I meet almost the same issue. I have two detected gamepad controllers when I plug my Teensy Lc. Joystick and buttons work in the RetroPie menu but not in the games. I tried all different Joystick codes I found on internet, I reinstall RetroPie from Raspian' lite, I tried to change the input order gamepads in RetroArch, and emulators, but nothing changed. Still this issue. However, my TEENSY works well on win10. Thanks for helps too.
 
You need to edit usb_desc.h. See the comments in that file for details. Pay attention to the folder name, as 2 copies exist for Teensy 3 vs 4.
 
You need to edit usb_desc.h. See the comments in that file for details. Pay attention to the folder name, as 2 copies exist for Teensy 3 vs 4.

I shall go forth and read, honestly had not even heard of that file before, thank you.

Stupid question, does the LC count as 3 or 4?

Edit: I think the answer is 3, but I'll leave the question in case I'm wrong and someone wants to correct me.
 
Last edited:
New dumb question. Finally got to modifying the usb_desc.h file. Modified the one in C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy3 (made a backup of the original before I touched it)

I made a new entry at the end of the list, however it's not showing in the USB type menu in the arduino IDE. I closed the IDE while changing the file, have restarted the IDE a bunch of times, have changed boards a bunch of times to see if that forces an update, but the new type does not show. I did change the product ID so it was not a duplicate of any others in the list.

I'm sure this is a case of "i have no idea what I'm doing" and I missed something that had to also be updated, or I didn't define my new type correctly. Hoping someone can just point out where I went wrong.

This is the new type I added to the file
Code:
  #elif defined(USB_STICKONLY)
  #define VENDOR_ID		0x16C0
  #define PRODUCT_ID		0x048D
  #define MANUFACTURER_NAME	{'T','e','e','n','s','y','d','u','i','n','o'}
  #define MANUFACTURER_NAME_LEN	11
  #define PRODUCT_NAME		{'J','o','y','s','t','i','c','k'}
  #define PRODUCT_NAME_LEN	8
  #define EP0_SIZE		64
  #define NUM_ENDPOINTS         3
  #define NUM_USB_BUFFERS	24
  #define NUM_INTERFACE		2
  #define SEREMU_INTERFACE      1	// Serial emulation
  #define SEREMU_TX_ENDPOINT    1
  #define SEREMU_TX_SIZE        64
  #define SEREMU_TX_INTERVAL    1
  #define SEREMU_RX_ENDPOINT    2
  #define SEREMU_RX_SIZE        32
  #define SEREMU_RX_INTERVAL    2
  #define JOYSTICK_INTERFACE    0	// Joystick
  #define JOYSTICK_ENDPOINT     3
  #define JOYSTICK_SIZE         12	//  12 = normal, 64 = extreme joystick
  #define JOYSTICK_INTERVAL     2
  #define ENDPOINT1_CONFIG	ENDPOINT_TRANSMIT_ONLY
  #define ENDPOINT2_CONFIG	ENDPOINT_RECEIVE_ONLY
  #define ENDPOINT3_CONFIG	ENDPOINT_TRANSMIT_ONLY
 
There are several entries in usb_desc.h that are not in the GUI. I assume there is another place to modify the GUI list.

I'm in the middle of the same problem as you. I can confirm that two TeensyLC configured as "keyboard/mouse/joystick" show up as 4 inputs, with input 0 and input 2 being the real joysticks. (player 1 and player 3 work in 4 player games).

Trying one TeensyLC on desktop Ubuntu, there are indeed two joysticks. A 7 axis, 32 button js1, which works as expected. And, a 12 axis, 71 button js2, which does not. Interestingly, the 71 button joystick is assigned a kbd handler AND a js* handler, just like on cegan09's system. js0 is marked as the mouse, but also shows up in jstest-gtk as a joystick.

There seems to be some unique bug that allows Teensy to work in Windows, but creates duplicates in Linux. Out of curiosity, how many buttons should the Teensy keyboard have? If I take 12 axes as 24 buttons, and add the 71 other buttons, I get 95 buttons, which is certainly in keyboard range.
 
There are several entries in usb_desc.h that are not in the GUI. I assume there is another place to modify the GUI list.

I think, I can answer that: Look at the file avr/boards.txt. Find your teensy there, and add the entries you need. I think, the file is pretty self-explanatory.

Additionally you might have to change some other code files, as you added your own entry to usb_desc.h. I found the files in question by searching for the #define that contains what I need (joystick in your case), so e.g. USB_SERIAL_HID. You might find something like

Code:
#if defined(USB_SERIAL) || defined(USB_SERIAL_HID)

(Just an example - not what you actually need). If you do find something, you might have to add your USB_STICKONLY there to include the relevant code. However, I think, for a joystick this might not be required. It's a bit of trial and error though. Just don't give up :)
 
Last edited:
Status
Not open for further replies.
Back
Top