I’ve spent a good deal of time lately completely rearranging the Keyglove controller code into a whole bunch of logically separated modular units to make everything more manageable. I know there is still plenty more code to write before all of the desired features are working, but even without that code it was becoming difficult to navigate and edit efficiently. When I brought the LUFA library into things and wrapped it around the existing Arduino sketch, I knew I had to do something drastic. So, here’s an overview of the changes.
- Make all
#definedconstants follow a recognizable pattern.
I can’t stand inconsistencies in my code, whenever I see them. Therefore, instead of having a
#define ENABLE_ADXL345directive and a
#define USE_TEENSY_BOARDdirective and a
#define KGM_RGB_BLINK, I’ve changed them to be consistently named and always include some hint of functionality.
- Change all variable declarations to C99 types.
This was on the recommendation of Dean Camera, the LUFA code author. Instead of using data types like
int, everything has been changed to be specific based on the data that will be stored there, like
uint8_tfor 8-bit unsigned integers or
int16_tfor 16-bit signed integers.
- Add explicit support for more boards than just the Arduino and Teensy.
You might use an Arduino Mega 1280 or 2560, or a different Arduino, or any one of four Teensy boards, or the official Keyglove controller board, or something I haven’t thought of. Which board you use impacts which functionality you can support, and which built-in objects exists (Arduino’s
Serial, or the Teensy’s
Mouse). Being able to specifically say which board you’re using makes it a little easier to write code that will compile under many different hardware configurations.
- Move complicated code out of the main
keyglove.pdesketch file and into task-specific source files.
All of the detailed code for each individual task is broken apart into respective modular source files and task-specific function calls.
- Abstract functional control code away from whatever specific hardware actually being used.
This means that whether you’re using an HMC5843 or an HMC5883L, the
update_motion_magnetometer()function does what you need without needing any changes inside that function. Each hardware module’s
#includefile defines task-specific setup and usage functions. You can only include hardware support files that don’t implement the same functionality, or else you’ll get a compiler error.
- Change debug output print() calls into preprocessor directives for simplicity.
Debug print statements are very helpful, but they take up program memory that is unnecessary for production code. I had previously been surrounding each debug output line or block with
#ifdefs, but this was getting messy. So, I changed them into compiler macros like
DEBUG_PRN_BENCHMARK()that are changed into the correct code if that particular debug flag is enabled, or are removed before compilation otherwise. It’s just a lot cleaner.
I used Gliffy to create a quick flowchart that represents the new program flow structure, which is now very easy to follow with visually if you look at the main
These changes have resulted in code that is significantly easier to understand and edit. Each hardware or software feature is controlled by a
#define directive, so that no matter what your particular Keyglove hardware looks like, you can set the configuration to match, and the compiler will take care of the rest. Using an Arduino Mega? Great. Using a Teensy++ 2.0 board instead? That has its own option. Using the WT12 Bluetooth module, or the USB connector? Those have options too. Using the ADXL345 accelerometer, or the ITG-3200 gyroscope, or the combined MPU-6050 chip? Each has its own option.
This also makes it very easy to write some new code to support a new sensor for testing purposes without actually changing any old code. If the new method works, switching is as easy as using a new
#defined option, while if it doesn’t, then I can revert back to the old methods in a second.
Another major advancement that I’ve made is been learning and implementing Dean Camera’s amazing LUFA framework. This has required learning more about how to write AVR-GCC code, not just Arduino code. Fortunately, for my needs so far, I haven’t needed to learn a lot of the more complicated parts of the AVR functionality, like timers and interrupts. I will have to, I know, but I’m confident that I’ll be able to progressively as the code grows and each new functional need becomes apparent.
The motivation for making this change is two-fold: first, I want to have code that is entirely open-source. The Teensy is amazing, but the bootloader is proprietary, with no indication that will change in the near future. The LUFA project is released under the MIT license, the same as the rest of the Keyglove code. Along these same lines, I’d also rather not tie people into necessarily using the Arduino IDE and/or libraries when the underlying hardware (Atmel AVR AT90USB) can do more than that. Using the Teensyduino add-on isn’t hard with the Teensy, but allowing the whole process to be done via command line and
avrdude is a good feature for anyone likely to want to actually modify the officially published Keyglove code.
Secondly, I wanted to have complete control over the USB functionality of the device. While the most convenient usage of the Keyglove will be wireless, there are many good use cases that involve a USB connection, the most common of which will involve charging and reprogramming. The Teensy’s USB device capabilities currently include keyboard, mouse, and a very recently added joystick capability. It can also enumerate as a virtual serial port. However, I want all four of these things at the same time: serial, keyboard, mouse, and joystick. The Teensy doesn’t do this without internal library modifications.
Strictly speaking, most of the special application of LUFA code that is now powering the prototype Keyglove has required the same modifications that the Teensy code would have, so the LUFA approach probably wasn’t really that much easier. However, by using LUFA instead, I’ve been able to write something all under the MIT license from the ground up instead of modifying an intermediate layer built on top of something proprietary.
Plus, the experience of discovering intricacies of the USB protocol and the HID interface specifications has been amazing. I’ve been able to learn a ton.
LUFA Arduino Wrapper
The Arduino language makes certain things much simpler than they would be in plain AVR-GCC code. Although I don’t want to be tied to the Arduino IDE and libraries, I don’t mind using the language and functions when they make things easier, and I also wanted to avoid “porting” all of my Arduino code into a different codebase that would compile with LUFA. But LUFA doesn’t have all of the Arduino’s libraries! What to do? Create a wrapper, of course!
Now, before you ask: yes, I am aware of the LUFAduino project by the people over at Micropendous. However, their library appears to be built on top of a lot of their other code, and it includes functionality I don’t need, as well as not everything I do need. I wanted a single source/header file set that I could basically drop into a stock LUFA distribution and have it support the basic Arduino functions I need—essentially, digital I/O pin support, USB serial, USB keyboard, USB mouse, USB joystick, I2C, and SPI support. A lot of it is actually working pretty well already. The USB virtual serial, I2C, and SPI support all need work, but so far, the lack of progress has been more a matter of time rather than difficulty. It’s coming along well so far, but I’ll probably need to become a little more familiar with those pesky timers and interrupts to finish the job.
The Keyglove code is up on GitHub for anyone interested in checking it out, contributing, using the ArduinoWrapper code, etc.