Monday, March 28, 2011

Contraption and Horsefly: Beagle Board, Android, AR.drone

Readers who have followed my articles on my Contraption project, a hack that allows a GNU software stack to run along side the Android software stack under a common Linux kernel on the Beagle Board, may have been wondering about my sudden turn into the world of remote controlled helicopters with the AR.drone, a project I call Horsefly. Here's where I tie it all together.

Step one: I hacked the /bin/wifi_setup.sh script on the AR.drone so that it uses a different IP subnet, 192.168.2.0/24, than that of the Palatial Overclock Estate (a.k.a. the Heavily Armed Overclock Compound), 192.168.1.0/24. I described how to do this in Deconstructing the AR.drone: Part 3. Yes, this almost certainly voids the warranty on my drone. Given what violence and indiscretions I've already committed on my unit, I was hardly worried about that at this point. Your mileage of course may vary.

Step two: I dug an old Linksys WET54G WiFi-Ethernet bridge out of the vast Estate storeroom (imagine if you will those last scenes from Raiders of the Last Ark or perhaps Citizen Kane). I configured it to work using my AR.drone's SSID and the new IP subnet, and plugged this bridge into the Estate LAN. This creates a bridge between the Estate subnet and the dedicated AR.drone subnet. The former is a crazy quilt mixture of infrastructure WiFi, PowerLine Ethernet over electrical wiring, and CAT5 directly to the router. The latter is the ad hoc WiFi network for which the AR.drone itself serves as a DHCP server.

Step three: I connected to the Beagle Board running Android via its serial console and configured it to support both IP subnets over a single Ethernet port by just doing an ifconfig eth0:1 192.168.2.1 command. Indeed, I could have configured a USB WiFi dongle on the Beagle Board, but using the WiFi-Ethernet bridge allows any device on the Estate LAN to access the ad hoc network. Below is a screen snapshot of the Android console, made somewhat noisy by the Android stack logging stuff while I was typing.

Configuring Second IP Subnet for Android on Beagle Board

Step four: I brought up the web control panel for the WET54G bridge using the Android browser on the Beagle Board, just as a sanity check.

Linksys WET54G Bridge Configured via Android Browser on Beagle Board

Step five: I powered up the AR.drone, ssh-ed to the Beagle Board from my Mac mini desktop, and from there telnet-ed into the AR.drone, as another sanity check.

SSH to Android on Beagle Board then Telnet to AR.drone

Step six: from my desktop I used adb, the Android Debug Bridge tool that is part of the Android SDK, to install AR.Pro Lite onto the Beagle Board. AR.Pro Lite is an Android app developed by Shell Shrader that controls the AR.drone in a manner very similar to the standard Free Flight iDevice app developed by Parrot, the company that manufactures the AR.drone, and which I have used on my iPad. The Beagle Board was already recognized by the Android SDK USB driver on my desktop, so the install was simply a matter of adb -s 20100720 install 5036861.apk, where 20100720 is the Android serial number of my Beagle Board (which looks suspiciously like a date), and 5036861.apk is the AR.Pro Lite app from the Android App Store.

Installing AR.Pro Lite Android App on Beagle Board from Desktop

Here you can see the AR.Pro Lite icon now in the upper right-hand corner of the Android display.

AR.Pro Lite Android App on Beagle Board

Step seven: I brought up the AR.Pro Lite app on the Beagle Board and administered it to see the AR.drone at its address on the new subnet, 192.168.2.1, by using the app's Preferences menu whose icon is visible in the lower center of the Android display. (This is a feature the Free Flight iDevice app sadly lacks.) I then used the Connect to Drone button whose icon is visible in the lower left of the Android display.

AR.Pro Lite Android App Running on Beagle Board

Step eight: the AR.Pro Lite app almost immediately showed the cockpit view from the AR.drone through the drone's forward camera. I hit the Take Off button at the bottom of the display and (somewhat to my surprise I must admit), my AR.drone spun up its engines and leaped into the air. Below on the Android display you can see the cockpit view showing an aerial shot of the hallway outside my office, along with the ground view from the ventral camera showing the AR.drone cardboard box I was using as a landing pad, as well as an altimeter, a WiFi signal strength gauge, and a fuel (battery) gauge. Between the big Mac Cinema Display and the Android display you can see the WET54G bridge and the Beagle Board. The AR.drone was hovering just outside the door at the right hand edge of the photograph.

AR.drone in Flight via AR.Pro Lite Android App from Beagle Board

Step nine: celebrate!

Contraption and Horsefly are part of my effort to demonstrate that learning real-time and embedded software development can be exciting, using popular software stacks such as Linux, GNU, and Android, and inexpensive, using platforms like the Beagle Board and the AR.drone. This milestone has been a great proof of concept towards that goal.

(A big Thank You to Shell Shrader, of Shellware, for his support of this project!)

Monday, March 07, 2011

Deconstructing the AR.drone: Part 3

Although the AR.drone is based on the Linux kernel, the way embedded systems use Linux typically differs significantly from how desktop or server systems use it due to resource constraints in memory, storage, CPU speed, and power consumption.

The AR.drone has 128 megabytes of memory, which is generous compared to other embedded systems of my acquaintance. But that is a fraction of what the typical Linux-based desktop or server would have.

The AR.drone has a read-write persistent file system implemented in NAND flash using the Unsorted Block Image File System (UBIFS) which is specific to flash devices. But the size of the flash partition in which the root file system is implemented (I'm guessing that's the Psystem partition in flash partition /dev/mtd3) is sixteen megabytes. That's smaller than any USB thumb drive you can buy these days. And I have implemented Linux-based embedded systems that had no read-write persistent file system.

And so on. Many of the constraints are due to the application. Many embedded systems are mobile devices which are handheld (so they have to be small and light) and battery powered (so they have to be extremely power efficient). But cost is also a driving factor. The number of processors manufactured and sold each year into embedded applications far far outstrips the number of processors sold into desktops and servers during the same period of time. Embedded processors, the smaller and less powerful of which are often referred to as microcontrollers but which may still run Linux, are ubiquitous. Most of the applications for embedded processors are extremely price sensitive. So given these factors and volumes, saving even fractions of a cent in the design of an embedded system can have significant economic consequences for the manufacturer.

As we continue to peer into the details of the AR.drone we will continue to see how clever its designers and engineers were. Although at US$300 it might seem to be on the high side for a toy, I find its design to be remarkable in its tradeoff between price and capability.

Now we'll look at how the AR.drone, the smallest flying Linux system of which I'm aware, gets to a shell prompt.

It is not unusual for Linux systems, embedded and otherwise, to have a multi-stage boot process such that several executable programs are run before Linux gets control of the CPU. All processors have to have some kind of rudimentary fixed mechanism to start running software. For some I've used, the CPU merely starts executing instructions at a fixed address, and it is up to the designer to have executable machine instructions, typically in read-only memory (ROM), present at that address. Other processors have sophisticated (relatively speaking) mechanisms involving reading instructions into memory over simple serial buses from some kind of persistent storage device that may be flash-based.

I actually don't know yet how the lowest level boot mechanism works on the AR.drone; although it based on an ARM-core, the drone has a proprietary processor manufactured especially for Parrot, the parrot-6. I'm guessing the parrot-6 is a System on a Chip (SoC): a processor core plus I/O controllers integrated into a single piece of silicon. The use of SoCs is very common in embedded systems.

In Part 2 of this series I mentioned that are two two flash partitions that look to be boot loaders: /dev/mtd0 which is named Pbootloader, and /dev/mtd1 which is named Pmain_boot. (I'm guessing the P stands for Partition, but it might also stand for Parrot, the AR.drone manufacturer.) What might these be? Running the strings utility against the read-only versions of these partitions might offer some clues. (I had thought I was going to have to FTP the contents of these two partitions from the AR.drone, move them to my desktop, and do a strings there; I was delighted and more than a little surprised to find the strings utility resident on the AR.drone itself. Even though /usr/bin/strings is, as you might have guessed, a link to /bin/busybox, many embedded systems omit that applet in their BusyBox configuration.)

In bootloader (after editing out a lot of cruft) we find some interesting snippets.

# strings /dev/mtd0ro
#IBU
!IBU
PLF!
return from stage1_boot
Parrotboot for target MYKONOS, built on Nov 18 2010
-> Change VDD2 reset value
volume %d : %s ok
volume %d is bad
read error on volume %d
scaning start %x end %x page shift %d eb size %d
skipping bad block %d
vid_hdr_offset %d, data_offset %d leb_size %d
image_seq is %x
unexpected image_seq %x
lnum(%d) >= used_ebs(%d)
new volume %d
can't alloc volume %d
not vtbl found
incomplete vtbl
no valid vtbl
ubi scan failure
Attempt booting on UBI volume with ID %d...
Failure (%d)
main_boot
alt_boot
i2cm0
Booting Linux...
0123456789ABCDEF
0123456789
0123456789abcdef
%08X:
%02X
%04X
%08X
uart0
uart1
uart2
uart3
sdram
dmac
nand
mpmc
i2cm1
spi0
spi1
spi2
2 x Micron MT46H64M16LF 6ns @ CL=3 BL=4 156 MHz - Parelia
Micron MT46H32M32LF 6ns @ CL=3 BL=4 156 MHz - P6dev
Micron MT46H16M16LF 6ns @ CL=3 BL=4 156 MHz - Palladium
Elpida EDD20323ABH 6ns @ CL=3 BL=4 156 MHz - RnB4
Micron MT46H64M32LF 6ns @ CL=3 BL=4 156 MHz - RnB4
-error during driver configuration
unknown error
no error
device is not responding
I/O error
write protection is on
an ECC error was detected and fixed
an incorrectable ECC error was detected
nand_flash: %s
nand_flash: By ONFI Manufacturer: %s, Model: %s
nand_flash: Support ONFI v1.0
nand_flash: Support ONFI v2.0
nand_flash: Support ONFI v2.1
nand_flash: Support ONFI v2.2
nand_flash: unknown device: manid=0x%02x, devid=0x%02x
unknown
large
small
1.8V
3.3V
nand_flash: %s %s page device, %d %cbits (x%d), %s
Fujitsu
Renesas
ST-Micro
National
Toshiba
Samsung
Hynix
Micron
Micron MT46H64M16LF 6ns @ CL=3 BL=4 156 MHz - P6idev
Micron MT48H32M16LF 6ns @ CL=3 BL=4 104 MHz - P6idev
Micron MT46H32M16LF 6ns @ CL=3 BL=4 156 MHz - FC6150 B/W
Micron MT46H16M16LF 6ns @ CL=3 BL=4 156 MHz - FC6050 B/W
Micron MT48H16M16LF 7.5ns @ CL=3 BL=4 104 MHz - FC6050
Micron MT48H8M16LF 7.5ns @ CL=3 BL=4 104 MHz - Voyager
Micron MT48H16M16LF 7.5ns @ CL=3 BL=4 104 MHz -FC6050-HW00
Micron MT48H4M16LF 8ns @ CL=3 BL=4 104 MHz - FC6000
Micron MT48H4M16LF 8ns @ CL=3 BL=4 104 MHz - FC6000-HW00
/dev/nand_ba315_boot
return from stage1_boot
Parrotboot for target MYKONOS, built on Nov 18 2010
-> Change VDD2 reset value
volume %d : %s ok
volume %d is bad
read error on volume %d
scaning start %x end %x page shift %d eb size %d
skipping bad block %d
vid_hdr_offset %d, data_offset %d leb_size %d
image_seq is %x
unexpected image_seq %x
lnum(%d) >= used_ebs(%d)
new volume %d
can't alloc volume %d
not vtbl found
incomplete vtbl
no valid vtbl
ubi scan failure
Attempt booting on UBI volume with ID %d...
Failure (%d)
main_boot
alt_boot
i2cm0
Booting Linux...
0123456789ABCDEF
0123456789
0123456789abcdef
%08X:
%02X
%04X
%08X
uart0
uart1
uart2
uart3
sdram
dmac
nand
mpmc
i2cm1
spi0
spi1
spi2
2 x Micron MT46H64M16LF 6ns @ CL=3 BL=4 156 MHz - Parelia
Micron MT46H32M32LF 6ns @ CL=3 BL=4 156 MHz - P6dev
Micron MT46H16M16LF 6ns @ CL=3 BL=4 156 MHz - Palladium
Elpida EDD20323ABH 6ns @ CL=3 BL=4 156 MHz - RnB4
Micron MT46H64M32LF 6ns @ CL=3 BL=4 156 MHz - RnB4
-error during driver configuration
unknown error
no error
device is not responding
I/O error
write protection is on
an ECC error was detected and fixed
an incorrectable ECC error was detected
nand_flash: %s
nand_flash: By ONFI Manufacturer: %s, Model: %s
nand_flash: Support ONFI v1.0
nand_flash: Support ONFI v2.0
nand_flash: Support ONFI v2.1
nand_flash: Support ONFI v2.2
nand_flash: unknown device: manid=0x%02x, devid=0x%02x
unknown
large
small
1.8V
3.3V
nand_flash: %s %s page device, %d %cbits (x%d), %s
Fujitsu
Renesas
ST-Micro
National
Toshiba
Samsung
Hynix
Micron
Micron MT46H64M16LF 6ns @ CL=3 BL=4 156 MHz - P6idev
Micron MT48H32M16LF 6ns @ CL=3 BL=4 104 MHz - P6idev
Micron MT46H32M16LF 6ns @ CL=3 BL=4 156 MHz - FC6150 B/W
Micron MT46H16M16LF 6ns @ CL=3 BL=4 156 MHz - FC6050 B/W
Micron MT48H16M16LF 7.5ns @ CL=3 BL=4 104 MHz - FC6050
Micron MT48H8M16LF 7.5ns @ CL=3 BL=4 104 MHz - Voyager
Micron MT48H16M16LF 7.5ns @ CL=3 BL=4 104 MHz -FC6050-HW00
Micron MT48H4M16LF 8ns @ CL=3 BL=4 104 MHz - FC6000
Micron MT48H4M16LF 8ns @ CL=3 BL=4 104 MHz - FC6000-HW00
/dev/nand_ba315_boot

The things that interest me here are Parrotboot, which suggests to me that this is a boot loader written especially for this custom processor (probably with its low-level boot mechanism in mind), main_boot, which is the name of our other flash partition of interest, and alt_boot, which suggests this boot loader can load a different secondary boot loader if it exists (could be a redundant backup or something used during development).

In main_boot, clues are not nearly so forthcoming, making me wonder if this partition is compressed (not unusual in multi-stage boot systems). But we do see a few snippets that pique our interest (after editing out hundreds of lines of cruft).

# strings /dev/mtd1ro
UBI#
UBI!
main_boot
alt_boot
parrotparts=nand0:256K(Pbootloader),
8M(Pmain_boot),8M(Pfactory),16M(Psystem),
98048K(Pupdate)
console=ttyPA0,115200 loglevel=4
ubi.mtd=Pfactory,2048 ubi.mtd=Psystem,2048
ubi.mtd=Pupdate,2048
root=ubi1:system rootfstype=ubifs
parrot5.low_latency=1
PLF!
-- System halted
ran out of input data
Malloc error
Out of memory
incomplete literal tree
incomplete distance tree
bad gzip magic numbers
internal error, invalid method
Input is encrypted
Multi part input
Input has invalid flags
invalid compressed format (err=1)
invalid compressed format (err=2)
out of memory
invalid compressed format (other)
crc error
length error
Uncompressing Linux...
done, booting the kernel.

We see the command line that in Part 2 we saw was passed to the Linux kernel from the boot loader as indicated in /proc/cmdline (so this is probably the final boot loader stage before the Linux kernel executes). We also see messages that in the past I have associated with the popular U-Boot boot loader. So I'm guessing this partition contains a compressed U-Boot executable image.

Notice the UBI# and UBI! strings in both boot loaders, which are byte swapped in the first one (that's interesting). I'm guessing these are magic numbers stored in the metadata by UBIFS or its lower UBI layer used to identify its own control data. UBIFS compresses its data using either the zlib (a.k.a. Deflate) or the Lempel-Ziv-Oberhumer (LZO) algorithms. The presence of the magic numbers supports the hypothesis that the main_boot partition is compressed. Why are these strings byte swapped in bootloader? I'm guessing that this partition isn't actually a UBIFS file system, but maybe it knows how to read a UBIFS file system. So the strings are actually part of the boot loader and not magic numbers in file system metadata. That would be consistent with it not being compressed itself, acting as a pre-stage to running U-Boot, and being amenable to whatever native boot mechanism is in the parrot-6 SoC.

Although I haven't necessarily shown it, in both of these flash partitions I see a lot of string sequences duplicated. That could indicate multiple redundant copies of the code in each partition. But it is more likely in my opinion that these are artifacts of system updates and I am just seeing older copies of the same boot loaders.

Eventually the Linux kernel is loaded and executed. The root=ubi1:system rootfstype=ubifs in the command line from the boot loader points the kernel to its root file system and tells it that it is a UBIFS file system, so we know the root file system in one of the flash partitions. The ubi.mtd=Psystem,2048 in the command line, which is the second (or number one counting from zero) such parameter, plus the mounted file systems we saw in Part 2, suggests that we were probably correct in our assumption that the Psystem partition is the root partition.

Once the Linux kernel is running, it has to bring the system up into single-user mode. For many embedded systems, this is the only state there is; multi-user mode may only makes sense for desktop and server systems. It will typically do this by finding the /sbin/init application and running it as the very first process, with process identifier (PID) 1. (If the kernel fails to find /sbin/init, it will also look for /etc/init, /bin/init, and even /bin/sh, this latter giving you some hope of recovering a seriously scrogged system, or, as I have done, building a really minimal Linux-based embedded system.)

If you have been paying attention, it will not surprise you to know that /sbin/init is simply a link to the Swiss Army Knife of embedded tools /bin/busybox. As it does with all its other applets, BusyBox looks to see the name by which it has been invoked, and then does the right thing. In this case, the right thing is to look for the /etc/inittab file for further instructions.

The /etc/inittab file will seem new and different to the youngsters in the crowd, since Linux distributions for mainstream desktop and server systems have evolved far more complex mechanisms for dealing with system initialization. My big quad-core Dell server running Ubuntu looks for initialization scripts in the directory /etc/init. Having the initialization scripts split into discrete files vastly simplifies the incremental installation of new features. But such a capability isn't necessary for most embedded systems. And in fact at one time, all UNIX systems took their initial marching orders from /etc/inittab, which contains a series of text lines indicating what programs should be run at what stage of the initialization process, and what programs should be restarted should they terminate. BusyBox implements a subset of the old /etc/inittab semantics.

Of particular interest, we find the following lines in the /etc/inittab on the AR.drone.

# Startup the system and run any rc scripts
::sysinit:/etc/init.d/rcS

# Put a getty on the serial port
ttyPA0::askfirst:/bin/sh

The first line directs the init process to run the program /etc/init.d/rcS, which as we shall see shortly is a shell script. (Historically, rc has stood for Run Control and S for Single-user mode.) The second line starts the shell /bin/sh (which, of course, will also turn out to be a link to /bin/busybox) on the serial terminal /dev/ttyPA0 after first asking the user (if such exists and has access to that terminal) to hit return. We know from /proc/cmdline that /dev/ttyPA0 is the system console, so we'll keep that in mind as we continue to peruse the AR.drone. (It is just sheer guess work on my part that the PA stands for Parrot Asynchronous.)

Perusing /etc/init.d/rcS we see lots of interesting stuff. Of particular interest is the fact that most of the network setup is in a second script.

/bin/hostname -F /etc/hostname
/sbin/ifconfig lo 127.0.0.1 up
/sbin/route add -net 127.0.0.0 netmask 255.0.0.0 lo
/bin/wifi_setup.sh

Here are some snippets extracted from /bin/wifi_setup.sh where we can see the AR.drone setting up its ad hoc WiFI network as well as starting its TELNET and DHCP daemons. We can also see it using arping with -D for duplicate address detection mode. I'm guessing it's verifying that it isn't stepping on any other device on the same ad hoc WiFi network. Note that the shell variable SSID contains the service set identifier of the ad hoc WiFI network, RANDOM_CHAN is set to a random WiFI channel number, BASE_ADDRESS is the IP network that the AR.drone will use, and PROBE is its initial try at an IP host number.

SSID=`grep ssid_single_player /data/config.ini | awk -F "=" '{print $2}'`

RANDOM_CHAN=`/bin/channelselector`

iwconfig ath0 mode ad-hoc
iwconfig ath0 channel $RANDOM_CHAN
iwconfig ath0 essid "$SSID"

BASE_ADRESS=192.168.1.
PROBE=1

ifconfig ath0 $BASE_ADRESS$PROBE
arping -I ath0 -q -f -D -w 2 $BASE_ADRESS$PROBE

/bin/pairing_setup.sh

iwconfig ath0 rate 54M
iwconfig ath0 rate auto

telnetd -l /bin/sh
udhcpd /tmp/udhcpd.conf

Although I didn't show it above, this script also creates the DHCP daemon configuration file in /tmp/udhcpd.conf. We can see that the DHCP daemon serves IP addresses in the range from 192.168.1.2 through 192.168.1.5 (reserving 192.168.1.1 for itself), with a subnet mask of 255.255.255.0, and a router (gateway) address pointing to itself. This all jives with what we saw in Part 1.

# cat /tmp/udhcpd.conf
start 192.168.1.2
end 192.168.1.5
interface ath0
decline_time 1
conflict_time 1
opt subnet 255.255.255.0
opt router 192.168.1.1
opt lease 1200

The /bin/wifi_setup.sh script in turn invokes /bin/pairing_setup.sh. Here are some snippets from that script. The logic in this script (not all of which is shown here) is kind of remarkable. Depending on the contents of /data/config.ini, a firewall may be established using iptables that restricts traffic to a particular user identified by a specific MAC address. Otherwise, all rules are cleared and one of the LEDs is flashed on the drone.

if [ $MAC_ADDR != $NULL_MAC ]
then
echo "Setting pairing for: $MAC_ADDR"
# Clearing all rules
iptables -P INPUT ACCEPT
iptables -F
# Allowing only owner's traffic
iptables -A INPUT -m mac --mac-source $MAC_ADDR -j ACCEPT
# allowing ICMP (ping), ftp and nfs traffic for everyone.
# Telnet is only allowed for paired user
iptables -A INPUT --protocol icmp -j ACCEPT
#iptables -A INPUT --protocol tcp --dport 23 -j ACCEPT
iptables -A INPUT --protocol tcp --dport 21 -j ACCEPT
iptables -A INPUT --protocol tcp --dport 2049 -j ACCEPT
# Blocking all incoming traffic by default
iptables -P INPUT DROP
else
echo "Clearing pairing rule"
# Switching rad LED on
gpio 63 -d ho 1

# Clearing all rules
iptables -F
# Allows incoming connections from anywhere outside
iptables -P INPUT ACCEPT

# Switching rad LED off
gpio 63 -d ho 0
fi

/data/config.ini is a parameter file containing keyword-value pairs. For example, it specifies the SSID of the ad hoc WiFi network. The shell variable NULL_MAC above is initialized to 00:00:00:00:00:00 in the script and MAC_ADDR is extracted from the owner_mac parameter in the file. Below are some snippets from the file that include information that is relevant to my interests.

[network]
ssid_single_player = ardrone_040582
ssid_multi_player = ardrone_040582
infrastructure = TRUE
secure = FALSE
passkey =
navdata_port = 5554
video_port = 5555
at_port = 5556
cmd_port = 0
owner_mac = 00:00:00:00:00:00
owner_ip_address = 0
local_ip_address = 0
broadcast_address = 0

The values of some of the keywords in the file change dynamically, for example when I connect the Parrot Free Flight iDevice app to the AR.drone. But the parameter pertinent to the firewall, owner_mac, did not change, nor as far as I can tell do any of the other networking-related parameters. This merits further investigation.

I confess at the moment I am less excited about the firewall than I am about the fact that I now know that there is a tool to manipulate General Purpose I/O (GPIO) pins on the AR.drone. I can't tell you how many times I've written a little tool to do this exact kind of thing (and have written about it here and here).

Did I try running gpio myself? Of course I did. It turns out the arguments used above turn the LED on the bottom of the body of the AR.drone from green to red and back again. Does gpio have a help menu? Of course it does.

Usage : gpio num_gpio options [output_value]
num_gpio : the gpio to configure.
options :
-h : Display this help.
-d x : configure the direction of the gpio, where x can be:
- i for input.
- lo for low output.
- ho for high output.
-r : read value on the GPIO.
output_value : 0 or 1. Required when configuring gpio as output.

By this time the AR.drone has its ad hoc WiFi network established, it has configured an IP subnet, the drone is running a DHCP server ready to respond to anyone who joins the network, and a TELNET server is running.

Remember the BASE_ADDRESS and PROBE variables in /bin/wifi_setup.sh? It might occur to you that you could trivially change the IP network and address that the AR.drone uses by editing that script and changing those variables. Could this possibly work? Yes. Yes, it does. But I can give you three good reasons not to do this.

  1. Doing so would almost certainly void the warranty on your expensive $300 toy.
  2. If you make a mistake, you are likely to brick your AR.drone by rendering unusable the only channel through which you can fix it, TELNETing though its ad hoc WiFi network.
  3. It probably won't do you any good. The iDevice apps I have used to control the AR.drone, including the one provided by Parrot, hard code the IP address of the drone to 192.168.1.1. This is also consistent with the example app source code Parrot provides on their web site. (One of the Android apps I've looked at does give you the option of using a different address.)

This is unfortunate, since for many of us the 192.168.1.0 subnet will conflict with our conventional LAN. Indeed, for most of us the 192.168.1.1 host address will conflict with our WiFi access point and router. Hard coding the drone's network and host address on the client side prevents me from integrating the drone into the LAN at the Palatial Overclock Estate (or what the media still insists on calling the Heavily Armed Overclock Compound). This is especially problematic, given the drone runs a DHCP server which would conflict with the server on my household AP and router. I don't really need my MacBook Air connecting unexpectedly and exclusively to the AR.drone when I'm trying to browse LOLCats. Yes, I could completely reconfigure the household LAN, which is a crazy-quilt mixture of CAT5, PowerLine, and WiFi technologies, but with several servers and other assets having static IP addresses, that's harder than it might appear.

Why would I want to integrate the AR.drone into the household LAN? Oh, um, ...

We noticed in Part 2 that the AR.drone runs klogd and syslogd, daemons that log status and error messages from the kernel and user applications respectively to a system log file. /var/log/messages is full of information about what the kernel is doing as it initializes itself and its device drivers but before it runs the init process.

Next up: we go back in time to briefly look at /var/log/messages.

Saturday, March 05, 2011

Rethinking Memory Models with Adve and Boehm

Long time readers of this blog, if such exist, know that I am interested in (some might say obsessed with) the topic of memory models for modern processors and programming languages. Given my background -- for the past three plus decades I've bounced between embedded development (the very small) and high performance and enterprise computing (the very large) with an abiding interest in what goes on near bare metal -- this is not terribly surprising. My reading time the past two days has been taken up with the article

Sarita V. Adve and Hans-J. Boehm, "Memory Models: A Case for Rethinking Parallel Languages and Hardware", Communications of the ACM, 53.8, August 2010, pp. 90-101 (preprint)

by two experts on the topic. Adve (U. of Illinois at Urbana-Champaign) and Boehm (HP Laboratories) write frequently and cogently, together and separately, in this area that should be of interest to anyone who, like me, develops real-time and/or multi-threaded code. This includes everyone from the person writing a device driver in C destined for an embedded multi-core platform to the person writing in Java for an enterprise server-side application. I have in fact been both of those persons.

In this particular article Adve and Boehm suggest software-hardware co-development will be necessary to tackle the issue of broken memory models which are repaired with memory models too subtle and difficult for anyone except experts to understand and hence impossible to teach at the undergraduate level. What I really like about the article though is that six or so pages are an excellent, detailed introduction to the topic that is very accessible for those willing to make the effort.

One of their several tiny pseudo-code snippets used as examples actually made me laugh out loud: a speculative store by one thread based on an analysis of prior application behavior, either statically by the compiler at compile-time or dynamically by the processor at run-time, causes another thread to act such that this speculation turns out to be correct post-hoc, creating a "causality loop" resulting in a "self-fulfilling speculation". This can result in the storing of a speculative value (42 in their example) created out of thin air that has nothing to do with the actual algorithm being executed.

They make the point that although no such processor or compiler does this today, such an operation isn't that different from speculative operations that are performed today by processors and compilers, and current memory models do nothing to indicate that such an operation is incorrect. They also say that it is remarkably difficult to define a formal memory model that disallows such an operation without disallowing optimizations that are routinely done today.

I feel like Stephen King reading about the funeral home that tossed bodies in the pond out back when their cremation oven broke down: you can't make this stuff up; no one would believe it! There is also some discussion about the forthcoming atomic keyword in C++, which is like the volatile keyword in Java, which is completely different in semantics from the volatile keyword in C. This is the kind of thing will keep me gainfully employed for the next few years.

Adve and Boehm also make the excellent point that the use of memory barriers, in the form of either compiler directives and machine instructions, is problematic because for nearly all compilers and processors such barriers affect all of the active variables (for the former) or all of cached memory (for the latter), not just the one variable shared between threads with which the developer is concerned. This can potentially have a huge impact on performance, including cache hit rate and use of memory bus bandwidth.

Thirty years ago I found myself in graduate school teaching a course in real-time software design where my students wrote multi-threaded applications, device drivers, and interrupt service routines, while simultaneously working on my thesis as part of a research group looking at programming language designs for massively-parallel data-flow machines. In their technical report on the advent of many-core processors

K. Asanovic at al., The Landscape of Parallel Computing Research: A View from Berkeley, EECS Department, U. C. Berkeley, UCB/EECS 2006-183, December 2006

the authors (which includes David Patterson of Patterson and Hennesy) remark that the skill sets for embedded development and for many-core development are remarkably similar. That's obviously been my experience too. At my extremely advanced age, pondering the implications of many-core processors, with dozens or even hundreds of cores, it's making me positively nostalgic for the old days of non-procedural single-assignment languages with lazy-evaluation running on massively-parallel data-flow architectures.