Jump to content

Paul Stoffregen

Active Members
  • Posts

    74
  • Joined

  • Last visited

Posts posted by Paul Stoffregen

  1. Alpha #3 uploaded.

    So far, not even one single person has replied or emailed with any feedback on actually using these new versions.... why not be the first?

    Also, does anyone know a way to temporarily disable the Windows safe to remove hardware balloon notification? That's temporarily, like for the fraction of a second before calling the WIN32 function CM_Request_Device_Eject() as soon as it's done?

    This whole process is painfully slow in XP (like an extra several seconds longer than Linux and MacOS, and sometimes very slow, like 15+ seconds), so I'm searching for ideas to speed it up!

  2. Ohhh thats awesome, I guess the Serial.print(); has some opposite option Serial.read();?!?

    for communication between the teensy and the comp?

    if not what use it it? or purley debugging?

    Yes, Serial.read() and Serial.available() can be used to receive data. The usual approach looks like:

    if (Serial.available()) {

    mybyte = Serial.read();

    }

    Serial.read() only reads a single byte, so if you want to receive strings or more than 1 byte numbers, you need to call it in a loop and parse the bytes into whatever you need. If there isn't actually a byte received, Serial.read() will return -1. If you want to wait for a byte, you need something like:

    while (Serial.available() < 1) { /* wait */

    mybyte = Serial.read();

    When using USB Serial, which is the only way you can use normal Arduino boards, these can be used to build code which communicate with PC-based code. There's lots of code out there which communicates via serial ports, because for many years (since the 1980's even), using serial communication has been the main way to communicate with microcontrollers.

    Over the next several months, I'm planning to add more USB types. It's a LOT of work, especially integrating them nicely into Teensyduino and making them easy to use. USB Disk still has a long way to go, as you can see from 0.9 alpha #2. Still, I'm looking for more ideas.... Joystick/Gamepad and MIDI will almost certainly be the next two, and maybe the Raw HID packet code if I can figure out ways to make it easier (more stuff on the PC side). Any other USB ideas?

  3. I know this is probably old news if you're experienced with Arduino, but in case nobody mentioned it...

    You can use Serial.println() and Serial.print() to send messages to Arduino's "Serial Monitor". This works when you build as "USB Keyboard/Mouse" because there is a separate custom HID communication interface that sends to the Serial Monitor, completely independent of whatever you're doing with the Keyboard and Mouse. Of course, when you use a real Arduino or Teensy with USB Serial, the Arduino Serial Monitor listens to an actual COM port (windows) or serial device file (mac, linux).... and on a genuine Arduino board it actually is slow serial from the AVR chip over to a USB-Serial converter chip. On Teensy it's always native USB speed. Currently the serial monitor is broken if you're using the experimental Teensyduino USB Disk, but I'm going to fix it in alpha #3.

    If you've been turning the orange LED on and off to see where your code's running, making use of Serial.print() and watching with the Serial Monitor is a much more satisfying experience.

    Happy hacking, and please use Ducky responsibly!

  4. Alpha #2 uploaded.

    Most changes are bug fixes and changes in the Arduino tools menu. The installer looks the same, but got a major rewrite so it can install to any supported Arduino version. I somehow broke 0016 on Windows (and whatever java exception isn't being thrown to the console, so I can't figure out why.... windows, grrrrr) so only 0017 and 0018 will install. On Mac and Linux, 0016 to 0018 install.

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

    Still broken on USB Disk is using Serial.print() and having the board automatically reset, so you don't have to push the reset button. Those are up next, then I'm going to tackle SD/Micro-SD card support.

    Please give the "Disk(internal) + Keyboard" option a try from the new Tools->USB Type menu! If you discover a bug, please tell me. Or even if it works fine, wouldn't hurt to post here with a "works for me".

  5. okay im confused. How would i change the vendor on my teensy?

    All USB devices have a 16 bit Vendor ID and 16 bit Product ID number. In Teensy, these numbers (and pretty much everything else) is definable by programming.

    If you're programming using Arduino with Teensyduino, look inside your Arduino IDE's installation directory, in hardware/teensy/cores/teensy_hid/usb_private.h. You'll find this near the top:

    #define VENDOR_ID               0x16C0
    #define PRODUCT_ID              0x0482
    

    A little farther down, you'll find this:

    #define STR_PRODUCT             L"Teensy Keyboard/Mouse"
    

    You'll also find there's lots of editable stuff inside usb.c, also in that directory. Those "descriptors" are the actual data the PC reads when it's detecting the USB device (the process is called "enumeration" in USB lingo). You can change it to absolutely anything you desire, though you might want to read chapter 5 and 9 of the USB specification, and maybe review the HID spec and usage tables.... all of which are free downloads at www.usb.org in the developer section.

    Those numbers are compile-time constants, which are placed into arrays of bytes stored in read-only flash memory. You can't change them while the Teensy is running. However, if you really felt ambitious, you could change the code which reads the memory and transmit it to the PC. It's located in the giant endpoint0 interrupt routine, in usb.c. In fact, here it is:

                    if (bRequest == GET_DESCRIPTOR) {
                            list = (const uint8_t *)descriptor_list;
                            for (i=0; ; i++) {
                                    if (i &gt;= NUM_DESC_LIST) {
                                            UECONX = (1&lt;&lt;STALLRQ)|(1&lt;&lt;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 &lt; 256) ? wLength : 255;
                            if (len &gt; desc_length) len = desc_length;
                            list = desc_addr;
                            do {
                                    // wait for host ready for IN packet
                                    do {
                                            i = UEINTX;
                                    } while (!(i &amp; ((1&lt;&lt;TXINI)|(1&lt;&lt;RXOUTI))));
                                    if (i &amp; (1&lt;&lt;RXOUTI)) return;    // abort
                                    // send IN packet
                                    n = len &lt; 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;
                    }
    

    That code is responsible for sending all the descriptors, so if you tweaked it for only 1 descriptor, be sure to make that a special case test and fall back to the normal code for the other cases, since the PC needs to read all the descriptors.

    Of course, intentionally setting the ID numbers to mimic a well known product is ethically questionable, and also violates the USB-IF adapter's agreement, and might be bad karma too....

  6. Please please please use the wiki that Darren set up.

    This whole idea, using HID this way, was Darren's idea pretty much the moment he first saw Teensy, in the days of episode 503. Darren also financed sending 100 free Ducky kits to the Hak5 community!!

    It's really only right to put this on Hak5's wiki. It's new and needs contributions.

    http://www.hak5.org/projects/doku.php?id=usb_rubber_ducky

  7. Any ideas of the eta on the MicroSD boards? :)

    A Teensy form factor adaptor is in the works. It's very small, less than half the size of the Teensy itself, pretty much just the size of the Micro SD card itself plus the first 5 pins on the top and bottom of the Teensy. A first proto was made last week, just to get access to the Micro SD card pins, but without any 5 to 3 volt circuitry. Second proto is in fab now, and parts to build it just arrived a couple days ago. If that works, properly manufactured boards at low price (likely about $7) should be available in late May.

    Of course, you could always build your own, or buy one ready-made....

    http://www.instructables.com/id/Cheap-DIY-...adboard-socket/

    http://store.gravitech.us/micaad.html

    Do keep in mind the SD cards need 3.3 volts. Using a 3.3 volt regulator and a 5 to 3 volt buffer (eg, 74LCX125) is the best option. You can also mod the Teensy to run at 3.3 volts, though running at 16 MHz and 3.3 is technically overclocking.

    http://www.pjrc.com/teensy/3volt.html

    Software support should begin to appear in a couple weeks. I've used SD cards before in several projects, so I have plenty of code laying around. Then again, I haven't used the relatively new SDHC cards yet (other than plugged them into my camera), so it'll need some tweaking. Also, there are some challenging low-level issues I'm concerned about. The main one is achieving close to 1 Mbyte/sec speed, at least for reading, but hopefully while writing too. Since the USB packets are 64 bytes and are handled in an interrupt driven driver (which is how I'm making it integrate so nicely with Arduino), it's going to take some tricky state machine logic to manage the card's state. When I start putting in the ability to access the card through a filesystem layer from your code on the Teensy, some tricky locking and media access management is going to be needed, down to the lowest levels. I imagine that is going to take time to write and debug.

    So, like all software, who knows how long it'll take?! There will be lots and lots of bugs releases, I'm sure.

    While I'm really more focused on apps like data logging, really from a technical point of view, the Ducky project is a great test because raw media access to USB with little or no media support (yet) from the Teensy-based code is actually useful. (though to be honest, I'm not a networking or security guy and I do hope everyone here is using this stuff responsibly) Really, user feedback, and especially well written bug reports, really, really help. So if you're jonesing for Micro SD card support but not into low level device driver coding, even just trying out the existing code and keeping a watchful eye for anything strange really helps.

    For the next few days, I'm going to take a little break from SCSI commands and sense codes, USB mass storage bulk only transport protocol, FAT filesystem, and worrying about individual bytes and instruction cycles! I do most of this coding in C+asm and then bring it over into Teensyduino once it's stable. Using Arduino again reminded me of its bugs that really annoy me. I put them on my to-do list, so I think I'm going to take a few days off and do relatively easy java coding to fix those damn Arduino bugs!

  8. Would you believe the "arduino language" is actually just C++? It's true. Ok, there is just a tiny bit of preprocessing which tries to make function prototypes for you automatically, and includes an extra header to automatically define all those easy-to-use library functions, but otherwise everything you type is just going right into gcc (g++ actually).

    When you write Keyboard.print(), "Keyboard" is just a C++ object, which inherits the "print" method from a base printing class, where Keyboard provides the low-level I/O to send the bytes as HID keyboard events instead.

    Nobody actually tell most Arduino users this, because C++ scares them, but they're coding in C++ anyways!

    But the Arduino text is rather rather lame.

    When I try to compile it I get loads of errors.

    Of all the forums I'd expect to see someone complain about error messages but not actually copy the actual message.....

    another hint -- try ALSO posting the actual code you're compiling, and maybe while you're at it mention which operating system and version of the software you're using!

  9. I've been working on USB mass storage, so far with the unused space in the chip for media. On Teensy++ it's writable. On Teensy it's read-only. I just got it working on Teensy++ yesterday, though it still fails a couple of the USB-IF compliance tests, but seems to work fine on WinXP, OS-X 10.5 and Ubuntu 9.04. Today I'm writing a utility to package up files into a minimal FAT12 filesystem and merge it into compiler's ELF output before the final HEX file is produced and downloaded, so for Teensy you can have something more interesting than blank, read-only media. Next week, I'm going to add code to support a SD flash card instead of internal memory. Alpha/beta test versions will be appearing soon. Eventually I'm going to add a filesystem layer and arbitration between the Teensy's code and the PC's access. My main goal is enabling data collecting apps on Teensy, which need a lot more functionality than simply automating PC input.

    On Teensy with 31.5K memory, the filesystem overhead might be similar to base64, though it should be a lot faster! The USB mass storage code adds about 2K and a minimal FAT12 filesystem has 2.5K overhead (MBR, Vol ID, 2 FATs, root dir).

    Of course, if you want to maximize on-chip storage, you would just store the code in binary and convert to base64 on the fly. On AVR chips, to directly use the flash memory, you need to declare the array with PROGMEM and read it with pgm_read_byte(). Yes, that's annoying, but it's the way the avr-gcc authors decided to implement it. The above code actually allocates "program" in RAM, and the C runtime startup code copies it from flash into RAM before the program starts. If it gets much bigger than 2K on Teensy, you'll run out of RAM and crash. Using PROGMEM and pgm_read_byte() will let you use up to 64k flash.

  10. Is there a way to quickly get the operating system the teensy is connected to?

    Not easily or directly. But much like TCP/IP fingerprinting, there are subtle differences between the various operating systems which might be recognizable.

    For example, you could probably tell windows vs macos vs linux by just recording a log of which endpoint0 messages arrive, and perhaps their relative timing (eg, use timer1 in 16 bit CTC mode and capture the value for each logged message).

    Recently I've been working on a USB mass storage example. The specific SCSI commands each operating system sends are very different, at least while starting the driver and reading the partition table. For example, Windows XP sends command 0x23 right after the 1st inquiry, but linux and macos never use 0x23. If the WP bit indicates the card is writable, macos is the only system that immediately writes things like a .Trashes directory, but linux and windows immediately write stuff (at least clean, default installs don't anyway).

    The HID drivers are pretty similar on all 3 systems, but I'm pretty sure if you intentionally gave wrong responses, there would be detectable differences in the ways each system handles certain situations and recovers.

    Of course, this is some fairly advanced hacking on the low-level USB code. It's all available to be edited, though you'll need quite a bit of knowledge about USB. A USB protocol analyzer (eg, beagle12) would help, but at least a good USB packet sniffer program would probably suffice.

    Then again, maybe just a simple array with code storing the first several dozen USB events/messages might give enough info. I really hope someone tries this. There are so many interesting things like this, which so far nobody seems to have attempted and published their results.

  11. Depends if HID keyboard even differentiate between them.

    I would set up a USB keyboard and sniff the traffic (Couple of programs around to do this, some VM's do it too.) under 4 different scenarios. (Same sentence for example.)

    1. Lowercase

    2. Uppercase (holding down shift)

    3. Caps lock on without shift

    4. Caps lock on while holding shift.

    Even if there are codes there that aren't in the libraries, it would be trivially easy to add them. (If not boring.)

    There no need to go to the trouble of reverse engineering, since the HID key codes are a published standard. Here's the official document.

    http://www.usb.org/developers/devclass_docs/Hut1_12.pdf

    The keyboard codes are in chapter 10, starting on page 53.

    It's also worth mentioning the HID report descriptor, found inside your Arduino directory at hardware/teensy/cores/teensy_hid/usb.c starting on line 77, claims the 8 bytes sent will encode usage numbers 224 to 231 (control, shift, alt, gui; both left and right) in the first 8 bit field, followed by 8 unused bits, and then 6 bytes encoding usage numbers 0 to 104. If you want to send codes greater than 104, this bit should be edited:

            0x15, 0x00,          //   Logical Minimum (0),
            0x25, 0x68,          //   Logical Maximum(104),
            0x05, 0x07,          //   Usage Page (Key Codes),
            0x19, 0x00,          //   Usage Minimum (0),
            0x29, 0x68,          //   Usage Maximum (104),
            0x81, 0x00,          //   Input (Data, Array),
    

    Change the two 0x68 to whatever maximum usage code you want.

    The format itself, 8 bits for the modifier keys, 8 reserved bits, then 6 bytes for the normal keys is called the "boot protocol". Most PC bios hard code this format, so they do not need to read the HID report descriptor. Below, you'll find the "bInterfaceSubClass" field is set to inform the host this keyboard implements the boot protocol, so it's compatible with your bios before the operating system is loaded.

    In theory, you could change bInterfaceSubClass to 0 and create your own packet format, and document it with the HID report descriptor. You could do things like switch to a larger packet size to send more than 6 keys at once. In fact, you could switch to a 16 byte packet and dedicate a bit to every single usage code. As long as the HID report descriptor properly specifies your format, at least in theory, the operating system should use it. (but in practice, with windows people have found doing strange things sometimes will crash the entire HID driver in Windows.... best to use either Linux or at least a PS2 keyboard and mouse if you must develop on Windows!)

    But no matter what you change in the report descriptor, ultimately you're going to map data in the HID report (aka. USB packet) to those usage codes in chapter 10. There simply aren't separate codes for uppercase and lowercase, and of course they codes are nothing like ASCII, so subtracting 32 would be pointless (and would integer underflow, since the A-Z codes are 4 to 29). How the host's HID keyboard driver interprets those codes depends on the presence of other codes, like 225 and 229, and its internal state, likely influenced by codes like 57.

    A really interesting experiment might be to create a HID device that resembles something definitely not a keyboard, where bInterfaceSubClass and bInterfaceProtocol are set to 0, and the HID report descriptor top level usage is not set to 1 (generic desktop) and the top level usage page is not set to 6 (keyboard)... but inside the descriptor define some data fields that map to usage page 7 (key codes, chapter 10). I wonder which operating systems would route those codes through as keystrokes?

    That's probably way more than you ever wanted to think about low-level HID keyboard usage codes, but then if you're going to use the low-level API that gives you direct control over the raw USB communication, you've got to play by the codes that the driver receiving those messages expects.

    Working in ASCII is a lot easier, and that's why I wrote Keyboard.print(). Of course, all it does is translate ASCII into those codes. If you want to hack on that, it's available inside hardware/teensy/cores/teensy_hid/usb_api.cpp

  12. move the mouse a few inches every 10-30 seconds, send a letter or two every 20-40 seconds.

    Mouse.move(-5, 3);

    delay(30000); // in ms, 30 sec

    Keyboard.print("a1");

    delay(20000);

    get it to generate random numbers (which I'm sure you can.)

    Mouse.move(random(-5, 5), random(-4, 4));

    delay(10000 + random(20000));

    Keyboard.print('a' + (char)random(26));

    delay(20000 + random(20000));

    It should be really easy

    http://arduino.cc/en/Reference/Delay

    http://arduino.cc/en/Reference/Random

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

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

  13. I know it's possible to write a HID blacklist/whitelist but since I don't know enough about it I'm finding it a little tricky.

    It may be possible (eg, udev rules on modern linux), but that won't be very effective.

    Everything the host (PC, Mac, etc) can know about the USB device is under the device's control. In Teensy (and virtually all microcontrollers with USB), code produces all that data. For example, if you use Arduino/Teensyduino, this code is automatically built into the executable image:

    #define VENDOR_ID               0x16C0
    #define PRODUCT_ID              0x0482
    
    static 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
            0x00, 0x01,                             // bcdDevice
    

    It's pretty trivial, even if you have no programming skill, to just find these files, named "usb.c" and "usb_private.h" and edit the USB descriptor data to anything you want.

    Less trivial, but not very difficult if you know C, would be changing the code which transmits this data. Instead of reading it from a static array in memory, certain numbers like vendor id, product id, bcdDevice could be created at random, or tried from a list of known common keyboards, or any other algorithm you can craft.

    Also possible, but definitely not trivial, would be making use of the detach capability. Most USB devices have a resistor soldered to one of the data lines, which is how the PC knows the device is present. There isn't a physical switch in the connector, it's that resistor which signals a device is plugged in. In the AVR USB chip on Teensy, that resistor is under software control. In fact, every time you reprogram Teensy, that resistor is disconnected and then reconnected, which is to your PC looks like the old device was physically unplugged, and then moments later a completely new device (implementing the ability to download your new code) gets connected. After your code cownload, the same thing happens again. That's how you can so easily try new USB devices with Teensy.... every time you reboot your code, your machine believes the device was physically unplugged and then a new device gets plugged in.

    With the detach capability under your code's control, if you don't get the desired results, you could just detach and try again (maybe much later... the PC can't tell you're still physically present), perhaps with new randomly generated ID numbers or some other strategy.

    A whitelist/blacklist defense just doesn't have any trustable data available.

    Ultimately, blind trust in HID keyboards is the weakness. Perhaps a solution would might involve a one-time authorization process for a new keyboard? But who do you trust for user input to authorize a new keyboard? The USB HID mouse?!?

    And if an attacker has physical access, what's to stop them from momentarily unplugging the trusted keyboard and using another machine to capture all its USB descriptors? For example, my "ID 05AC:0220 Apple, Inc. Aluminum Keyboard" returns an empty field for the optional USB serial number. Even if it did have a serial number, it's right there to read and copy.

    USB HID doesn't have any challenge/response authentication, so all trusted data could be easily captured. Perhaps public key signature capability to prove a device's unique identity would give you something useful to trust the device hasn't been copied. It seems pretty unlikely keyboards will get that class of hardware anyday soon!

    Security is difficult.... much harder than just designing working USB devices.

  14. A MicroSD breakout board would be better.

    Would you believe I just sent in PCB files for a prototype. It's half the size of the Teensy, meant to mount above or below using the first six pins, just above and below the USB connector.

    If everything goes perfectly, the soonest they could be manufactured and available in any quantity would be early to mid May.

    Is there ever a way to set a device to be 2 USB devices? a HID and a Mass Storage?

    The short answer: Yes.

    Now, for the long answer......

    USB has a lot of terminology which has very specific meaning. You probably know "host" is the PC, or whatever has the "A type" connector, and "device" is whatever has the "B type" connector. There can be only 1 host, which controls everything, and of course many devices. Because the functionality is completely different between a host and the devices, they used different shape connectors, so it's (supposed to be) impossible to plug devices together without a host, or more than 1 host connected together, even if someone makes a "gender changer".

    With USB a "device", there are "configurations", "interfaces" and "endpoints". These are probably less familiar USB terms, unless you've designed a USB device or you just happen to like reading the 650 page USB 2.0 spec and the dozens of supplementary documents, adding up the thousands of pages.

    Endpoints are similar to port numbers in TCP/IP networking. Just like how a server can have port 80 for http, port 25 for smtp, port 22 for ssh, and so on, a USB device can have many endpoints, each used for a specific purpose.

    Similar to how IP-based networking has different protocols, like TCP and UDP, in USB there are 4 endpoint types, called Control, Bulk, Interrupt, and Isychronous. Control is a datagram protocol, with an extra 8 byte header, which allows the datagrams to be directed to a diverse number of logical targets within the device. The other three are unidirectional streaming protocols, similar to TCP, except of course TCP is bidirectional, so you need two endpoints for both directions. Like port numbers in TCP and UDP, endpoints are numbered 0 to 15. Endpoint 0 is always control type. Endpoints 1 to 15 can be any other types. (Teensy's hardware supports endpoints 1 to 6)

    USB has a concept of "interfaces". An interface is basically just a group of endpoints, which together are intended for some purpose. While there's no direct equivalent in TCP/IP networking, you can think of FTP's "interface" (in active mode) as two TCP ports. Many interfaces uses 2 endpoints, one for sending and one for receiving. Sometimes more than 2 are needed, because the 3 non-control endpoint types have very different bandwidth and timing allocation. Sometimes only 1 is needed, such as most HID interfaces use a single endpoint for sending to the host, and for the very infrequent data from the host to HID (eg, keyboard LEDs), a control packet is sent on endpoint 0 (remember, the extra 8 byte header is very flexible and can specify packets to or from lots of locations, including of course interfaces).

    I skipped "configurations", because they aren't so interesting. Basically, they're used in devices like webcams, where each configuration has different specs for its endpoints, usually offering lower bandwidth requirements. If the host knows there isn't much bandwidth available, it can choose one of the lower configurations. This happens before any device drivers are loaded by the operating system.

    When you first plug in a USB device, the host uses endpoint 0 to read a bunch of binary data called "descriptors", which inform it about the device and all its configurations, interfaces and endpoints, and sometimes other optional data. Then it chooses a configuration (most devices have only 1). Then it loads drivers.

    A windows (or mac, or linux) driver can be associated with the entire device, or with only 1 interface. In some cases, a driver can use more than 1 interface, but not the whole device (though Microsoft only recently supported this in XP-SP3 and Vista SP1, and Apple basically doesn't support it at all, so multi-interface driver associations are very rare).

    Most devices with a proprietary driver from the manufacturer use whole-device driver association. The USB device has a "Vendor ID" which is assigned by the USB-IF (for a $2500 fee), and the vendor gives each product a unique "Product ID". They can also assign a revision code. Windows, Linux, and Mac OS-X first look at the VID/PID/Rev and then VID/PID. If a driver matches those numbers, it will load that driver to control the entire device.

    Drivers can also be associated with just a single interface. Commonly single-interface drivers are provided with the operating system, and intended for the standardized USB device classes.

    USB has many "Device Classes", such as HID and Mass Storage (though Microsoft sadly doesn't support most of them, other than HID and Mass Storage). These classes specify how an interface works, including how many and what types of endpoints it must have and the format of the data send/received on each, what additional messages it send or receives using endpoint 0, any additional descriptor data for detecting the details specific to that interface.

    So, the long answer is yes, when there are multiple interfaces, it's called a "composite device" in USB lingo. Even though it's a single device, it contains multiple interface, each of which gets its own driver loaded by the operating system. To the end users, it's as if multiple USB devices were plugged in. But to us, those involved in development of such devices, terminology like "composite device" and the difference between a driver associating with the whole device versus only a single interface are important distinctions.

  15. USB "interrupt" type endpoints have a descriptor field called "bInterval", which specifies the maximum (slowest) rate the host is supposed to poll them for new data. The number represents the maximum number of USB frames between initiating a USB transaction to check for new data. There are 1000 frames per second. According to the USB spec, the host is allowed to poll more frequently, and the device must allow polling at any speed, though returning a NAK is of course allowed when no data is to be sent. (the 650 page USB 2.0 spec says a lot more, but these are the main points relevant to this issue).

    Teensyduino sets bInterval to 1 for the keyboard. So according to the USB spec, it should never be polled slower than 1000 times per second.

    However, Microsoft is not known for adhering closely to standards! At least 1 knowledgeable person has told me (and claims to have verified) that some Windows systems will poll once every 8 frames in some cases, even if bInterval says they must poll faster. Of course, this is completely disregarding the USB standard, and there doesn't seem to be any documentation about it. Well, maybe there is? I've also heard hints that other unrelated things, maybe under the USB device's control, can influence if Microsoft's driver will honor the bInterval requirement or default to 125 Hz polling.

    I would really like to explore this further, and if possible modify the code so as many Windows systems as possible will use the correct polling speed. If you have a windows system that polls slow, please let me know.

  16. Actually, I've been planning to add more device types in the next version of Teensyduino. Once that's released (there will be beta tests....), implementing this using the Arudino IDE will be as easy as just selecting it from the Tools menu.

    In addition to a SD card connected to the 4 SPI pins, I also plan to support using the unused flash memory as a tiny read-only volume. You can expect example and documentation to be rough at first and become better over time....

    Yes, it'll be a composite device which also provides a HID keyboard interface. Everything already written with Keyboard.print(), Keyboard.send_now(), etc should work when changing to this other device type.

×
×
  • Create New...