Announcing RAD 0.2: Software Serial Support, Inline Assembler, and More!

16 March, 2008

I'm proud to announce a new release of the Ruby Arduino Development gem (RAD)! This release brings two major new features (software serial serial support and inline assembler), a major revamping of the hardware serial library, and a raft of other small features and bug fixes. I've got lots of details below, but first I wanted to thank Scott Windsor who contributed the software serial support as well as all the other people who wrote in with bug reports, ideas, and comments, and of course all the members of the RAD core team. It's exciting to see RAD starting to support physical computing scenarios I've never had the hardware to work with myself.

Inline Assembler

I'm starting with this new feature not because it's necessarily the most import or most broadly useful, but just because I think it's the sexiest (which probably says something sick about me, but there you go)! RAD now offers a class method to all sub-classes of ArduinoSketch for writing routines in assembly language. You give the method three arguments: the name of the routine, its signature, and the assembly code you'd like to consitute its body. Here's an example script showing the method in action:

class AssemblerTest < ArduinoSketch
serial_begin
def loop
serial_println product(10,4)
end
assembler( :product, "int product(int a, int b);",
<<-CODE
product:
mov r18,r24 ; move a to another register
ldi r24,0 ; clear running sum, used to coalesce product
ldi r25,0 ; sum = 0
.loop:
tst r18 ; is a = 0? if so, we're done
breq .end
mov r19,r18 ; copy a
andi r19,1 ; is a % 2 == 0
breq .skip
add r24,r22 ; add b to sum
adc r25,r23
.skip:
lsr r18 ; divide a by 2
clc
rol r22 ; multiply b by 2
rol r23
rjmp .loop
.end:
ret
.size product, .-product
CODE
)
end

As you can see, the body of the assembly code is simply passed as a string to the 'assembler' method. In this case, all I'm doing is implementing multiplication of two integers. RAD takes your assembly code, adds some architecture-specific headers and other boilerplate, writes it to a source file, and makes sure that the compiler knows to compile it into object code and link it into your project during the build process.

I'm an asm newbie and I found that the hardest part of getting started learning the stuff was bootstrapping an environment where you could actually run your code and see the results. Hopefully this addition to RAD will smooth that process for people in a similar situation. Now all you've got to do is put your assembly code in an ArduinoSketch model like the one above, upload it to your Arduino, and read the board's serial output (for example by attaching to it with screen). You can be writing (and debugging) your first assembler routines in seconds.

It's worth noting that this feature wouldn't have been possible without Reed College math professor Jim Fix teaching me the basics of AVR assembler and the avr-gcc build process. Thanks, Jim!

Software Serial Support

This feature came in as a patch from Scott Windsor. Scott was working on hooking up his Boarduino (an Arduino-compatible clone from Lady Ada) to a GPS module and a Serial LCD both of which require serial connections. Thankfully, Arduino provides a SoftwareSerial library for doing serial connection on any of the board's digital i/o pins. Scott's patch gives you really convenient access to this functionality, thusly:

class MySketch < ArduinoSketch
output_pin 13, :as => :led
software_serial 6, 7, :as => :gps
serial_begin
def loop
digitalWrite(led, true)
serial_print(gps.read)
end
end

As you can see, he configures ports 6 and 7 as a software seria connetion called "gps" and then he simply says "gps.read" to read the data his device is sending over that connection. Scott also implemented "print" and "println" methods for outputting to serial-connected devices such as his LCD, which work in the same way.

I was especially psyched to see this patch since I haven't gotten to work with any devices that communicate over software serial yet, which had meant that I couldn't really test and add this functionality myself. I'm planning to get my hands on some of that soon and so I'm excited to play with the clean simple API Scott's provided here.

Fixed Hardware Serial Support

In previous releases of RAD, hardware serial support had been, uh, perfunctory. The trouble stemmed from the wide variety of functionality hidden behind Arduino's elegant serial API. Serial.read(), Serial.print(), and their brethren do subtle things to act correctly when called with different arguments, from integers to individual characters to full strings (or arrays of characters, as C would have it). The result was that RAD's versions of these methods would sometimes do strange things like returning ASCII-value integers when sent characters. That should no longer be happening. For example if your run the following sketch:

class SlowTypewriter < ArduinoSketch
serial_begin
def loop
serial_print serial_read
end
end

and attach to the serial output with screen, you'll see the characters you type successfully roundtripping to the Arduino and coming back with their encoding preserved. It's the world's slowest typewriter!

A Panoply of Small Features, Tweaks and Bug Fixes

Including, but not limited to:

  • Made 'rake make:upload' default to skipping the prompt for reseting the board. The older NG boards that require the reset are getting rare and I recently modded mine to no longer require it. The reset is still available as an option by editing the "physical_reset" option in config/hardware.yml.
  • Added support for HIGH/LOW and ON/OFF constants. This is a nice feature of the Arduino API that I hadn't been able to sneak throug the RubyToC translation stage until now.
  • Support for variables that are not local to the loop method. It's a common desire to be able to initialize variables outside of the loop method of a sketch so that they will not be constantly re-initialized with each run, for example to define environmental constants or initialize counters. Since RAD replaces the Arduino setup functions and global declarations with ArduinoSketch class methods (such as output_pin), this wasn't previously possible. As of this release, you can use the 'vars' method to initialize variables in this scope thusly:

    class VarTest < ArduinoSketch
    vars :a => :int, :b => 7, :c => "hello"
    def loop
    a = 1
    serial_print a
    serial_print b
    serial_println c
    end
    end

    This will produce output like:

    17hello
    17hello
    17hello
    17hello
    [...]
    

    As you can see, the vars method takes a hash where each key is the name of the variable you'd like to initialize and the value and be either a type (rendered as a symbol, i.e. ":int"), or an actual value if you want the var to be initialized to something (i.e. "hello").

  • Changed default Arduino location to be /Applications/arduino-00010, which seems to be where most people (now including me) have it.
  • Plus too many small bug fixes to list here!

What's Next?

There's all kinds of things big and small on the immediate roadmap for RAD. There's the administrative: putting the RAD source on Git Hub, adding sorely needed documentation to the core ArduinoSketch methods, organizing an email list for the growing group of people wanting to be kept up-to-date on the project, etc. There's the lofty: I've got the beginnings of a plan for putting building a testing and simulation framework on top of RAD that would let you run your sketch against a software version of the Arduino hardware while developing (with a visualization/interactive app built on Shoes!), etc.

And then there's your contribution: send me your patches and RAD can become whatever your want it to! As always, if you've got any questions, ideas for contributions, or run into any troubles running RAD, feel free to email me: greg [dot] borenstein [at] gmail [dot] com or comment here; I'd especially love to see/hear what projects people are building with RAD. Happy hacking!

Tagged: , , , , , , , , ,