PDA

View Full Version : (n00b) Switch ports on KVM



myk3
05-13-2013, 07:47 PM
I have an IOGear KVM and I am attempting to use a wireless keyboard and mouse through it. Everything works fine through the mouse port, but not through the keyboard port. I found a video online using a teensy to control this device, the same kvm as mine. I have a teensy from an old project that I never got around to doing and was wondering if I can control what happens when the button is pressed on the teensy. I only need to send the "scroll lock + scroll lock" button presses in order to switch the kvm.


I have no clue how to go about doing this and would appreciate anyone who can send me to the documentation needed to program this little guy.

The video I saw was here

https://www.youtube.com/watch?featur...&v=dgH07NEp1hg

PaulStoffregen
05-13-2013, 08:52 PM
Did he publish the code used in that video?

If not, you might ask the author if they'll give you the code. It's probably very simple, but having a copy of the already-tested code will make this much simpler.

myk3
05-13-2013, 08:54 PM
Did he publish the code used in that video?

If not, you might ask the author if they'll give you the code. It's probably very simple, but having a copy of the already-tested code will make this much simpler.

No he didn't.. I sent him an email though, to see if he would share it..

PaulStoffregen
05-13-2013, 09:04 PM
If he doesn't release the code, you'll probably need to modify the Buttons example.

You can download Arduino and install Teensyduino, then open it within Arduino from File > Examples > Teensy > USB_Keyboard > Buttons. It's written for 10 buttons, but you can just connect 1 and not use the other 9. You'll probably just have to change the stuff the Keyboard.print() lines to send the right commands. This code is all free downloads, so you can take a look anytime and see if you feel comfortable with how the code works?

myk3
05-13-2013, 09:29 PM
If he doesn't release the code, you'll probably need to modify the Buttons example.

You can download Arduino and install Teensyduino, then open it within Arduino from File > Examples > Teensy > USB_Keyboard > Buttons. It's written for 10 buttons, but you can just connect 1 and not use the other 9. You'll probably just have to change the stuff the Keyboard.print() lines to send the right commands. This code is all free downloads, so you can take a look anytime and see if you feel comfortable with how the code works?

He just sent me a link to the code.


// Sketch for Easy Button
// 2012 Dave Jacoby <jacoby.david@gmail.com>

// This program for the Teensy takes a digital input on 10 (c7)
// and turns it into two Scroll Locks (ASCII 145), so I can use
// it as

// Inspired by http://rasterweb.net/raster/2011/05/09/the-button/
// Not far divergent from sample code, with <10 lines of actual code
// so copyright? What copyright?

// ========= ========= ========= =========
void setup() {
// make pin 10 an input and turn on the
// pullup resistor so it goes high unless
// connected to ground:
pinMode(10, INPUT_PULLUP);
delay(2000);
Keyboard.begin() ;
}

// ========= ========= ========= =========
void loop() {
if ( digitalRead( 10 ) == LOW ) {
//Keyboard.write( 72 );
//delay(300);
//Keyboard.write( 73 );
//delay(300);
Keyboard.press( KEY_SCROLL_LOCK ) ;
Keyboard.releaseAll() ;
delay(300);
Keyboard.press( KEY_SCROLL_LOCK ) ;
Keyboard.releaseAll() ;
delay(600); // Delay of 6/10 second to keep from repeating.
}
delay(10);
}

PaulStoffregen
05-13-2013, 10:00 PM
Great. Just program that onto a Teensy 2.0 and it should work.

Get the software here:

http://www.pjrc.com/teensy/td_download.html

This tutorial shows more detail on how to use it:

http://www.pjrc.com/teensy/tutorial.html

Practice with getting the LED to blink at different speeds. Then when you are comfortable with how to program the board, program it with his code.

Before reassembling the Easy Button, or even before soldering wires, test to make sure it works be touching a wire between GND and pin 10.

myk3
05-14-2013, 03:50 PM
Great. Just program that onto a Teensy 2.0 and it should work.

Get the software here:

http://www.pjrc.com/teensy/td_download.html

This tutorial shows more detail on how to use it:

http://www.pjrc.com/teensy/tutorial.html

Practice with getting the LED to blink at different speeds. Then when you are comfortable with how to program the board, program it with his code.

Before reassembling the Easy Button, or even before soldering wires, test to make sure it works be touching a wire between GND and pin 10.

Could i use the button on the teensy, instead of a easy button?

myk3
05-14-2013, 04:32 PM
Great. Just program that onto a Teensy 2.0 and it should work.

Get the software here:

http://www.pjrc.com/teensy/td_download.html

This tutorial shows more detail on how to use it:

http://www.pjrc.com/teensy/tutorial.html

Practice with getting the LED to blink at different speeds. Then when you are comfortable with how to program the board, program it with his code.

Before reassembling the Easy Button, or even before soldering wires, test to make sure it works be touching a wire between GND and pin 10.

I downloaded the blink_slow and blink_fast, programmed it with the teensy loader. I then installed the arduino compiler and programmed the teensy using the code provided.. I had to switch it over to Keyboard, else the ide kept failing.. I am testing it by just bridging pin 10 and +5v, but nothing is happening.. Is there something else I should be doing?

myk3
05-14-2013, 06:57 PM
I downloaded the blink_slow and blink_fast, programmed it with the teensy loader. I then installed the arduino compiler and programmed the teensy using the code provided.. I had to switch it over to Keyboard, else the ide kept failing.. I am testing it by just bridging pin 10 and +5v, but nothing is happening.. Is there something else I should be doing?

Well this is starting to get really fun..

I was able to get the scroll lock buttons to press.. i used the on screen keyboard in order to test it, but the KVM isn't switching the inputs..

I have tried compiling as a Keyboard + Mouse + Joystick and Serial + Keboard...

myk3
05-14-2013, 07:44 PM
Here is the code I am currently using.. The KVM does not recognize the SL + SL keystrokes. I added the LED lightup so I could verify it was launching the loop when on the KVM, and it is. The KVM is jsut not recognizing the SL+SL


int ledPin = 11;

void setup(){
pinMode(10, INPUT_PULLUP);
delay(2000);
Keyboard.begin();
}

void loop(){
if (digitalRead(10) == LOW)
{
digitalWrite(ledPin, HIGH);
Keyboard.press( KEY_SCROLL_LOCK ) ;
Keyboard.releaseAll() ;
delay(500);
Keyboard.press( KEY_SCROLL_LOCK ) ;
Keyboard.releaseAll() ;
digitalWrite(ledPin, LOW);
}
delay(10);
}

EDIT: It switches the ports on my other KVM fine.. :(

Dawnmist
05-15-2013, 12:43 AM
Are both KVM switches the same brand/model? If not, can you double-press scroll-lock on a normal keyboard connected to the one that isn't working (to test whether double-scroll lock is actually the right key combination for that kvm). I've seen a few kvms that used a different key sequence to switch machines, so I'm just checking that the issue isn't due to sending the wrong key sequence on the non-working kvm.

Otherwise, I notice that you have modified the timing delays from the original code. The sampl code you posted would check for whether the button had been pressed every 10 ms (0.01 seconds). If it was pressed, it would then send 2 keypresses 300ms (0.3s) apart, then give you an additional 600ms (0.6 seconds) to let go of the button before starting the "is the button now pressed" checks again.

In your modified code, you have the same 10ms check interval, but you have increased the delay between the two keypresses to 500ms (0.5 seconds), and removed entirely the buffer time afterwards to let go of the button. The potential issues with this are that 0.5 seconds may be "too long" between keypresses for that kvm to recognise the pair as a "double-click", so that kvm may not then be joining the pair of keypresses together. The second issue is that if you take longer than 510ms to press-and-release your button (including the time it takes for the contacts inside the button to stop bouncing), your sequence of keystrokes will be sent twice. If the two kvms are the same, I'd be surprised if the delay changes would work on one and not the other though.

You can again test for double-click speed with a real keyboard plugged into the kvm - how much delay does it let you have before the real keyboard's double-press doesn't trigger the kvm into switching?

You should also be setting the pinMode for the led pin in setup, since you are using it:
pinMode(ledPin, OUTPUT);

myk3
05-15-2013, 01:08 AM
Are both KVM switches the same brand/model? If not, can you double-press scroll-lock on a normal keyboard connected to the one that isn't working (to test whether double-scroll lock is actually the right key combination for that kvm). I've seen a few kvms that used a different key sequence to switch machines, so I'm just checking that the issue isn't due to sending the wrong key sequence on the non-working kvm.

Otherwise, I notice that you have modified the timing delays from the original code. The sampl code you posted would check for whether the button had been pressed every 10 ms (0.01 seconds). If it was pressed, it would then send 2 keypresses 300ms (0.3s) apart, then give you an additional 600ms (0.6 seconds) to let go of the button before starting the "is the button now pressed" checks again.

In your modified code, you have the same 10ms check interval, but you have increased the delay between the two keypresses to 500ms (0.5 seconds), and removed entirely the buffer time afterwards to let go of the button. The potential issues with this are that 0.5 seconds may be "too long" between keypresses for that kvm to recognise the pair as a "double-click", so that kvm may not then be joining the pair of keypresses together. The second issue is that if you take longer than 510ms to press-and-release your button (including the time it takes for the contacts inside the button to stop bouncing), your sequence of keystrokes will be sent twice. If the two kvms are the same, I'd be surprised if the delay changes would work on one and not the other though.

You can again test for double-click speed with a real keyboard plugged into the kvm - how much delay does it let you have before the real keyboard's double-press doesn't trigger the kvm into switching?

You should also be setting the pinMode for the led pin in setup, since you are using it:
pinMode(ledPin, OUTPUT);

The KVMs are not the same model / brand. I know the SL + SL key combo is the correct keystrokes since I have been using this KVM with a wired keyboard and mouse. I just switched to a wireless KB + Mouse combo, which only uses one USB dongle. This works great on the mouse side and not on the KB side; however, I can no longer change the port. I currently have a wired KB plugged into the KB side and just reaching over it and changing the input. This keyboard is tucked out of the way, so it doesn't look bad just want something different.

I tried the code I posted first, once I figured out how to compile and send the code to the teensy. After It didn't work I started messing with timing to see if that was the issue. I also don't have any buttons currently connected I am just bridging the wires to start the loop. Is this ok?

Thanks for letting me know about the pinMode, I just started messing with this today and learning as I go.

Dawnmist
05-15-2013, 01:25 AM
The KVMs are not the same model / brand. I know the SL + SL key combo is the correct keystrokes since I have been using this KVM with a wired keyboard and mouse. I just switched to a wireless KB + Mouse combo, which only uses one USB dongle. This works great on the mouse side and not on the KB side; however, I can no longer change the port. I currently have a wired KB plugged into the KB side and just reaching over it and changing the input. This keyboard is tucked out of the way, so it doesn't look bad just want something different.

I tried the code I posted first, once I figured out how to compile and send the code to the teensy. After It didn't work I started messing with timing to see if that was the issue. I also don't have any buttons currently connected I am just bridging the wires to start the loop. Is this ok?

Thanks for letting me know about the pinMode, I just started messing with this today and learning as I go.

Ok, given that I'd be testing with a shorter timing between keypresses rather than longer timing. I know for example that in Java, the default time interval between mouse-clicks to be detected as a "double click" is only 200ms. While the kvm won't itself be running Java, it's quite possible that it's using a similarly short "double-press" time interval.

Maybe try something like 60ms to 150ms delay between the two keypress events (and a longer delay after the two, because with that timing you'll end up with double-sends otherwise).

Other dumb question - did this kvm originally take a usb keyboard, or a PS/2 keyboard? If the kvm originally used a PS/2 keyboard, it may not actually understand USB itself (just passing through whatever comes along the USB port instead of actually reading the keyboard presses). If that is the case, it wouldn't matter what you sent via the USB keyboard - the kvm wouldn't understand it at all. You could still potentially use the teensy, but it'd be a more complex project (I *think* you'd need to add a PS/2 connector as another output from the teensy and plug that into the PS/2 port on the KVM, then send the PS/2 scan-codes through that connector - but it's not something I've done before so I'm not sure where you'd start with that/how to wire it up/etc).

myk3
05-15-2013, 01:30 AM
Ok, given that I'd be testing with a shorter timing between keypresses rather than longer timing. I know for example that in Java, the default time interval between mouse-clicks to be detected as a "double click" is only 200ms. While the kvm won't itself be running Java, it's quite possible that it's using a similarly short "double-press" time interval.

Maybe try something like 60ms to 150ms delay between the two keypress events (and a longer delay after the two, because with that timing you'll end up with double-sends otherwise).

Other dumb question - did this kvm originally take a usb keyboard, or a PS/2 keyboard? If the kvm originally used a PS/2 keyboard, it may not actually understand USB itself (just passing through whatever comes along the USB port instead of actually reading the keyboard presses). If that is the case, it wouldn't matter what you sent via the USB keyboard - the kvm wouldn't understand it at all. You could still potentially use the teensy, but it'd be a more complex project (I *think* you'd need to add a PS/2 connector as another output from the teensy and plug that into the PS/2 port on the KVM, then send the PS/2 scan-codes through that connector - but it's not something I've done before so I'm not sure where you'd start with that/how to wire it up/etc).

Nope it is a USB KVM..

http://www.iogear.com/product/GCS632U/

The one that works is an older version of this one.. (actual version is a TK-409, which has since been discontinued)

http://www.trendnet.com/products/proddetail.asp?status=view&prod=230_TK-409K

Dawnmist
05-15-2013, 03:36 AM
Ok. I'm assuming you've connected the teensy to the Keyboard console port, with your wireless mouse/keyboard adaptor in the mouse console port (only the keyboard port on that kvm will respond to the switch-computers hotkeys).

I've had issues with key macros (which is essentially what you're using the Teensy to do) with some software in the past if there wasn't delays between the key pressed/key released events in the macro (software didn't recognise the keys were pressed at all, or joined the two presses together into one), and this kvm switch looks like it is pretty tempermental in what it actually recognises on the keyboard port (instead of being a "true" usb port, it does conversion of the USB information and then resends it as it's own usb-keyboard code - in part so that it can emulate keys that don't exist on the keyboard, etc). The Teensy does use the standard usb keyboard reports, so the kvm *should* be able to be read/interpret the teensy.

Try something like this, and let us know how it goes:

int ledPin = 11;

void setup(){
pinMode(10, INPUT_PULLUP);
pinMode(ledPin, OUTPUT);
delay(2000);
Keyboard.begin();
}

void loop(){
if (digitalRead(10) == LOW)
{
digitalWrite(ledPin, HIGH);
Keyboard.press( KEY_SCROLL_LOCK ) ;
delay(50); // give time to recognise key down
Keyboard.releaseAll() ;
delay(150); // give time to recognise key up, so the next keypress is treated as a second press
Keyboard.press( KEY_SCROLL_LOCK ) ;
delay(50);
Keyboard.releaseAll() ;
delay(350); // give time to let go of button/wire connection before rescanning - may need increasing if you get multiple sends per press
digitalWrite(ledPin, LOW);
}
delay(10);
}

Failing that, you could try toggling the setting for the kvm from scroll-lock+scroll-lock to ctrl+ctrl and modifying the code above to send CTRL key presses (replace the "Keyboard.press(KEY_SCROLL_LOCK);" with "Keyboard.set_modifier(MODIFIERKEY_CTRL); Keyboard.send_now();"). The FAQ on the iogear site (and the manual for the kvm) say how to toggle between using scroll lock or ctrl as the trigger: http://iogear.custhelp.com/app/answers/detail/a_id/2420/related/1/session/L2F2LzEvdGltZS8xMzY4NTg2NDQyL3NpZC9vKkVQVmNxbA%3D% 3D . You'd need to use the wired keyboard to change between using scroll lock or ctrl as the triggers (and it looks like it's a toggle - so if it doesn't work you can toggle it back to scroll lock).

myk3
05-15-2013, 03:42 AM
Ok. I'm assuming you've connected the teensy to the Keyboard console port, with your wireless mouse/keyboard adaptor in the mouse console port (only the keyboard port on that kvm will respond to the switch-computers hotkeys).

I've had issues with key macros (which is essentially what you're using the Teensy to do) with some software in the past if there wasn't delays between the key pressed/key released events in the macro (software didn't recognise the keys were pressed at all, or joined the two presses together into one), and this kvm switch looks like it is pretty tempermental in what it actually recognises on the keyboard port (instead of being a "true" usb port, it does conversion of the USB information and then resends it as it's own usb-keyboard code - in part so that it can emulate keys that don't exist on the keyboard, etc). The Teensy does use the standard usb keyboard reports, so the kvm *should* be able to be read/interpret the teensy.

Try something like this, and let us know how it goes:

int ledPin = 11;

void setup(){
pinMode(10, INPUT_PULLUP);
pinMode(ledPin, OUTPUT);
delay(2000);
Keyboard.begin();
}

void loop(){
if (digitalRead(10) == LOW)
{
digitalWrite(ledPin, HIGH);
Keyboard.press( KEY_SCROLL_LOCK ) ;
delay(50); // give time to recognise key down
Keyboard.releaseAll() ;
delay(150); // give time to recognise key up, so the next keypress is treated as a second press
Keyboard.press( KEY_SCROLL_LOCK ) ;
delay(50);
Keyboard.releaseAll() ;
delay(350); // give time to let go of button/wire connection before rescanning - may need increasing if you get multiple sends per press
digitalWrite(ledPin, LOW);
}
delay(10);
}

Failing that, you could try toggling the setting for the kvm from scroll-lock+scroll-lock to ctrl+ctrl and modifying the code above to send CTRL key presses (replace the "Keyboard.press(KEY_SCROLL_LOCK);" with "Keyboard.set_modifier(MODIFIERKEY_CTRL); Keyboard.send_now();"). The FAQ on the iogear site (and the manual for the kvm) say how to toggle between using scroll lock or ctrl as the trigger: http://iogear.custhelp.com/app/answers/detail/a_id/2420/related/1/session/L2F2LzEvdGltZS8xMzY4NTg2NDQyL3NpZC9vKkVQVmNxbA%3D% 3D . You'd need to use the wired keyboard to change between using scroll lock or ctrl as the triggers (and it looks like it's a toggle - so if it doesn't work you can toggle it back to scroll lock).

When i first started this adventure I was able to change the hotkey from SL to CTRL.. I changed it back since I had no use at the time.. I will test this tomorrow.. Thanks for the help..

myk3
05-15-2013, 01:20 PM
Well I still can't get any combination working. I tried the posted code, changing it to CTRL + CTRL (on the KVM and the code) and that didn't work. I tried the original code again, and it still isn't working..

I know this is probably a stupid question but I am compiling as "keyboard + Mouse + Joystick". I am also using Arduion version 1.0.3, since the teensy installer said my folder for 1.0.4 was not valid. Is this ok?

myk3
05-15-2013, 03:21 PM
Well I still can't get any combination working. I tried the posted code, changing it to CTRL + CTRL (on the KVM and the code) and that didn't work. I tried the original code again, and it still isn't working..

I know this is probably a stupid question but I am compiling as "keyboard + Mouse + Joystick". I am also using Arduion version 1.0.3, since the teensy installer said my folder for 1.0.4 was not valid. Is this ok?

the worst part is the trendnet switches fine, but for some odd reason when i have the dvi port used on my laptop it doesn't detect the VGA, only when using the trendnet, it works fine on the iogear

Dawnmist
05-16-2013, 03:48 AM
Keyboard/Mouse/Joystick or Serial/Keyboard/Mouse/Joystick should both work...if the KVM were doing the right thing (and I haven't screwed up something stupid in the code).

I'm running out of ideas for this :(. It's sounding a lot like the KVM isn't properly reading the keyboard data reports (despite them being the normal standard "bios-mode" USB keyboard report). Is it at least passing the data through to the currently-connected computer?

If you change the programming so that it sends a normal keypress (e.g. send KEY_A twice instead of sending KEY_SCROLL_LOCK twice), and then open a text document, does the computer type that letter twice into the document when you make the touch connection while the teensy is plugged into the keyboard port of the KVM? Does it type that letter twice when the teensy is plugged directly into one of the computer's usb ports (not through the kvm)? If they both type the double-a, then I'm at a total loss - it would mean (if I've read the manual/faqs for that kvm switch right) that the kvm understood the teensy usb keyboard presses well enough to emulate them but not to actually respond to them (wtf?). If the computer typed the a, but the kvm didn't, then the kvm is probably not recognising the teensy USB keyboard at all. If neither typed it, then there's a problem with the actual sending code so that the keypresses are not actually being sent.

If it's working through the computer but not through the kvm, the last thing I can think of to try is more difficult - it would be to change the teensy hardware-library code so that it *only* reported the Keyboard USB HID interface (in case it was the presence of the mouse/joystick interfaces that is causing the KVM's emulation to go wacky), and not the mouse/joystick/(Serial) interfaces. Paul is probably a *much* better person to describe how to cut that down properly - there's a lot of stuff in there, and if you get it wrong the computer won't recognise the teensy when you boot your code (though you can at least get it back into reprogram mode by holding down the reset button on the teensy while plugging it into the computer if that happens).

nox771
05-16-2013, 05:38 AM
Just my 2c here - if you are having trouble with an Iogear KVM not recognizing a composite device through its keyboard port, the problem is the Iogear, not your device.

I ran into this exact problem years ago on a 4-port Iogear KVM. I detailed my problems here: http://rewiredgear.net/deckmod5.html (about half way down). Composite device would work fine connected directly to computer, but not on the Iogear. The Iogear would not recognize anything except a simple keyboard.

My solution now, run virtual machines and ditch the KVM.

myk3
05-16-2013, 01:25 PM
Keyboard/Mouse/Joystick or Serial/Keyboard/Mouse/Joystick should both work...if the KVM were doing the right thing (and I haven't screwed up something stupid in the code).

I'm running out of ideas for this :(. It's sounding a lot like the KVM isn't properly reading the keyboard data reports (despite them being the normal standard "bios-mode" USB keyboard report). Is it at least passing the data through to the currently-connected computer?

If you change the programming so that it sends a normal keypress (e.g. send KEY_A twice instead of sending KEY_SCROLL_LOCK twice), and then open a text document, does the computer type that letter twice into the document when you make the touch connection while the teensy is plugged into the keyboard port of the KVM? Does it type that letter twice when the teensy is plugged directly into one of the computer's usb ports (not through the kvm)? If they both type the double-a, then I'm at a total loss - it would mean (if I've read the manual/faqs for that kvm switch right) that the kvm understood the teensy usb keyboard presses well enough to emulate them but not to actually respond to them (wtf?). If the computer typed the a, but the kvm didn't, then the kvm is probably not recognising the teensy USB keyboard at all. If neither typed it, then there's a problem with the actual sending code so that the keypresses are not actually being sent.

If it's working through the computer but not through the kvm, the last thing I can think of to try is more difficult - it would be to change the teensy hardware-library code so that it *only* reported the Keyboard USB HID interface (in case it was the presence of the mouse/joystick interfaces that is causing the KVM's emulation to go wacky), and not the mouse/joystick/(Serial) interfaces. Paul is probably a *much* better person to describe how to cut that down properly - there's a lot of stuff in there, and if you get it wrong the computer won't recognise the teensy when you boot your code (though you can at least get it back into reprogram mode by holding down the reset button on the teensy while plugging it into the computer if that happens).


It is working through the computer.. I used this (https://www.youtube.com/watch?feature=player_embedded&v=eYRa3ClXP-w) video to build an "awesome" button, but just bridging the wires.

How do I go about attempting to make this only a keyboard and not a Joystick etc..

myk3
05-16-2013, 01:35 PM
I would use a VM, but the machines on the KVM are on different networks.. I guess i could add an extra network card though..

myk3
05-20-2013, 03:03 PM
Can i configure the teensy just a a keyboard and nothing else?

PaulStoffregen
05-21-2013, 06:17 AM
Can i configure the teensy just a a keyboard and nothing else?

Yes, but you'll have to edit the USB code. The code is a bit complex, but just disabling the stuff you don't want is relatively easy.

The code for Teensy 2.0 and 3.0 is different, so any more specific answer depends on which board you're using.

myk3
05-22-2013, 06:30 PM
Yes, but you'll have to edit the USB code. The code is a bit complex, but just disabling the stuff you don't want is relatively easy.

The code for Teensy 2.0 and 3.0 is different, so any more specific answer depends on which board you're using.


I am using a Teensy 2.0

PaulStoffregen
05-22-2013, 08:53 PM
Ok, you'll need to edit hardware/teensy/cores/usb_hid/usb.c. The first part of the file is the descriptor data. This is the binary data that your PC reads the learn what type of device you're plugged in. You only need to remove the mouse and joystick from the descriptors. The rest of the code can remain.

The main thing you need to edit is the "config1_descriptor" array. You'll see it's in 5 sections (a blank line between each). Keep the first two, and delete the last 3 (mouse, debug and joystick). Right above that array are some #defines for the length of the array and offsets of stuff within it. The numbers correspond to the sections. You must delete the numbers for the stuff you delete from the array, so it still matches up.

That ought to do it. There's a lot of other code you could delete, but it does no harm to leave it in.

myk3
05-22-2013, 09:27 PM
Ok, you'll need to edit hardware/teensy/cores/usb_hid/usb.c. The first part of the file is the descriptor data. This is the binary data that your PC reads the learn what type of device you're plugged in. You only need to remove the mouse and joystick from the descriptors. The rest of the code can remain.

The main thing you need to edit is the "config1_descriptor" array. You'll see it's in 5 sections (a blank line between each). Keep the first two, and delete the last 3 (mouse, debug and joystick). Right above that array are some #defines for the length of the array and offsets of stuff within it. The numbers correspond to the sections. You must delete the numbers for the stuff you delete from the array, so it still matches up.

That ought to do it. There's a lot of other code you could delete, but it does no harm to leave it in.

I think i did it right, but i got an error when trying to compile


In file included from C:\Users\user\Desktop\arduino-1.0.3\hardware\teensy\cores\teensy\usb.c:4:
C:\Users\user\Desktop\arduino-1.0.3\hardware\teensy\cores\teensy\/../usb_hid/usb.c:231: error: 'CONFIG1_DESC_SIZE' undeclared here (not in a function)
C:\Users\user\Desktop\arduino-1.0.3\hardware\teensy\cores\teensy\/../usb_hid/usb.c:303: error: 'MOUSE_HID_DESC_OFFSET' undeclared here (not in a function)
C:\Users\user\Desktop\arduino-1.0.3\hardware\teensy\cores\teensy\/../usb_hid/usb.c:305: error: 'DEBUG_HID_DESC_OFFSET' undeclared here (not in a function)
C:\Users\user\Desktop\arduino-1.0.3\hardware\teensy\cores\teensy\/../usb_hid/usb.c:308: error: 'JOYSTICK_HID_DESC_OFFSET' undeclared here (not in a function)

Before Edit:

#define KEYBOARD_HID_DESC_OFFSET ( 9 + 9 )
#define MOUSE_HID_DESC_OFFSET ( 9 + 9+9+7 + 9 )
#define DEBUG_HID_DESC_OFFSET ( 9 + 9+9+7 + 9+9+7 + 9 )
#ifdef JOYSTICK_INTERFACE
#define JOYSTICK_HID_DESC_OFFSET ( 9 + 9+9+7 + 9+9+7 + 9+9+7+7 + 9 )
#define CONFIG1_DESC_SIZE ( 9 + 9+9+7 + 9+9+7 + 9+9+7+7 + 9+9+7)
#else
#define CONFIG1_DESC_SIZE ( 9 + 9+9+7 + 9+9+7 + 9+9+7+7 )
#endif

static const uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = {
// configuration descriptor, USB spec 9.6.3, page 264-266, Table 9-10
9, // bLength;
2, // bDescriptorType;
LSB(CONFIG1_DESC_SIZE), // wTotalLength
MSB(CONFIG1_DESC_SIZE),
NUM_INTERFACE, // bNumInterfaces
1, // bConfigurationValue
0, // iConfiguration
0xC0, // bmAttributes
50, // bMaxPower

// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
9, // bLength
4, // bDescriptorType
KEYBOARD_INTERFACE, // bInterfaceNumber
0, // bAlternateSetting
1, // bNumEndpoints
0x03, // bInterfaceClass (0x03 = HID)
0x01, // bInterfaceSubClass (0x01 = Boot)
0x01, // bInterfaceProtocol (0x01 = Keyboard)
0, // iInterface
// HID interface descriptor, HID 1.11 spec, section 6.2.1
9, // bLength
0x21, // bDescriptorType
0x11, 0x01, // bcdHID
0, // bCountryCode
1, // bNumDescriptors
0x22, // bDescriptorType
sizeof(keyboard_hid_report_desc), // wDescriptorLength
0,
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
7, // bLength
5, // bDescriptorType
KEYBOARD_ENDPOINT | 0x80, // bEndpointAddress
0x03, // bmAttributes (0x03=intr)
KEYBOARD_SIZE, 0, // wMaxPacketSize
KEYBOARD_INTERVAL, // bInterval

// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
9, // bLength
4, // bDescriptorType
MOUSE_INTERFACE, // bInterfaceNumber
0, // bAlternateSetting
1, // bNumEndpoints
0x03, // bInterfaceClass (0x03 = HID)
0x01, // bInterfaceSubClass (0x01 = Boot)
0x02, // bInterfaceProtocol (0x02 = Mouse)
0, // iInterface
// HID interface descriptor, HID 1.11 spec, section 6.2.1
9, // bLength
0x21, // bDescriptorType
0x11, 0x01, // bcdHID
0, // bCountryCode
1, // bNumDescriptors
0x22, // bDescriptorType
sizeof(mouse_hid_report_desc), // wDescriptorLength
0,
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
7, // bLength
5, // bDescriptorType
MOUSE_ENDPOINT | 0x80, // bEndpointAddress
0x03, // bmAttributes (0x03=intr)
MOUSE_SIZE, 0, // wMaxPacketSize
MOUSE_INTERVAL, // bInterval

// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
9, // bLength
4, // bDescriptorType
DEBUG_INTERFACE, // bInterfaceNumber
0, // bAlternateSetting
2, // bNumEndpoints
0x03, // bInterfaceClass (0x03 = HID)
0x00, // bInterfaceSubClass
0x00, // bInterfaceProtocol
0, // iInterface
// HID interface descriptor, HID 1.11 spec, section 6.2.1
9, // bLength
0x21, // bDescriptorType
0x11, 0x01, // bcdHID
0, // bCountryCode
1, // bNumDescriptors
0x22, // bDescriptorType
sizeof(debug_hid_report_desc), // wDescriptorLength
0,
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
7, // bLength
5, // bDescriptorType
DEBUG_TX_ENDPOINT | 0x80, // bEndpointAddress
0x03, // bmAttributes (0x03=intr)
DEBUG_TX_SIZE, 0, // wMaxPacketSize
DEBUG_TX_INTERVAL, // bInterval
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
7, // bLength
5, // bDescriptorType
DEBUG_RX_ENDPOINT, // bEndpointAddress
0x03, // bmAttributes (0x03=intr)
DEBUG_RX_SIZE, 0, // wMaxPacketSize
DEBUG_RX_INTERVAL, // bInterval

#ifdef JOYSTICK_INTERFACE
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
9, // bLength
4, // bDescriptorType
JOYSTICK_INTERFACE, // bInterfaceNumber
0, // bAlternateSetting
1, // bNumEndpoints
0x03, // bInterfaceClass (0x03 = HID)
0x00, // bInterfaceSubClass
0x00, // bInterfaceProtocol
0, // iInterface
// HID interface descriptor, HID 1.11 spec, section 6.2.1
9, // bLength
0x21, // bDescriptorType
0x11, 0x01, // bcdHID
0, // bCountryCode
1, // bNumDescriptors
0x22, // bDescriptorType
sizeof(joystick_hid_report_desc), // wDescriptorLength
0,
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
7, // bLength
5, // bDescriptorType
JOYSTICK_ENDPOINT | 0x80, // bEndpointAddress
0x03, // bmAttributes (0x03=intr)
12, 0, // wMaxPacketSize
JOYSTICK_INTERVAL, // bInterval
#endif
};


After Edit:

#define KEYBOARD_HID_DESC_OFFSET ( 9 + 9 )
static const uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = {
// configuration descriptor, USB spec 9.6.3, page 264-266, Table 9-10
9, // bLength;
2, // bDescriptorType;
LSB(CONFIG1_DESC_SIZE), // wTotalLength
MSB(CONFIG1_DESC_SIZE),
NUM_INTERFACE, // bNumInterfaces
1, // bConfigurationValue
0, // iConfiguration
0xC0, // bmAttributes
50, // bMaxPower

// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
9, // bLength
4, // bDescriptorType
KEYBOARD_INTERFACE, // bInterfaceNumber
0, // bAlternateSetting
1, // bNumEndpoints
0x03, // bInterfaceClass (0x03 = HID)
0x01, // bInterfaceSubClass (0x01 = Boot)
0x01, // bInterfaceProtocol (0x01 = Keyboard)
0, // iInterface
// HID interface descriptor, HID 1.11 spec, section 6.2.1
9, // bLength
0x21, // bDescriptorType
0x11, 0x01, // bcdHID
0, // bCountryCode
1, // bNumDescriptors
0x22, // bDescriptorType
sizeof(keyboard_hid_report_desc), // wDescriptorLength
0,
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
7, // bLength
5, // bDescriptorType
KEYBOARD_ENDPOINT | 0x80, // bEndpointAddress
0x03, // bmAttributes (0x03=intr)
KEYBOARD_SIZE, 0, // wMaxPacketSize
KEYBOARD_INTERVAL, // bInterval
};

Dawnmist
05-28-2013, 09:06 AM
CONFIG1_DESC_SIZE - this define is used to specify the total size of the config1_descriptor array, so you still need it. I believe it should be set to the sum of the initial header part + the size of the keyboard part, which would make it (assuming I've read what's there right - if I'm wrong, please DO correct me!):



#define CONFIG1_DESC_SIZE ( 9 + 9+9+7 )


The other errors (for MOUSE_HID_DESC_OFFSET, DEBUG_HID_DESC_OFFSET and JOYSTICK_HID_DESC_OFFSET) indicate that these are still used further down in the file - there's another section that would need editing too. If you look down where it's referring to (lines 303-308 in your version of usb.c), you'll see a section that defines the descriptor list:


static const struct descriptor_list_struct {
uint16_t wValue;
uint16_t wIndex;
const uint8_t *addr;
uint8_t length;
} PROGMEM descriptor_list[] = {
{0x0100, 0x0000, device_descriptor, sizeof(device_descriptor)},
{0x0200, 0x0000, config1_descriptor, sizeof(config1_descriptor)},
{0x2200, KEYBOARD_INTERFACE, keyboard_hid_report_desc, sizeof(keyboard_hid_report_desc)},
{0x2100, KEYBOARD_INTERFACE, config1_descriptor+KEYBOARD_HID_DESC_OFFSET, 9},
{0x2200, MOUSE_INTERFACE, mouse_hid_report_desc, sizeof(mouse_hid_report_desc)},
{0x2100, MOUSE_INTERFACE, config1_descriptor+MOUSE_HID_DESC_OFFSET, 9},
{0x2200, DEBUG_INTERFACE, debug_hid_report_desc, sizeof(debug_hid_report_desc)},
{0x2100, DEBUG_INTERFACE, config1_descriptor+DEBUG_HID_DESC_OFFSET, 9},
#ifdef JOYSTICK_INTERFACE
{0x2200, JOYSTICK_INTERFACE, joystick_hid_report_desc, sizeof(joystick_hid_report_desc)},
{0x2100, JOYSTICK_INTERFACE, config1_descriptor+JOYSTICK_HID_DESC_OFFSET, 9},
#endif
{0x0300, 0x0000, (const uint8_t *)&string0, 4},
{0x0301, 0x0409, (const uint8_t *)&string1, sizeof(STR_PRODUCT)},
};
#define NUM_DESC_LIST (sizeof(descriptor_list)/sizeof(struct descriptor_list_struct))

This will also need to be edited to remove the mouse/debug/joystick descriptors. I *think* the edited version would be:


static const struct descriptor_list_struct {
uint16_t wValue;
uint16_t wIndex;
const uint8_t *addr;
uint8_t length;
} PROGMEM descriptor_list[] = {
{0x0100, 0x0000, device_descriptor, sizeof(device_descriptor)},
{0x0200, 0x0000, config1_descriptor, sizeof(config1_descriptor)},
{0x2200, KEYBOARD_INTERFACE, keyboard_hid_report_desc, sizeof(keyboard_hid_report_desc)},
{0x2100, KEYBOARD_INTERFACE, config1_descriptor+KEYBOARD_HID_DESC_OFFSET, 9},
{0x0300, 0x0000, (const uint8_t *)&string0, 4},
{0x0301, 0x0409, (const uint8_t *)&string1, sizeof(STR_PRODUCT)},
};
#define NUM_DESC_LIST (sizeof(descriptor_list)/sizeof(struct descriptor_list_struct))


I'm not sure if that's all the sections that need modification - there's code dealing with some of those endpoints for mouse/joystick that I don't know whether it needs removal or will just work with the edited descriptors.

myk3
05-28-2013, 01:33 PM
CONFIG1_DESC_SIZE - this define is used to specify the total size of the config1_descriptor array, so you still need it. I believe it should be set to the sum of the initial header part + the size of the keyboard part, which would make it (assuming I've read what's there right - if I'm wrong, please DO correct me!):



#define CONFIG1_DESC_SIZE ( 9 + 9+9+7 )


The other errors (for MOUSE_HID_DESC_OFFSET, DEBUG_HID_DESC_OFFSET and JOYSTICK_HID_DESC_OFFSET) indicate that these are still used further down in the file - there's another section that would need editing too. If you look down where it's referring to (lines 303-308 in your version of usb.c), you'll see a section that defines the descriptor list:


static const struct descriptor_list_struct {
uint16_t wValue;
uint16_t wIndex;
const uint8_t *addr;
uint8_t length;
} PROGMEM descriptor_list[] = {
{0x0100, 0x0000, device_descriptor, sizeof(device_descriptor)},
{0x0200, 0x0000, config1_descriptor, sizeof(config1_descriptor)},
{0x2200, KEYBOARD_INTERFACE, keyboard_hid_report_desc, sizeof(keyboard_hid_report_desc)},
{0x2100, KEYBOARD_INTERFACE, config1_descriptor+KEYBOARD_HID_DESC_OFFSET, 9},
{0x2200, MOUSE_INTERFACE, mouse_hid_report_desc, sizeof(mouse_hid_report_desc)},
{0x2100, MOUSE_INTERFACE, config1_descriptor+MOUSE_HID_DESC_OFFSET, 9},
{0x2200, DEBUG_INTERFACE, debug_hid_report_desc, sizeof(debug_hid_report_desc)},
{0x2100, DEBUG_INTERFACE, config1_descriptor+DEBUG_HID_DESC_OFFSET, 9},
#ifdef JOYSTICK_INTERFACE
{0x2200, JOYSTICK_INTERFACE, joystick_hid_report_desc, sizeof(joystick_hid_report_desc)},
{0x2100, JOYSTICK_INTERFACE, config1_descriptor+JOYSTICK_HID_DESC_OFFSET, 9},
#endif
{0x0300, 0x0000, (const uint8_t *)&string0, 4},
{0x0301, 0x0409, (const uint8_t *)&string1, sizeof(STR_PRODUCT)},
};
#define NUM_DESC_LIST (sizeof(descriptor_list)/sizeof(struct descriptor_list_struct))

This will also need to be edited to remove the mouse/debug/joystick descriptors. I *think* the edited version would be:


static const struct descriptor_list_struct {
uint16_t wValue;
uint16_t wIndex;
const uint8_t *addr;
uint8_t length;
} PROGMEM descriptor_list[] = {
{0x0100, 0x0000, device_descriptor, sizeof(device_descriptor)},
{0x0200, 0x0000, config1_descriptor, sizeof(config1_descriptor)},
{0x2200, KEYBOARD_INTERFACE, keyboard_hid_report_desc, sizeof(keyboard_hid_report_desc)},
{0x2100, KEYBOARD_INTERFACE, config1_descriptor+KEYBOARD_HID_DESC_OFFSET, 9},
{0x0300, 0x0000, (const uint8_t *)&string0, 4},
{0x0301, 0x0409, (const uint8_t *)&string1, sizeof(STR_PRODUCT)},
};
#define NUM_DESC_LIST (sizeof(descriptor_list)/sizeof(struct descriptor_list_struct))


I'm not sure if that's all the sections that need modification - there's code dealing with some of those endpoints for mouse/joystick that I don't know whether it needs removal or will just work with the edited descriptors.

I got a different error this time..


In file included from C:\Users\michael.chipser\Desktop\arduino-1.0.3\hardware\teensy\cores\teensy\usb.c:4:
C:\Users\michael.chipser\Desktop\arduino-1.0.3\hardware\teensy\cores\teensy\/../usb_hid/usb.c:244: error: lvalue required as unary '&' operand
C:\Users\michael.chipser\Desktop\arduino-1.0.3\hardware\teensy\cores\teensy\/../usb_hid/usb.c:245: error: expected expression before '>>' token


I don't see a & or >> on the lines specified..


/* USB Serial Example for Teensy USB Development Board
* http://www.pjrc.com/teensy/usb_serial.html
* Copyright (c) 2008 PJRC.COM, LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/


#include "usb_common.h"
#include "usb_private.h"



/************************************************** ************************
*
* Endpoint Buffer Configuration
*
************************************************** ************************/


static const uint8_t PROGMEM endpoint_config_table[] = {
1, EP_TYPE_INTERRUPT_IN, EP_SIZE(DEBUG_TX_SIZE) | DEBUG_TX_BUFFER,
1, EP_TYPE_INTERRUPT_OUT, EP_SIZE(DEBUG_RX_SIZE) | DEBUG_RX_BUFFER,
1, EP_TYPE_INTERRUPT_IN, EP_SIZE(KEYBOARD_SIZE) | KEYBOARD_BUFFER,
1, EP_TYPE_INTERRUPT_IN, EP_SIZE(MOUSE_SIZE) | MOUSE_BUFFER,
#ifdef JOYSTICK_INTERFACE
1, EP_TYPE_INTERRUPT_IN, EP_SIZE(JOYSTICK_SIZE) | JOYSTICK_BUFFER,
0
#endif
};


/************************************************** ************************
*
* Descriptor Data
*
************************************************** ************************/

// Descriptors are the data that your computer reads when it auto-detects
// this USB device (called "enumeration" in USB lingo). The most commonly
// changed items are editable at the top of this file. Changing things
// in here should only be done by those who've read chapter 9 of the USB
// spec and relevant portions of any USB class specifications!

static const uint8_t PROGMEM device_descriptor[] = {
18, // bLength
1, // bDescriptorType
0x00, 0x02, // bcdUSB
0, // bDeviceClass
0, // bDeviceSubClass
0, // bDeviceProtocol
ENDPOINT0_SIZE, // bMaxPacketSize0
LSB(VENDOR_ID), MSB(VENDOR_ID), // idVendor
LSB(PRODUCT_ID), MSB(PRODUCT_ID), // idProduct
0x05, 0x01, // bcdDevice
0, // iManufacturer
1, // iProduct
0, // iSerialNumber
1 // bNumConfigurations
};

// Keyboard Protocol 1, HID 1.11 spec, Appendix B, page 59-60
static const uint8_t PROGMEM keyboard_hid_report_desc[] = {
0x05, 0x01, // Usage Page (Generic Desktop),
0x09, 0x06, // Usage (Keyboard),
0xA1, 0x01, // Collection (Application),
0x75, 0x01, // Report Size (1),
0x95, 0x08, // Report Count (8),
0x05, 0x07, // Usage Page (Key Codes),
0x19, 0xE0, // Usage Minimum (224),
0x29, 0xE7, // Usage Maximum (231),
0x15, 0x00, // Logical Minimum (0),
0x25, 0x01, // Logical Maximum (1),
0x81, 0x02, // Input (Data, Variable, Absolute), ;Modifier byte
0x95, 0x08, // Report Count (8),
0x75, 0x01, // Report Size (1),
0x15, 0x00, // Logical Minimum (0),
0x25, 0x01, // Logical Maximum (1),
0x05, 0x0C, // Usage Page (Consumer),
0x09, 0xE9, // Usage (Volume Increment),
0x09, 0xEA, // Usage (Volume Decrement),
0x09, 0xE2, // Usage (Mute),
0x09, 0xCD, // Usage (Play/Pause),
0x09, 0xB5, // Usage (Scan Next Track),
0x09, 0xB6, // Usage (Scan Previous Track),
0x09, 0xB7, // Usage (Stop),
0x09, 0xB8, // Usage (Eject),
0x81, 0x02, // Input (Data, Variable, Absolute), ;Media keys
0x95, 0x05, // Report Count (5),
0x75, 0x01, // Report Size (1),
0x05, 0x08, // Usage Page (LEDs),
0x19, 0x01, // Usage Minimum (1),
0x29, 0x05, // Usage Maximum (5),
0x91, 0x02, // Output (Data, Variable, Absolute), ;LED report
0x95, 0x01, // Report Count (1),
0x75, 0x03, // Report Size (3),
0x91, 0x03, // Output (Constant), ;LED report padding
0x95, 0x06, // Report Count (6),
0x75, 0x08, // Report Size (8),
0x15, 0x00, // Logical Minimum (0),
0x25, 0x7F, // Logical Maximum(104),
0x05, 0x07, // Usage Page (Key Codes),
0x19, 0x00, // Usage Minimum (0),
0x29, 0x7F, // Usage Maximum (104),
0x81, 0x00, // Input (Data, Array), ;Normal keys
0xc0 // End Collection
};

// Mouse Protocol 1, HID 1.11 spec, Appendix B, page 59-60, with wheel extension
static const uint8_t PROGMEM mouse_hid_report_desc[] = {
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x02, // Usage (Mouse)
0xA1, 0x01, // Collection (Application)
0x05, 0x09, // Usage Page (Button)
0x19, 0x01, // Usage Minimum (Button #1)
0x29, 0x03, // Usage Maximum (Button #3)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x95, 0x03, // Report Count (3)
0x75, 0x01, // Report Size (1)
0x81, 0x02, // Input (Data, Variable, Absolute)
0x95, 0x01, // Report Count (1)
0x75, 0x05, // Report Size (5)
0x81, 0x03, // Input (Constant)
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y)
0x15, 0x81, // Logical Minimum (-127)
0x25, 0x7F, // Logical Maximum (127)
0x75, 0x08, // Report Size (8),
0x95, 0x02, // Report Count (2),
0x81, 0x06, // Input (Data, Variable, Relative)
0x09, 0x38, // Usage (Wheel)
0x95, 0x01, // Report Count (1),
0x81, 0x06, // Input (Data, Variable, Relative)
0xC0 // End Collection
};

#ifdef JOYSTICK_INTERFACE
static const uint8_t PROGMEM joystick_hid_report_desc[] = {
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x04, // Usage (Joystick)
0xA1, 0x01, // Collection (Application)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x20, // Report Count (32)
0x05, 0x09, // Usage Page (Button)
0x19, 0x01, // Usage Minimum (Button #1)
0x29, 0x20, // Usage Maximum (Button #32)
0x81, 0x02, // Input (variable,absolute)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x07, // Logical Maximum (7)
0x35, 0x00, // Physical Minimum (0)
0x46, 0x3B, 0x01, // Physical Maximum (315)
0x75, 0x04, // Report Size (4)
0x95, 0x01, // Report Count (1)
0x65, 0x14, // Unit (20)
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x39, // Usage (Hat switch)
0x81, 0x42, // Input (variable,absolute,null_state)
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x01, // Usage (Pointer)
0xA1, 0x00, // Collection ()
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x03, // Logical Maximum (1023)
0x75, 0x0A, // Report Size (10)
0x95, 0x04, // Report Count (4)
0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y)
0x09, 0x32, // Usage (Z)
0x09, 0x35, // Usage (Rz)
0x81, 0x02, // Input (variable,absolute)
0xC0, // End Collection
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x03, // Logical Maximum (1023)
0x75, 0x0A, // Report Size (10)
0x95, 0x02, // Report Count (2)
0x09, 0x36, // Usage (Slider)
0x09, 0x36, // Usage (Slider)
0x81, 0x02, // Input (variable,absolute)
0xC0 // End Collection
};
#endif







static const uint8_t PROGMEM debug_hid_report_desc[] = {
0x06, 0xC9, 0xFF, // Usage Page 0xFFC9 (vendor defined)
0x09, 0x04, // Usage 0x04
0xA1, 0x5C, // Collection 0x5C
0x75, 0x08, // report size = 8 bits (global)
0x15, 0x00, // logical minimum = 0 (global)
0x26, 0xFF, 0x00, // logical maximum = 255 (global)
0x95, DEBUG_TX_SIZE, // report count (global)
0x09, 0x75, // usage (local)
0x81, 0x02, // Input
0x95, DEBUG_RX_SIZE, // report count (global)
0x09, 0x76, // usage (local)
0x91, 0x02, // Output
0x95, 0x04, // report count (global)
0x09, 0x76, // usage (local)
0xB1, 0x02, // Feature
0xC0 // end collection
};



#define KEYBOARD_HID_DESC_OFFSET ( 9 + 9 )
#define CONFIG1_DESC_SIZE ( 9 + 9+9+7 )
#define MOUSE_HID_DESC_OFFSET
#define DEBUG_HID_DESC_OFFSET
#ifdef JOYSTICK_INTERFACE
#define JOYSTICK_HID_DESC_OFFSET
#define CONFIG1_DESC_SIZE
#else
#define CONFIG1_DESC_SIZE
#endif

static const uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = {
// configuration descriptor, USB spec 9.6.3, page 264-266, Table 9-10
9, // bLength;
2, // bDescriptorType;
LSB(CONFIG1_DESC_SIZE), // wTotalLength
MSB(CONFIG1_DESC_SIZE),
NUM_INTERFACE, // bNumInterfaces
1, // bConfigurationValue
0, // iConfiguration
0xC0, // bmAttributes
50, // bMaxPower

// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
9, // bLength
4, // bDescriptorType
KEYBOARD_INTERFACE, // bInterfaceNumber
0, // bAlternateSetting
1, // bNumEndpoints
0x03, // bInterfaceClass (0x03 = HID)
0x01, // bInterfaceSubClass (0x01 = Boot)
0x01, // bInterfaceProtocol (0x01 = Keyboard)
0, // iInterface
// HID interface descriptor, HID 1.11 spec, section 6.2.1
9, // bLength
0x21, // bDescriptorType
0x11, 0x01, // bcdHID
0, // bCountryCode
1, // bNumDescriptors
0x22, // bDescriptorType
sizeof(keyboard_hid_report_desc), // wDescriptorLength
0,
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
7, // bLength
5, // bDescriptorType
KEYBOARD_ENDPOINT | 0x80, // bEndpointAddress
0x03, // bmAttributes (0x03=intr)
KEYBOARD_SIZE, 0, // wMaxPacketSize
KEYBOARD_INTERVAL, // bInterval
};

// If you're desperate for a little extra code memory, these strings
// can be completely removed if iManufacturer, iProduct, iSerialNumber
// in the device desciptor are changed to zeros.
struct usb_string_descriptor_struct {
uint8_t bLength;
uint8_t bDescriptorType;
int16_t wString[];
};
static const struct usb_string_descriptor_struct PROGMEM string0 = {
4,
3,
{0x0409}
};
static const struct usb_string_descriptor_struct PROGMEM string1 = {
sizeof(STR_PRODUCT),
3,
STR_PRODUCT
};

// This table defines which descriptor data is sent for each specific
// request from the host (in wValue and wIndex).
static const struct descriptor_list_struct {
uint16_t wValue;
uint16_t wIndex;
const uint8_t *addr;
uint8_t length;
} PROGMEM descriptor_list[] = {
{0x0100, 0x0000, device_descriptor, sizeof(device_descriptor)},
{0x0200, 0x0000, config1_descriptor, sizeof(config1_descriptor)},
{0x2200, KEYBOARD_INTERFACE, keyboard_hid_report_desc, sizeof(keyboard_hid_report_desc)},
{0x2100, KEYBOARD_INTERFACE, config1_descriptor+KEYBOARD_HID_DESC_OFFSET, 9},
{0x0300, 0x0000, (const uint8_t *)&string0, 4},
{0x0301, 0x0409, (const uint8_t *)&string1, sizeof(STR_PRODUCT)},
};
#define NUM_DESC_LIST (sizeof(descriptor_list)/sizeof(struct descriptor_list_struct))


/************************************************** ************************
*
* Variables - these are the only non-stack RAM usage
*
************************************************** ************************/

// zero when we are not configured, non-zero when enumerated
volatile uint8_t usb_configuration USBSTATE;
volatile uint8_t usb_suspended USBSTATE;

// the time remaining before we transmit any partially full
// packet, or send a zero length packet.
volatile uint8_t debug_flush_timer USBSTATE;

// byte0: which modifier keys are currently pressed
// 1=left ctrl, 2=left shift, 4=left alt, 8=left gui
// 16=right ctrl, 32=right shift, 64=right alt, 128=right gui
// byte1: media keys (TODO: document these)
// bytes2-7: which keys are currently pressed, up to 6 keys may be down at once
uint8_t keyboard_report_data[8] USBSTATE;

// protocol setting from the host. We use exactly the same report
// either way, so this variable only stores the setting since we
// are required to be able to report which setting is in use.
static uint8_t keyboard_protocol USBSTATE;

// the idle configuration, how often we send the report to the
// host (ms * 4) even when it hasn't changed
static uint8_t keyboard_idle_config USBSTATE;

// count until idle timeout
uint8_t keyboard_idle_count USBSTATE;

// 1=num lock, 2=caps lock, 4=scroll lock, 8=compose, 16=kana
volatile uint8_t keyboard_leds USBSTATE;

// which buttons are currently pressed
uint8_t mouse_buttons USBSTATE;

// protocol setting from the host. We use exactly the same report
// either way, so this variable only stores the setting since we
// are required to be able to report which setting is in use.
static uint8_t mouse_protocol USBSTATE;

// joystick data
#ifdef JOYSTICK_INTERFACE
uint8_t joystick_report_data[12] USBSTATE;
#endif


/************************************************** ************************
*
* Public Functions - these are the API intended for the user
*
************************************************** ************************/



// initialize USB serial
void usb_init(void)
{
uint8_t u;

u = USBCON;
if ((u & (1<<USBE)) && !(u & (1<<FRZCLK))) return;
HW_CONFIG();
USB_FREEZE(); // enable USB
PLL_CONFIG(); // config PLL
while (!(PLLCSR & (1<<PLOCK))) ; // wait for PLL lock
USB_CONFIG(); // start USB clock
UDCON = 0; // enable attach resistor
usb_configuration = 0;
usb_suspended = 0;
debug_flush_timer = 0;
keyboard_report_data[0] = 0;
keyboard_report_data[1] = 0;
keyboard_report_data[2] = 0;
keyboard_report_data[3] = 0;
keyboard_report_data[4] = 0;
keyboard_report_data[5] = 0;
keyboard_report_data[6] = 0;
keyboard_report_data[7] = 0;
keyboard_protocol = 1;
keyboard_idle_config = 125;
keyboard_idle_count = 0;
keyboard_leds = 0;
mouse_buttons = 0;
mouse_protocol = 1;
#ifdef JOYSTICK_INTERFACE
joystick_report_data[0] = 0;
joystick_report_data[1] = 0;
joystick_report_data[2] = 0;
joystick_report_data[3] = 0;
joystick_report_data[4] = 0x0F;
joystick_report_data[5] = 0x20;
joystick_report_data[6] = 0x80;
joystick_report_data[7] = 0x00;
joystick_report_data[8] = 0x02;
joystick_report_data[9] = 0x08;
joystick_report_data[10] = 0x20;
joystick_report_data[11] = 0x80;
#endif
UDINT = 0;
UDIEN = (1<<EORSTE)|(1<<SOFE);
//sei(); // init() in wiring.c does this
}

void usb_shutdown(void)
{
UDIEN = 0; // disable interrupts
UDCON = 1; // disconnect attach resistor
USBCON = 0; // shut off USB periperal
PLLCSR = 0; // shut off PLL
usb_configuration = 0;
usb_suspended = 1;
}


// Public API functions moved to usb_api.cpp

/************************************************** ************************
*
* Private Functions - not intended for general user consumption....
*
************************************************** ************************/



// USB Device Interrupt - handle all device-level events
// the transmit buffer flushing is triggered by the start of frame
//
ISR(USB_GEN_vect)
{
uint8_t intbits, t, i;
static uint8_t div4=0;

intbits = UDINT;
UDINT = 0;
if (intbits & (1<<EORSTI)) {
UENUM = 0;
UECONX = 1;
UECFG0X = EP_TYPE_CONTROL;
UECFG1X = EP_SIZE(ENDPOINT0_SIZE) | EP_SINGLE_BUFFER;
UEIENX = (1<<RXSTPE);
usb_configuration = 0;
}
if ((intbits & (1<<SOFI)) && usb_configuration) {
t = debug_flush_timer;
if (t) {
debug_flush_timer = -- t;
if (!t) {
UENUM = DEBUG_TX_ENDPOINT;
while ((UEINTX & (1<<RWAL))) {
UEDATX = 0;
}
UEINTX = 0x3A;
}
}
if (keyboard_idle_config && (++div4 & 3) == 0) {
UENUM = KEYBOARD_ENDPOINT;
if (UEINTX & (1<<RWAL)) {
keyboard_idle_count++;
if (keyboard_idle_count == keyboard_idle_config) {
keyboard_idle_count = 0;
//len = keyboard_protocol ? sizeof(keyboard_keys) : 8;
for (i=0; i < 8; i++) {
UEDATX = keyboard_report_data[i];
}
UEINTX = 0x3A;
}
}
}
}
if (intbits & (1<<SUSPI)) {
// USB Suspend (inactivity for 3ms)
UDIEN = (1<<WAKEUPE);
usb_configuration = 0;
usb_suspended = 1;
#if (F_CPU >= 8000000L)
// WAKEUPI does not work with USB clock freeze
// when CPU is running less than 8 MHz.
// Is this a hardware bug?
USB_FREEZE(); // shut off USB
PLLCSR = 0; // shut off PLL
#endif
// to properly meet the USB spec, current must
// reduce to less than 2.5 mA, which means using
// powerdown mode, but that breaks the Arduino
// user's paradigm....
}
if (usb_suspended && (intbits & (1<<WAKEUPI))) {
// USB Resume (pretty much any activity)
#if (F_CPU >= 8000000L)
PLL_CONFIG();
while (!(PLLCSR & (1<<PLOCK))) ;
USB_CONFIG();
#endif
UDIEN = (1<<EORSTE)|(1<<SOFE)|(1<<SUSPE);
usb_suspended = 0;
return;
}
}


// Misc functions to wait for ready and send/receive packets
static inline void usb_wait_in_ready(void)
{
while (!(UEINTX & (1<<TXINI))) ;
}
static inline void usb_send_in(void)
{
UEINTX = ~(1<<TXINI);
}
static inline void usb_wait_receive_out(void)
{
while (!(UEINTX & (1<<RXOUTI))) ;
}
static inline void usb_ack_out(void)
{
UEINTX = ~(1<<RXOUTI);
}



// USB Endpoint Interrupt - endpoint 0 is handled here. The
// other endpoints are manipulated by the user-callable
// functions, and the start-of-frame interrupt.
//
ISR(USB_COM_vect)
{
uint8_t intbits;
const uint8_t *list;
const uint8_t *cfg;
uint8_t i, n, len, en;
uint8_t bmRequestType;
uint8_t bRequest;
uint16_t wValue;
uint16_t wIndex;
uint16_t wLength;
uint16_t desc_val;
const uint8_t *desc_addr;
uint8_t desc_length;

UENUM = 0;
intbits = UEINTX;
if (intbits & (1<<RXSTPI)) {
bmRequestType = UEDATX;
bRequest = UEDATX;
read_word_lsbfirst(wValue, UEDATX);
read_word_lsbfirst(wIndex, UEDATX);
read_word_lsbfirst(wLength, UEDATX);
UEINTX = ~((1<<RXSTPI) | (1<<RXOUTI) | (1<<TXINI));
if (bRequest == GET_DESCRIPTOR) {
list = (const uint8_t *)descriptor_list;
for (i=0; ; i++) {
if (i >= NUM_DESC_LIST) {
UECONX = (1<<STALLRQ)|(1<<EPEN); //stall
return;
}
pgm_read_word_postinc(desc_val, list);
if (desc_val != wValue) {
list += sizeof(struct descriptor_list_struct)-2;
continue;
}
pgm_read_word_postinc(desc_val, list);
if (desc_val != wIndex) {
list += sizeof(struct descriptor_list_struct)-4;
continue;
}
pgm_read_word_postinc(desc_addr, list);
desc_length = pgm_read_byte(list);
break;
}
len = (wLength < 256) ? wLength : 255;
if (len > desc_length) len = desc_length;
list = desc_addr;
do {
// wait for host ready for IN packet
do {
i = UEINTX;
} while (!(i & ((1<<TXINI)|(1<<RXOUTI))));
if (i & (1<<RXOUTI)) return; // abort
// send IN packet
n = len < ENDPOINT0_SIZE ? len : ENDPOINT0_SIZE;
for (i = n; i; i--) {
pgm_read_byte_postinc(UEDATX, list);
}
len -= n;
usb_send_in();
} while (len || n == ENDPOINT0_SIZE);
return;
}
if (bRequest == SET_ADDRESS) {
usb_send_in();
usb_wait_in_ready();
UDADDR = wValue | (1<<ADDEN);
return;
}
if (bRequest == SET_CONFIGURATION && bmRequestType == 0) {
usb_configuration = wValue;
debug_flush_timer = 0;
usb_send_in();
cfg = endpoint_config_table;
for (i=1; i<NUM_ENDPOINTS; i++) {
UENUM = i;
pgm_read_byte_postinc(en, cfg);
UECONX = en;
if (en) {
pgm_read_byte_postinc(UECFG0X, cfg);
pgm_read_byte_postinc(UECFG1X, cfg);
}
}
UERST = 0x1E;
UERST = 0;
return;
}
if (bRequest == GET_CONFIGURATION && bmRequestType == 0x80) {
usb_wait_in_ready();
UEDATX = usb_configuration;
usb_send_in();
return;
}
if (bRequest == GET_STATUS) {
usb_wait_in_ready();
i = 0;
if (bmRequestType == 0x82) {
UENUM = wIndex;
if (UECONX & (1<<STALLRQ)) i = 1;
UENUM = 0;
}
UEDATX = i;
UEDATX = 0;
usb_send_in();
return;
}
if ((bRequest == CLEAR_FEATURE || bRequest == SET_FEATURE)
&& bmRequestType == 0x02 && wValue == 0) {
i = wIndex & 0x7F;
if (i >= 1 && i <= NUM_ENDPOINTS) {
usb_send_in();
UENUM = i;
if (bRequest == SET_FEATURE) {
UECONX = (1<<STALLRQ)|(1<<EPEN);
} else {
UECONX = (1<<STALLRQC)|(1<<RSTDT)|(1<<EPEN);
UERST = (1 << i);
UERST = 0;
}
return;
}
}
if (wIndex == KEYBOARD_INTERFACE) {
if (bmRequestType == 0xA1) {
if (bRequest == HID_GET_REPORT) {
usb_wait_in_ready();
//len = keyboard_protocol ? sizeof(keyboard_keys) : 8;
for (i=0; i < 8; i++) {
UEDATX = keyboard_report_data[i];
}
usb_send_in();
return;
}
if (bRequest == HID_GET_IDLE) {
usb_wait_in_ready();
UEDATX = keyboard_idle_config;
usb_send_in();
return;
}
if (bRequest == HID_GET_PROTOCOL) {
usb_wait_in_ready();
UEDATX = keyboard_protocol;
usb_send_in();
return;
}
}
if (bmRequestType == 0x21) {
if (bRequest == HID_SET_REPORT) {
usb_wait_receive_out();
keyboard_leds = UEDATX;
usb_ack_out();
usb_send_in();
return;
}
if (bRequest == HID_SET_IDLE) {
keyboard_idle_config = (wValue >> 8);
keyboard_idle_count = 0;
//usb_wait_in_ready();
usb_send_in();
return;
}
if (bRequest == HID_SET_PROTOCOL) {
keyboard_protocol = wValue;
//usb_wait_in_ready();
usb_send_in();
return;
}
}
}
if (wIndex == MOUSE_INTERFACE) {
if (bmRequestType == 0xA1) {
if (bRequest == HID_GET_REPORT) {
usb_wait_in_ready();
UEDATX = mouse_buttons;
UEDATX = 0;
UEDATX = 0;
UEDATX = 0;
usb_send_in();
return;
}
if (bRequest == HID_GET_PROTOCOL) {
usb_wait_in_ready();
UEDATX = mouse_protocol;
usb_send_in();
return;
}
}
if (bmRequestType == 0x21) {
if (bRequest == HID_SET_PROTOCOL) {
mouse_protocol = wValue;
usb_send_in();
return;
}
}
}
#ifdef JOYSTICK_INTERFACE
if (wIndex == JOYSTICK_INTERFACE) {
if (bmRequestType == 0xA1) {
if (bRequest == HID_GET_REPORT) {
usb_wait_in_ready();
for (i=0; i<12; i++) {
UEDATX = joystick_report_data[i];
}
usb_send_in();
return;
}
}
}
#endif
if (wIndex == DEBUG_INTERFACE) {
if (bRequest == HID_GET_REPORT && bmRequestType == 0xA1) {
len = wLength;
do {
// wait for host ready for IN packet
do {
i = UEINTX;
} while (!(i & ((1<<TXINI)|(1<<RXOUTI))));
if (i & (1<<RXOUTI)) return; // abort
// send IN packet
n = len < ENDPOINT0_SIZE ? len : ENDPOINT0_SIZE;
for (i = n; i; i--) {
UEDATX = 0;
}
len -= n;
usb_send_in();
} while (len || n == ENDPOINT0_SIZE);
return;
}
if (bRequest == HID_SET_REPORT && bmRequestType == 0x21) {
if (wValue == 0x0300 && wLength == 0x0004) {
uint8_t b1, b2, b3, b4;
usb_wait_receive_out();
b1 = UEDATX;
b2 = UEDATX;
b3 = UEDATX;
b4 = UEDATX;
usb_ack_out();
usb_send_in();
if (b1 == 0xA9 && b2 == 0x45 && b3 == 0xC2 && b4 == 0x6B)
_reboot_Teensyduino_();
if (b1 == 0x8B && b2 == 0xC5 && b3 == 0x1D && b4 == 0x70)
_restart_Teensyduino_();
}
}
}
if (bRequest == 0xC9 && bmRequestType == 0x40) {
usb_send_in();
usb_wait_in_ready();
_restart_Teensyduino_();
}
}
UECONX = (1<<STALLRQ) | (1<<EPEN); // stall
}

Dawnmist
05-28-2013, 02:11 PM
I got a different error this time..

I don't see a & or >> on the lines specified..


#define KEYBOARD_HID_DESC_OFFSET ( 9 + 9 )
#define CONFIG1_DESC_SIZE ( 9 + 9+9+7 )
#define MOUSE_HID_DESC_OFFSET
#define DEBUG_HID_DESC_OFFSET
#ifdef JOYSTICK_INTERFACE
#define JOYSTICK_HID_DESC_OFFSET
#define CONFIG1_DESC_SIZE
#else
#define CONFIG1_DESC_SIZE
#endif


The above section should have been just


#define KEYBOARD_HID_DESC_OFFSET ( 9 + 9 )
#define CONFIG1_DESC_SIZE ( 9 + 9+9+7 )

The mouse & joystick lines are not necessary, and the repeated CONFIG1_DESC_SIZE lines with no value after them are actually unsetting the define again (setting it to essentially ""). This then results in no size being set for the config1_descriptor array, and the LSB() and MSB() defines/functions being called on an empty value instead of a valid value for the lines that were reported in the error message.

PaulStoffregen
05-28-2013, 05:39 PM
I got a different error this time..


You have multiple lines defining CONFIG1_DESC_SIZE. First, it's defined correctly. Then you're destroying the correct definition with an empty one.

Delete these lines:



#ifdef JOYSTICK_INTERFACE
#define JOYSTICK_HID_DESC_OFFSET
#define CONFIG1_DESC_SIZE
#else
#define CONFIG1_DESC_SIZE
#endif

penczoil
05-25-2014, 06:18 PM
Hi Myk3,
Did you ever get this working? I have the exact same problem. I wanted to know if it is worth it to edit the libraries.