00:00:09.760
All right, so I'm Mike Hewner, and I'll talk to you about something that should be familiar to most of you.
00:00:15.040
You may need to permit me a little bit of Unix nerd humor here. If you look into any big Unix nerd's home directory and do something like 'ls .rc', you'll see that it's basically like a badge of honor. If you don't have 12 of these suckers in there, you are not cool.
00:00:25.680
If you examine one of these rc files, each line often has some sort of history to it—like the day they were supposed to be working on a project but instead spent eight hours customizing the perfect Zsh prompt.
00:00:31.679
You know, each one may come from someone else—like this one from an Australian at a conference. Hopefully, I’ll get a chance to trade some tips with you guys later on today. But all these files show how nerds often love customizing their stuff. You need everything tricked out, shiny, and polished. Just look how much work has gone into this thing! I can't even imagine the various processes and chemicals involved to get those wheels shiny, but one thing’s for sure: this sort of customization is a classic nerd thing.
00:01:07.600
However, I’ve felt recently that this kind of customization is a bit fraught with peril because, after a while, when you shine up the wheels and get everything working smoothly, it seems like you run out of things to customize.
00:01:18.399
Yes, you might have a few spam emails come in, which probably means you need to add a few lines to your procmail.rc, and maybe you could find a couple of Vim plug-ins that could revolutionize your life, but it's hard to envision what they might do.
00:01:29.920
Then, if you're an Emacs user, you've probably reached the point where you never leave Emacs for any reason. You might even have a command to use the restroom. Everything starts feeling pretty good and normal, but soon you realize you're done, and your computer seems to work great. But the question becomes: what do you do now? You might notice people hanging out at your house, possibly related to you. Maybe you could consider talking to them—apparently, religion is good. Ruby is probably something you know about to some extent.
00:02:03.600
Or you could take the approach of saying, 'Screw all that! I'm going to make something that essentially works and add a fishbowl to it.' So, in my opinion, you're not done. What you might not realize is that while you've done all these amazing customizations on the screen of your computer, there's still so much more you could be doing in the actual physical world.
00:02:29.280
Instead of having shiny, perfect devices, you could incorporate more bizarre gadgets, which might seem odd at first. But you could create something unique, like a USB device that lets you switch between desktops just by twiddling it around. That’s the concept I’m presenting here.
00:02:43.680
This isn't about USB for hardcore hardware enthusiasts who are building devices that normal people actually want. No, this is USB for hackers who want to take that mouse they have in their closet and turn it into something that plays a tune when you jiggle it around or something equally fun. This isn’t a project for work; it’s just for the fun of it.
00:03:05.920
The idea is that you can control USB devices using Ruby. I mean, Bluetooth would be even cooler, but I didn’t have time to look into that. USB devices are my focus because the main reason is that if your primary source of hardware comes from, say, the Best Buy bargain bin—you can pretty much bank on it being cheap and available.
00:03:29.920
Also, USB devices are self-describing. For instance, when you plug that mouse from the bargain bin into your system, it’s quite satisfying when your operating system recognizes it as a 'Japanese character mouse' or whatever, and you think, ‘Good, I think it’s going to happen for me.’ Clearly, there’s something in there that lets the device know what it is.
00:03:45.440
Those of you who remember back to the days before USB devices will recall the hassle of plugging in a serial mouse and then having to search for the right driver. You would plug it in, and it wouldn’t work properly, leading to countless uninstalls and reinstalls, only for it still to malfunction. Thankfully, that’s no longer the case with USB. These devices can convey a lot of information about themselves, and particularly Human Interface Devices (HID), like your USB printer or a thumb drive, can tell your computer exactly what they are.
00:04:14.560
Now, HID devices can often have a lot of strange features and are quite flexible—sometimes non-standard—and surprisingly, still functional. Moreover, while this next part doesn’t relate directly to Ruby, you can actually build your own USB devices. I’ll touch on that later, but I assure you it is simple enough that even someone like me can manage the soldering required.
00:04:47.680
The USB specification comes with various subspecifications. Just like any good spec, there are subspecs deep within subspecs. The main USB spec addresses how devices plug into hubs, whether they are powered or not, and introduces the concept of configurations. If anyone has a USB device that actually uses configurations, I want to hear from you because I have never found one that does, nor have I tested this aspect of Ruby USB.
00:05:14.599
Configurations can dictate a device's behavior based on whether it receives external power or not, and it can respond differently based on its powered status. Within a USB device definition, you can have multiple interfaces and more than one configuration. As examples, you can have a thumb drive and a salad shooter on a single USB device—where one conforms to a thumb drive specification and the other follows the salad shooter spec.
00:05:50.560
The most interesting aspect of USB that I’ll be discussing today pertains to HID. As I mentioned, it’s very flexible. If you want to know more, please check out my website at rubyusb.technofetish.net, where you’ll find all the links for this presentation along with all the documents I reference.
00:06:08.720
The goal for Human Interface Devices (HID) has always puzzled me due to its design choices at the specification level. HID devices send data in somewhat unconventional formats, but beforehand, they provide a description of the data they will send. You’d think any device could benefit from that finessed feature, but it strangely appears to be a quirk of the HID spec. It allows for interesting details regarding the format in which the data will be sent, which is beneficial.
00:06:35.760
This feature is significant because when you connect your interface device to your computer and then request data from it with Ruby, it first looks at that handy little document detailing everything about the data sent, allowing Ruby to interpret it accurately. For instance, you can analyze the seven different numbers the device sent, what they mean, and how they correspond to certain functions.
00:07:06.720
Let’s look at how you used to reverse-engineer some obscure device by staring at a random stream of binary data on your screen. You'd see a string of zeros and wonder what was being pressed at that exact moment. The disconnect was often baffling.
00:07:21.440
Imagine an HID's data stream on the far left indicating left mouse button activity: that magic number denotes the left mouse button you recognize, which is vital for clicking icons. Then there are specifics like the chaff release button for joysticks, which, believe it or not, is included in the HID spec. It's great to know that all manufacturers conform to this standard, even if I doubt many people utilize them.
00:07:52.880
However, the specs can get quite complicated. For instance, I can indicate groups of numbers and clarify their meanings through annotations—though, unfortunately, they don’t seem accessible through any known programmer interface—I’ve searched and never discovered how to access those annotations. Often you find little more than overwhelming voids of zeros.
00:08:27.680
Going deeper into USB specs, you might find what’s coming back, such as unexpected units or surprising ranges of values being shared without the specs indicating their significance. We can even mention the presence of negative numbers that would pose a challenge to decipher during reverse engineering, but having a spec helps mitigate this frustration.
00:08:43.120
Let’s address how to handle USB devices via Ruby. Below, you can see an example of a mouse descriptor’s beginning, expressed in hexadecimal code. It is essential to understand various terms I'd like to touch upon if you ever decide to hack on USB devices.
00:09:10.560
In terms of usage, there’s something called usage page—the one that indicates what types of devices people might want to look for—for instance, the left mouse button usage might have a distinct designation as part of this. Meanwhile, the keyboard key usage belongs to a similar categorization.
00:09:36.720
The USB spec introduces collections for grouping multiple functions and defines logical minimums and maximums—useful for range specifications. Additionally, the report count and report size give you insight into how the data is structured in a given context. You may find this detail-oriented, but Ruby USB helps to figure all of this out for you, preventing the need to struggle with complex codes.
00:10:06.960
So, now let’s get into some more technical details. When you want to work with these devices, there are a few necessary steps you must take. Obviously, you have to load your libraries carefully—it can be somewhat tricky, especially when you also need elevated permissions due to Linux’s USB device ownership criteria.
00:10:34.080
You may need to run prompts with pseudo commands to ensure proper permission and access to the devices. Once you manage that, you can get a list of connected USB devices using Ruby—generating outputs with descriptions of each device connected. For instance, I had an optical mouse and a keyboard connected, alongside a USB hub.
00:10:58.560
Following that, you can use vendor and product IDs to uniquely identify each connected device. Working off those parameters, you can retrieve information like the device's name and manufacturer. This is where it gets interesting; you’re also able to check if it’s a HID by evaluating the device’s configurations.
00:11:24.560
The magic inquiry begins when I grab my optical mouse, which Microsoft calls a basic optical mouse, and proceed to get the first interface. This is mainly for brevity since the reality is you would typically inspect all interfaces of a device to locate the specific HID interface it implements.
00:11:49.679
In practice, most devices typically only implement one interface; however, theoretically speaking, devices can certainly be multifaceted. We haven’t encountered performance issues as a general rule because system-level APIs and specifications govern how an HID functions. But remember, it’s crucial to detach the device from the kernel before proceeding with any interesting actions.
00:12:12.480
Once you detach the device from the kernel, keep in mind that it won’t automatically reattach, leading to situations where your mouse or trackpad may stop functioning. You would need to unplug and replug to refresh that connection.
00:12:38.960
After detaching, you can assess the device’s functionality by querying all input usages associated with it. You can effortlessly get a list of functionalities—each of which corresponds to different buttons or features present on the device. You can imagine picking a keyboard and realizing that it supports an extensive array of keys.
00:13:07.680
Let’s not forget about potential interruptions. It’s imperative to initiate listening for data from your USB device so that when it begins receiving input, you’ll have access to that exciting binary string data returned, showing you parameters like button activity—what’s on, off, coordinates, and whatnot.
00:13:32.799
I’ll demonstrate with my latest USB project, a surprisingly ghetto remote control I discovered at a thrift store, labeled as a Toshiba LED Control Module. The purpose of this device remains unclear to me, but with some creative problem-solving, I was able to reverse-engineer its communication protocol in about an hour and integrate that with VLC to function as a remote.
00:14:03.119
It’s important to note that the following code segment shows the USB aspects, where I locate the device, get its endpoint, detach it from the kernel, and listen for HID interrupts while successfully retrieving button codes to operate commands just as I intended.
00:14:36.799
Using VLC—a video player ideal for Linux and very Unix-like—I enjoy watching anime while easily controlling the volume and playback through the custom remote, showing just how effectively such integrations can work.
00:15:06.240
Addressing the operational layers of my setup helps clarify how it functions. I can describe it as a three-layer system. It begins with Lib USB, a cross-platform USB library designed primarily for Unix-like systems, including Mac OS X.
00:15:27.440
However, keep one thing in mind: Windows versions may be a bit quirky! When interfacing with C code, you usually think of reliable, solid foundational layers, but Ruby plus Lib USB results in some erratic behavior due to low-level operations.
00:15:52.480
This leads us to an aspect of the interface which could sometimes reveal unpredictable timeouts—an important detail since Ruby users expect a stable interface. I’ve primarily tested this on Linux systems, which creates complications if someone were to attempt this on different environments.
00:16:14.399
In reviewing the interface, you’ll naturally want to see how it accommodates querying a USB device for its characteristics by filling up its C structs to provide data and, ideally, navigate the complexity more smoothly.
00:16:46.799
I’ll share one significant downside of developing this; I wrote my HID parser in C++ thinking I’d create something reusable, but I learned it became an enormous pain while interfacing with Ruby.
00:17:07.679
Had I to do it again, I’d build it purely in Ruby for a more refined interface accessing USB’s report descriptor objects. These describe the different potential data types—a critical feature but managing devices in C++ created complexities beyond my expectations.
00:17:31.199
Among the lessons learned—always implement unit tests! This should be standard practice for any tech and ensures that as you add functionality, the core features remain intact. When you’re implementing without ample resources, you’ll inevitably encounter challenges.
00:17:55.280
If you want to implement unique setups without strict USB nuances, I’d recommend exploring the EVDev framework for Ruby, which is Linux-based and conveys exceptional performance. However, it lacks compatibility with other operating systems.
00:18:25.440
Lastly, I really value collecting data from USB devices and using that information in a constructive manner, whether that’s to manipulate settings or enable their features as you see fit. We still have a lot of advancements left ahead in terms of functionality.
00:18:54.800
While I haven’t worked extensively with Ruby threads in multi-threaded programs—my experience has shown listening for interrupts can leverage threads safely—there are bound to be bugs unless extensively tested.
00:19:13.440
It’s all not just theory; it's got practical applications you've likely used every single day. I even explored a quirky idea once of gluing two keyboards together—one in insert mode and one not.
00:19:34.880
I was curious about the complexity of input but ended up with two keyboards dominating my desk space. Despite its goofiness, it was perfectly functional—and you can always experiment with configurations.
00:19:56.240
What I strive for next is efficiency, perhaps developing customized devices or programming new ones with flexible features, especially if they can easily integrate with Ruby. Creating DIY USB devices is thrilling, and who knows what innovative functionalities we could see emerge!
00:20:30.000
If anyone feels inclined to help me brainstorm or work on a USB chainsaw project, I’m up for it! I’m always keen on using AVR programming to create fantastic USB devices that work with Unix.
00:20:59.680
Though I faced some hiccups during soldering my USB device, I still see potential in future integrations with new hardware. Please anticipate even more exciting things to come as I continue to develop and share projects relating to Ruby and USB interfacing.
00:21:25.200
Thank you for your time, and feel free to ask any questions about what we’ve discussed today or any projects you might have in mind. I'm happy to provide suggestions or insights if you have ideas you want to run through!
00:21:57.120
I realized that utilizing these systems isn’t solely about creating fun projects; it’s about embracing creativity and keeping aspirations alive through technology—it’s what drives the community of hackers and makers forward.