<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-28344720</id><updated>2012-01-27T18:34:48.094-07:00</updated><title type='text'>Chip Overclock</title><subtitle type='html'>90% of everything I say is crap. Because 90% of everything is crap.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://coverclock.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://coverclock.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default?start-index=101&amp;max-results=100'/><author><name>Chip Overclock</name><uri>http://www.blogger.com/profile/11195242013008369733</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-1xNiFqWVjh8/TWQ1ru5Z6KI/AAAAAAAAABw/kMJyhvluNMI/s220/Chip%2BOverclock%2BAvatar%2B2.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>168</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-28344720.post-6185150159498126741</id><published>2012-01-27T16:26:00.009-07:00</published><updated>2012-01-27T18:34:48.110-07:00</updated><title type='text'>Wireless Remote Sensing with Arduino and Zigbee</title><content type='html'>In "&lt;a href="http://coverclock.blogspot.com/2012/01/remote-sensing-with-arduino.html"&gt;Remote Sensing with Arduino&lt;/a&gt;" I described how to access light and temperature sensors on an &lt;a href="http://www.arduino.cc/"&gt;Arduino&lt;/a&gt; board over Ethernet via a web server. In this article I'll describe how I've taken the same basic sensor platform and am now accessing it wirelessly via XBee radios.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.digi.com/xbee/"&gt;Xbee&lt;/a&gt; is a family of tiny radios made by &lt;a href="http://www.digi.com/"&gt;Digi International&lt;/a&gt; and based on &lt;a href="http://en.wikipedia.org/wiki/Zigbee"&gt;Zigbee&lt;/a&gt;, the IEEE 802.15.4 standard for &lt;i&gt;personal area networks&lt;/i&gt; (PAN) that are characterized by low power (one milliwatt), short ranges (about one hundred feet), and a pretty sophisticated network stack. Zigbee is capable of implementing a &lt;a href="http://en.wikipedia.org/wiki/Wireless_mesh_network"&gt;wireless mesh network&lt;/a&gt;, but the radios and firmware I am using in this application do something much simpler, so simple in fact that it requires no configuration and works right out of the box: a 9600 baud wireless serial connection.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I did this using a &lt;a href="http://www.sparkfun.com/"&gt;SparkFun&lt;/a&gt; &lt;a href="http://www.sparkfun.com/products/9897"&gt;Xbee Wireless Kit&lt;/a&gt;. The kit includes two XBee 2.4 gigaHertz series 1 radio modules, an XBee Arduino shield (some assembly required, so I had to break out the soldering iron to attach the Arduino headers), and an XBee Explorer. The Explorer is a tiny board with a socket for the radio module and an FTDI chip that performs the serial to USB conversions. The Explorer implements the PC/Mac end of the wireless serial connection. The Explorer requires the FTDI &lt;a href="http://www.ftdichip.com/Drivers/VCP.htm"&gt;Virtual COM Port&lt;/a&gt; (VCP) drivers be installed on your PC or Mac. (I've written of my affection for &lt;a href="http://www.ftdichip.com/"&gt;FTDI&lt;/a&gt; and the quality of their products before, in "&lt;a href="http://coverclock.blogspot.com/2011/04/deconstructing-ardrone-part-5.html"&gt;Deconstructing the AR.drone: Part 5&lt;/a&gt;".)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;Below you can see the new setup. The breadboard at the top has exactly the same sensor setup as before. The Ethernet shield has been replaced on the Arduino board with the red XBee shield. The blue XBee radio module is plugged into a socket on the top of the shield. Jumper wires for power, ground, and the two sensors are plugged into the headers on top of the shield just as they were on the Ethernet shield. The Explorer is to the left with its own blue XBee radio module and a USB cable connecting it to my Mac. Note that there is no USB connection from the Arduino to my Mac; that's just a power cable from a wall wart powering the Arduino board. You could also power the Arduino side with something as simple as a nine volt transistor radio battery.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/6773159295/" title="XBee Explorer and Arduino by John Sloan, on Flickr"&gt;&lt;img src="http://farm8.staticflickr.com/7163/6773159295_ccfb7c4765.jpg" width="500" height="281" alt="XBee Explorer and Arduino" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here's a side view where you can see the power cable coming into the Arduino, with the XBee shield plugged in on top of it similar to the Ethernet shield.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/6773160405/" title="Arduino and XBee Shield by John Sloan, on Flickr"&gt;&lt;img src="http://farm8.staticflickr.com/7033/6773160405_70b5d67638.jpg" width="500" height="281" alt="Arduino and XBee Shield" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here's a closeup of the XBee shield. Near the lower right on the shield you might be able to see a tiny silver surface-mounted slider switch, so small you need a something like a toothpick to throw it. The switch has two positions, labelled &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;DLINE&lt;/span&gt;, in which you can load your Arduino board over its USB cable just as you normally would, and &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;UART&lt;/span&gt;, in which the XBee hijacks the serial pins on the Atmel ATmega328 so that, for example, whatever your software displays over the microcontroller's serial port goes across the wireless XBee channel instead of the USB cable.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/6773160745/" title="XBee Shield with XBee Module by John Sloan, on Flickr"&gt;&lt;img src="http://farm8.staticflickr.com/7007/6773160745_7bd2cb3e11.jpg" width="500" height="281" alt="XBee Shield with XBee Module" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;And here's a closeup of the XBee Explorer. It is powered completely off the USB cable connected to my Mac. Although the XBee modules can be configured to do different things, right out of the box they implement a wireless serial connection and automatically pair with one another. Digi refers to this as &lt;i&gt;transparent mode&lt;/i&gt;. Under the hood however, the radios are implementing a peer-to-peer network based on a &lt;a href="http://en.wikipedia.org/wiki/Carrier_sense_multiple_access_with_collision_avoidance"&gt;Carrier Sense Multiple Access/Collision Avoidance&lt;/a&gt; (CSMA/CA) model.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/6773160067/" title="XBee Explorer with XBee Module by John Sloan, on Flickr"&gt;&lt;img src="http://farm8.staticflickr.com/7028/6773160067_1023a4c056.jpg" width="500" height="281" alt="XBee Explorer with XBee Module" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So I loaded the FTDI drivers onto my Mac and restarted it. I plugged the USB cable from the XBee Explorer into my Mac and verified that a new serial device, &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;/dev/tty.usbserial-A800f3aA&lt;/span&gt;, showed up. I hooked up the Arduino to its USB cable and downloaded my program over its own serial device, &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;/dev/tty.usbmodem26431&lt;/span&gt;. I brought up the serial monitor tool in the Arduino IDE and verified that I was printing sensor values. I plugged in the power cable to the Arduino and removed the USB cable. I flipped the tiny switch on the XBee shield from &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;DLINE&lt;/span&gt; to &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;UART&lt;/span&gt;. I brought up the Arduino serial monitor tool &lt;i&gt;again&lt;/i&gt;, this time using the &lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;Serial Port&lt;/span&gt; option in the IDE's &lt;span class="Apple-style-span"  style="font-family:'lucida grande';"&gt;Tools&lt;/span&gt; pull down menu to specify the new serial device from the XBee Explorer. And this is what I saw.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/6773450345/" title="Screen Shot: XBee Wireless Serial Port by John Sloan, on Flickr"&gt;&lt;img src="http://farm8.staticflickr.com/7167/6773450345_01617b3114.jpg" width="500" height="313" alt="Screen Shot: XBee Wireless Serial Port" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;No, it is not 30.55°F in my office. Unfortunately I haven't replaced the temperature sensor I fried in "&lt;a href="http://coverclock.blogspot.com/2012/01/another-tragic-victim-of-electrostatic.html"&gt;Another Victim of Electrostatic Discharge&lt;/a&gt;", so we'll ignore the actual temperature readings for now. But the Arduino is reliably reporting sensor readings wirelessly via its serial port once per second. Here's the complete program, which is mostly the same as before with all the Ethernet and Webduino stuff stripped out of it.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;pre&gt;&lt;span style="color:#CC6600;"&gt;byte&lt;/span&gt; lightLevel = 0;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;float&lt;/span&gt; temperatureCentigrade = 0;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;float&lt;/span&gt; temperatureFahrenheit = 0;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;unsigned&lt;/span&gt; &lt;span style="color:#CC6600;"&gt;long&lt;/span&gt; then = 0;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;static&lt;/span&gt; const &lt;span style="color:#CC6600;"&gt;int&lt;/span&gt; lightAnalog = 4, lightDigital = A4;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;static&lt;/span&gt; const &lt;span style="color:#CC6600;"&gt;int&lt;/span&gt; temperatureAnalog = 5, temperatureDigital = A5;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;static&lt;/span&gt; const &lt;span style="color:#CC6600;"&gt;int&lt;/span&gt; oversample = 10;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;static&lt;/span&gt; const &lt;span style="color:#CC6600;"&gt;float&lt;/span&gt; reference = 4.66; &lt;span style="color:#7E7E7E;"&gt;// Measured; nominally 5v, or 3.3v external.&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;static&lt;/span&gt; const &lt;span style="color:#CC6600;"&gt;boolean&lt;/span&gt; internal = &lt;span style="color:#CC6600;"&gt;true&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;void&lt;/span&gt; sense(&lt;span style="color:#CC6600;"&gt;unsigned&lt;/span&gt; &lt;span style="color:#CC6600;"&gt;long&lt;/span&gt; now) {&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;int&lt;/span&gt; lightRaw = 0;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;for&lt;/span&gt; (&lt;span style="color:#CC6600;"&gt;int&lt;/span&gt; ii = 0; ii &amp;lt; oversample; ++ii) {&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;  lightRaw += &lt;span style="color:#CC6600;"&gt;analogRead&lt;/span&gt;(lightAnalog);&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;  &lt;span style="color:#CC6600;"&gt;delay&lt;/span&gt;(1);&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;}&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;lightRaw /= oversample;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;int&lt;/span&gt; temperatureRaw = 0;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;for&lt;/span&gt; (&lt;span style="color:#CC6600;"&gt;int&lt;/span&gt; ii = 0; ii &amp;lt; oversample; ++ii) {&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;  temperatureRaw += &lt;span style="color:#CC6600;"&gt;analogRead&lt;/span&gt;(temperatureAnalog);&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;  &lt;span style="color:#CC6600;"&gt;delay&lt;/span&gt;(1);&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;}&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;temperatureRaw /= oversample;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;float&lt;/span&gt; lightVolts = (lightRaw * reference) / 1023.0;&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;lightLevel = 100 - ((100UL * lightRaw) / 1023);&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;float&lt;/span&gt; temperatureVolts = (temperatureRaw * reference) / 1023.0;&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;temperatureCentigrade = (temperatureVolts - 0.5) * 100.0;&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;temperatureFahrenheit = (temperatureCentigrade * 1.8) + 32.0;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;b&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;Serial&lt;/b&gt;&lt;/span&gt;.&lt;span style="color:#CC6600;"&gt;print&lt;/span&gt;(lightRaw);&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;b&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;Serial&lt;/b&gt;&lt;/span&gt;.&lt;span style="color:#CC6600;"&gt;print&lt;/span&gt;(&lt;span style="color:#006699;"&gt;'='&lt;/span&gt;);&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;b&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;Serial&lt;/b&gt;&lt;/span&gt;.&lt;span style="color:#CC6600;"&gt;print&lt;/span&gt;(lightVolts);&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;b&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;Serial&lt;/b&gt;&lt;/span&gt;.&lt;span style="color:#CC6600;"&gt;print&lt;/span&gt;(&lt;span style="color:#006699;"&gt;'v'&lt;/span&gt;);&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;b&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;Serial&lt;/b&gt;&lt;/span&gt;.&lt;span style="color:#CC6600;"&gt;print&lt;/span&gt;(&lt;span style="color:#006699;"&gt;'='&lt;/span&gt;);&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;b&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;Serial&lt;/b&gt;&lt;/span&gt;.&lt;span style="color:#CC6600;"&gt;print&lt;/span&gt;(lightLevel);&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;b&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;Serial&lt;/b&gt;&lt;/span&gt;.&lt;span style="color:#CC6600;"&gt;print&lt;/span&gt;(&lt;span style="color:#006699;"&gt;'%'&lt;/span&gt;);&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;b&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;Serial&lt;/b&gt;&lt;/span&gt;.&lt;span style="color:#CC6600;"&gt;print&lt;/span&gt;(&lt;span style="color:#006699;"&gt;' '&lt;/span&gt;);&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;b&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;Serial&lt;/b&gt;&lt;/span&gt;.&lt;span style="color:#CC6600;"&gt;print&lt;/span&gt;(temperatureRaw);&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;b&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;Serial&lt;/b&gt;&lt;/span&gt;.&lt;span style="color:#CC6600;"&gt;print&lt;/span&gt;(&lt;span style="color:#006699;"&gt;'='&lt;/span&gt;);&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;b&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;Serial&lt;/b&gt;&lt;/span&gt;.&lt;span style="color:#CC6600;"&gt;print&lt;/span&gt;(temperatureVolts);&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;b&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;Serial&lt;/b&gt;&lt;/span&gt;.&lt;span style="color:#CC6600;"&gt;print&lt;/span&gt;(&lt;span style="color:#006699;"&gt;'v'&lt;/span&gt;);&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;b&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;Serial&lt;/b&gt;&lt;/span&gt;.&lt;span style="color:#CC6600;"&gt;print&lt;/span&gt;(&lt;span style="color:#006699;"&gt;'='&lt;/span&gt;);&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;b&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;Serial&lt;/b&gt;&lt;/span&gt;.&lt;span style="color:#CC6600;"&gt;print&lt;/span&gt;(temperatureCentigrade);&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;b&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;Serial&lt;/b&gt;&lt;/span&gt;.&lt;span style="color:#CC6600;"&gt;print&lt;/span&gt;(&lt;span style="color:#006699;"&gt;'C'&lt;/span&gt;);&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;b&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;Serial&lt;/b&gt;&lt;/span&gt;.&lt;span style="color:#CC6600;"&gt;print&lt;/span&gt;(&lt;span style="color:#006699;"&gt;'='&lt;/span&gt;);&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;b&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;Serial&lt;/b&gt;&lt;/span&gt;.&lt;span style="color:#CC6600;"&gt;print&lt;/span&gt;(temperatureFahrenheit);&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;b&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;Serial&lt;/b&gt;&lt;/span&gt;.&lt;span style="color:#CC6600;"&gt;println&lt;/span&gt;(&lt;span style="color:#006699;"&gt;'F'&lt;/span&gt;);&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;then = now;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;void&lt;/span&gt; sense() {&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;sense(&lt;span style="color:#CC6600;"&gt;millis&lt;/span&gt;());&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;void&lt;/span&gt; &lt;span style="color:#CC6600;"&gt;&lt;b&gt;setup&lt;/b&gt;&lt;/span&gt;() {&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;b&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;Serial&lt;/b&gt;&lt;/span&gt;.&lt;span style="color:#CC6600;"&gt;begin&lt;/span&gt;(9600);&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;pinMode&lt;/span&gt;(lightDigital, &lt;span style="color:#006699;"&gt;INPUT&lt;/span&gt;);&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;digitalWrite&lt;/span&gt;(lightDigital, &lt;span style="color:#006699;"&gt;LOW&lt;/span&gt;);&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;pinMode&lt;/span&gt;(temperatureDigital, &lt;span style="color:#006699;"&gt;INPUT&lt;/span&gt;);&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;digitalWrite&lt;/span&gt;(temperatureDigital, &lt;span style="color:#006699;"&gt;LOW&lt;/span&gt;);&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;if&lt;/span&gt; (!internal) {&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;  &lt;span style="color:#CC6600;"&gt;analogReference&lt;/span&gt;(&lt;span style="color:#006699;"&gt;EXTERNAL&lt;/span&gt;);&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;  &lt;span style="color:#CC6600;"&gt;delay&lt;/span&gt;(1);&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;}&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;sense();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;void&lt;/span&gt; &lt;span style="color:#CC6600;"&gt;&lt;b&gt;loop&lt;/b&gt;&lt;/span&gt;() {&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;unsigned&lt;/span&gt; &lt;span style="color:#CC6600;"&gt;long&lt;/span&gt; now = &lt;span style="color:#CC6600;"&gt;millis&lt;/span&gt;();&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;if&lt;/span&gt; ((now - then) &amp;gt; 1000) {&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;  sense(now);&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Some models of the Xbee radios do allow you to some configuration, in order to, for example, use them in other than transparent mode. Unfortunately, the tool to do this from Digi, &lt;a href="http://ftp1.digi.com/support/utilities/40003002_B.exe"&gt;X-CTU&lt;/a&gt;, is only available for Windows. But as &lt;a href="http://sentman.com/users/james/weblog/bd1c5/"&gt;James Sentman has pointed out&lt;/a&gt;, you can run X-CTU on the Mac, although to do so requires that you install &lt;a href="http://www.macports.org/index.php"&gt;MacPorts&lt;/a&gt;, a software package that makes it easier to port GNU-based open source applications to MacOS, and &lt;a href="http://wiki.winehq.org/"&gt;Wine&lt;/a&gt;, a software package that lets you run Windows applications on MacOS (and other OSes as well). Being a glutton for punishment, I of course did all of this, eventually running the X-CTU installer on the Mac under Wine, and then running X-CTU itself under Wine to talk to the XBee Explorer. However, you don't need to do any of this to accomplish what I've described here.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I found some of these references handy (in no particular order):&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;"&lt;a href="http://www.sparkfun.com/datasheets/Wireless/Zigbee/XBee-Manual.pdf"&gt;XBee Manual&lt;/a&gt;" from SparkFun;&lt;/div&gt;&lt;div&gt;"&lt;a href="http://www.sparkfun.com/datasheets/Wireless/Zigbee/XBee-Datasheet.pdf"&gt;XBee Data Sheet&lt;/a&gt;" from SparkFun;&lt;/div&gt;&lt;div&gt;"&lt;a href="http://fisherinnovation.com/simple-xbee-communication-with-arduino/"&gt;Simple XBee Communication with Arduino&lt;/a&gt;" by Matt Fisher;&lt;/div&gt;&lt;div&gt;"&lt;a href="http://www.sparkfun.com/tutorials/257"&gt;XBee Introduction and Buying Guide&lt;/a&gt;" from SparkFun;&lt;/div&gt;&lt;div&gt;"&lt;a href="http://www.instructables.com/id/Changing-Xbee-Baud-Rates/"&gt;Configuring XBees&lt;/a&gt;" from Indestructables;&lt;/div&gt;&lt;div&gt;"&lt;a href="http://www.ladyada.net/make/xbee/configure.html"&gt;XBee radios - connecting, configuring, and upgrading&lt;/a&gt;" by Limor Fried.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;But once again, you don't need any of these to actually get this wireless setup working. The hardest part was, for me, not being a hardware guy, soldering the headers onto the XBee shield, and even that worked the first time. I was, however, careful to wear an ESD strap while putting all of this together.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28344720-6185150159498126741?l=coverclock.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://coverclock.blogspot.com/feeds/6185150159498126741/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28344720&amp;postID=6185150159498126741' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/6185150159498126741'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/6185150159498126741'/><link rel='alternate' type='text/html' href='http://coverclock.blogspot.com/2012/01/wireless-remote-sensing-with-arduino.html' title='Wireless Remote Sensing with Arduino and Zigbee'/><author><name>Chip Overclock</name><uri>http://www.blogger.com/profile/11195242013008369733</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-1xNiFqWVjh8/TWQ1ru5Z6KI/AAAAAAAAABw/kMJyhvluNMI/s220/Chip%2BOverclock%2BAvatar%2B2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28344720.post-2669799548399306728</id><published>2012-01-26T10:04:00.005-07:00</published><updated>2012-01-26T11:26:36.063-07:00</updated><title type='text'>Another Tragic Victim of Electrostatic Discharge</title><content type='html'>&lt;i&gt;&lt;/i&gt;&lt;blockquote&gt;&lt;i&gt;If Chip spends more than a day trying to solve a software problem, it's a hardware problem. &lt;/i&gt;-- Mrs. Overclock's Law&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This isn't always true, but it's been true often enough, going all the way back to 1976 when a recalcitrant disk controller on a PDP-11/05 caused my device driver to work in the morning but not in the afternoon after the lab had warmed up. I typically work with hardware engineers of such caliber that I am extremely reluctant to invoke this law. However, when it's my hands on the hardware, all bets are off.&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;After writing the article "&lt;a href="http://coverclock.blogspot.com/2012/01/remote-sensing-with-arduino.html"&gt;Remote Sensing with Arduino&lt;/a&gt;" I anxiously awaited for Mrs. Overclock (a.k.a. Dr. Overclock, Medicine Woman) to return home from a hard day courageously saving lives so that I could demonstrate my latest project on her own laptop. Here is what she saw.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/6766322687/" title="Analog Devices TMP36: Another Victim of ESD by John Sloan, on Flickr"&gt;&lt;img src="http://farm8.staticflickr.com/7017/6766322687_77341b936f.jpg" width="500" height="258" alt="Analog Devices TMP36: Another Victim of ESD" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;Let me assure you that it is seldom if ever 38.77° Fahrenheit in my home office where the Arduino board was connected to the network. Convinced that I had somehow botched some recent software changes, or maybe knocked something loose on the breadboard, I spent several hours fiddling with the code, swapping jumper wires, peering at the Arduino source code that supports the analog pins, reading documentation about the analog-to-digital convertor in the Atmel ATmega328 microcontroller, and just generally wasting my time making all of this a lot harder than it needed to be. Everything pointed to the &lt;/span&gt;&lt;a href="http://www.analog.com/en/index.html"&gt;Analog Devices&lt;/a&gt; &lt;a href="http://www.analog.com/en/mems-sensors/digital-temperature-sensors/tmp36/products/product.html"&gt;TMP36&lt;/a&gt;&lt;span class="Apple-style-span"&gt; temperature sensor as the problem.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Finally, first thing this morning, I invoked Mrs. Overclock's Law and found this excellent &lt;a href="http://www.ladyada.net/learn/sensors/tmp36.html"&gt;description&lt;/a&gt; of how to test the TMP36 by (as I was to find out only just now) none other than &lt;a href="http://www.ladyada.net/bio/index.html"&gt;Limor Fried&lt;/a&gt; &lt;a href="http://www.wired.com/magazine/2011/03/ff_adafruit/all/1"&gt;herself&lt;/a&gt;. Here's a close-up of the tiny TMP36 surrounded by probes to my multimeter and wires providing power right from the Arduino board.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/6766323541/" title="Analog Devices TMP36: Surrounded by Probes by John Sloan, on Flickr"&gt;&lt;img src="http://farm8.staticflickr.com/7022/6766323541_e97b45444b.jpg" width="500" height="281" alt="Analog Devices TMP36: Surrounded by Probes" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Initially the device reported 140 millivolts; that's around -33°F. A few minutes later it was 350mV or 5°F. Right now it reports 624mV or 54°F. Since I have my sleeves rolled up, this seems unlikely. This is a semiconductor device that had been working just fine.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/6766323127/" title="Analog Devices TMP36: Testing by John Sloan, on Flickr"&gt;&lt;img src="http://farm8.staticflickr.com/7031/6766323127_40cb2b758c.jpg" width="500" height="281" alt="Analog Devices TMP36: Testing" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I have no one to blame but myself. While everything you see here is placed carefully on an anti-static mat, I am not always careful to ground myself using the anti-static wrist strap, to my woe. Especially in the dry winter months, it is not unusual for me to experience a spark here and there. I suspect I fried the part while putting my finger on it to warm it up during testing.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It's not really the semiconductor part that's the issue here, although if I had fried an OMAP microprocessor or some other expensive or hard to get component, it might have been. The TMP36 costs two bucks U.S. or less. It's the fact that my own carelessness cost me hours of my time. When you are self-employed and you bill by the hour, you are constantly aware of the value of your time in real dollars. Using a grounded wrist strap to protect against &lt;a href="http://en.wikipedia.org/wiki/Electrostatic_discharge"&gt;electrostatic discharge&lt;/a&gt; (ESD) would have saved me a lot of time &lt;i&gt;and&lt;/i&gt; money.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I have a grounded ESD mat and wrist strap permanently wired up on my work table in my office.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/2355189712/" title="Board Setup by John Sloan, on Flickr"&gt;&lt;img src="http://farm3.staticflickr.com/2014/2355189712_ee43a4539e.jpg" width="500" height="281" alt="Board Setup" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I even carry a portable model in my tool bag.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/5609734429/" title="Field Service ESD Mat by John Sloan, on Flickr"&gt;&lt;img src="http://farm6.staticflickr.com/5307/5609734429_1c40574365.jpg" width="500" height="281" alt="Field Service ESD Mat" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Back in my Bell Labs days we were required to take an annual refresher course in ESD practices. Or, I can just learn the hard way. If you lay hands on bare hardware, get yourself an ESD mat and wrist strap. And have the discipline to use them.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28344720-2669799548399306728?l=coverclock.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://coverclock.blogspot.com/feeds/2669799548399306728/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28344720&amp;postID=2669799548399306728' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/2669799548399306728'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/2669799548399306728'/><link rel='alternate' type='text/html' href='http://coverclock.blogspot.com/2012/01/another-tragic-victim-of-electrostatic.html' title='Another Tragic Victim of Electrostatic Discharge'/><author><name>Chip Overclock</name><uri>http://www.blogger.com/profile/11195242013008369733</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-1xNiFqWVjh8/TWQ1ru5Z6KI/AAAAAAAAABw/kMJyhvluNMI/s220/Chip%2BOverclock%2BAvatar%2B2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28344720.post-377222610406172710</id><published>2012-01-24T09:00:00.017-07:00</published><updated>2012-01-26T09:32:40.822-07:00</updated><title type='text'>Remote Sensing with Arduino</title><content type='html'>If you have met me in meatspace then you know that I am so old as to be on the verge of being a brain in a jar connected to wires and tubes. When I started doing real-time development, it was on &lt;a href="http://en.wikipedia.org/wiki/PDP-11"&gt;PDP-11&lt;/a&gt;s with just four kilobytes of memory. This goes a long way towards explaining my affection for microcontrollers like the tiny eight-bit sixteen mega-Hertz &lt;a href="http://www2.atmel.com/"&gt;Atmel&lt;/a&gt; &lt;a href="http://www.atmel.com/dyn/products/product_card.asp?part_id=4720"&gt;ATmega328&lt;/a&gt; used on the &lt;a href="http://www.arduino.cc/"&gt;Arduino&lt;/a&gt; &lt;a href="http://arduino.cc/en/Main/ArduinoBoardUno"&gt;Uno&lt;/a&gt; board. It has thirty-two kilobytes of non-volatile &lt;a href="http://en.wikipedia.org/wiki/Flash_memory"&gt;flash memory&lt;/a&gt; and a scant two kilobytes of volatile &lt;a href="http://en.wikipedia.org/wiki/Static_random-access_memory"&gt;static random access memory&lt;/a&gt; (SRAM) all on-chip. (&lt;i&gt;Update 2012-01-25&lt;/i&gt;: I got the SRAM size wrong in the original version of this article.) There is a skill, becoming rarer in these days of increasing software bloat, of writing code that will run on such a platform. Thanks to its resource constraints and powerful software toolkit, Arduino is an excellent platform with which to learn (or re-learn) this skill.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Why bother? Because it is microcontrollers just like this that are permeating our lives, whether we realize it or not: embedded in our appliances and toys and transportation and even computers, sometimes alongside much more powerful Intel or ARM processors that do the heavy lifting required by graphical user interfaces. Microcontrollers are the universal machines that are called upon to bridge the gap between the real world and the digital, between meatspace and cyberspace. It is a market that is growing even as the market for traditional high-end microprocessors is being impacted as the typical consumer finds less and less reason to own a desktop computer or even a laptop, finding their cyberneeds better met by a smartphone or tablet and more and more computation is moved into the cloud. Thanks to their relatively low price tags, microcontrollers are increasingly becoming replacements for more complex discrete circuitry for glueing other digital components together and for implementing complex behavior. Microcontrollers bring the added advantage of being able to have their firmware updated in the field; discrete electronics, not so much.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;One application for tiny microcontrollers is &lt;i&gt;remote sensing&lt;/i&gt;. Because of their small size and frugal power consumption, microcontrollers are useful for deploying digital control and sensing into the physical world, where they can gather intelligence and report back. Playing with remote sensing is easily done with Arduino with the addition of a &lt;a href="http://arduino.cc/en/Main/ArduinoEthernetShield"&gt;Ethernet shield&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Shields in the world of Arduino are daughter boards that provide specialized hardware and peripherals. They are designed with interface pins protruding from their lower surfaces that mate with the connectors or headers on the Arduino board. Those digital connections that they need themselves they take, those that they don't or which can be shared with additional boards they connect to another set of headers on their top surfaces. The Ethernet shield adds an Ethernet RJ45 connector and supporting hardware to provide an Arduino board with a wired network connection. (There are shields which provide wireless connectivity as well; one step at a time.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here is a side view of my Arduino Uno board with the Ethernet shield plugged in on top of it. You can see the metal pins from the shield above plugged into the headers on the Uno below. A CAT5 Ethernet cable is connected to the shield on the left. Below that you can see USB and power cables connecting to the Uno below. Jumper wires are plugged into the headers on the shield.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/6755336573/" title="Arduino + Ethernet Shield: Remote Sensing by John Sloan, on Flickr"&gt;&lt;img src="http://farm8.staticflickr.com/7152/6755336573_b1d408ca05.jpg" width="500" height="281" alt="Arduino + Ethernet Shield: Remote Sensing" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The &lt;a href="http://www.sparkfun.com/"&gt;SparkFun&lt;/a&gt; &lt;a href="http://www.sparkfun.com/products/11022"&gt;Inventor's Kit for Arduino&lt;/a&gt; has all the hardware you need to do several projects that involve reading sensors. I chose to combine two of them, &lt;a href="http://www.oomlout.com/a/products/ardx/circ-09"&gt;CIRC-09&lt;/a&gt; ("Light") that uses a &lt;a href="http://en.wikipedia.org/wiki/Photoresistor"&gt;photoresister&lt;/a&gt; (a device whose resistance changes with the amount of light falling on it), and &lt;a href="http://www.oomlout.com/a/products/ardx/circ-10"&gt;CIRC-10&lt;/a&gt; ("Temperature") that uses a &lt;a href="http://www.analog.com/static/imported-files/data_sheets/TMP35_36_37.pdf"&gt;low voltage temperature sensor&lt;/a&gt; from Analog Devices. The TMP36 temperature sensor is a clever little device that is complex enough that its data sheet deserves a look.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/6755335955/" title="Analog Devices TMP36 Data Sheet Title Page by John Sloan, on Flickr"&gt;&lt;img src="http://farm8.staticflickr.com/7018/6755335955_2d346d34f7.jpg" width="453" height="500" alt="Analog Devices TMP36 Data Sheet Title Page" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Both of these devices can be hooked up to pins on the Arduino board and read using the analog-to-digital convertor built into the chip. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So what about the "remote" part? The Arduino software includes an Ethernet library that has a rudimentary internet protocol (IP) stack that, for example, responds to ping. (The Ethernet library supports DHCP but I gave the board a static IP address on the local private network.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/6755607631/" title="Terminal: Pinging Arduino by John Sloan, on Flickr"&gt;&lt;img src="http://farm8.staticflickr.com/7029/6755607631_154fd6ce4f.jpg" width="500" height="335" alt="Terminal: Pinging Arduino" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;On top of that I added the &lt;a href="https://github.com/sirleech/Webduino"&gt;Webduino&lt;/a&gt; software that allows you to build a &lt;a href="https://docs.google.com/present/view?id=dd8gqxt8_5c8w9qfg3&amp;amp;pli=1"&gt;tiny web server&lt;/a&gt; that runs on the Arduino board. This web server, when interrogated by the browser on my Mac desktop, responds with a measure of the amount of light impinging on the photoresistor and the temperature in both Centigrade and Fahrenheit. Here's what it looks like, right from Safari.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/6755336011/" title="Web Browser: Remote Sensing by John Sloan, on Flickr"&gt;&lt;img src="http://farm8.staticflickr.com/7159/6755336011_ffa8ce2e92.jpg" width="500" height="258" alt="Web Browser: Remote Sensing" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I compute the light measurement to look like a percentage, but  some calibration might be necessary for other applications. Still, it is easy for the software to tell the difference between night and day or whether room lights are on or off.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here's a photograph of the entire fixture from above. The photoresistor is on the left and the temperature sensor is on the right on the breadboard, but they are so tiny that the jumper wires make them hard to see. Green, yellow and blue are sensor wires (the green one is merely reading the power bus), red are for power, and brown are for ground.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/6755337079/" title="Arduino + Ethernet Shield: Remote Sensing by John Sloan, on Flickr"&gt;&lt;img src="http://farm8.staticflickr.com/7145/6755337079_6b1ebf0eb3.jpg" width="281" height="500" alt="Arduino + Ethernet Shield: Remote Sensing" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here is the complete source code for my remote sensing project. It's not long. The underlying libraries do most of the work.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;pre&gt;#include &amp;lt;&lt;span style="color:#CC6600;"&gt;SPI&lt;/span&gt;.h&amp;gt;&lt;br /&gt;#include &amp;lt;Dhcp.h&amp;gt;&lt;br /&gt;#include &amp;lt;Dns.h&amp;gt;&lt;br /&gt;#include &amp;lt;&lt;span style="color:#CC6600;"&gt;Ethernet&lt;/span&gt;.h&amp;gt;&lt;br /&gt;#include &amp;lt;&lt;span style="color:#CC6600;"&gt;EthernetClient&lt;/span&gt;.h&amp;gt;&lt;br /&gt;#include &amp;lt;&lt;span style="color:#CC6600;"&gt;EthernetServer&lt;/span&gt;.h&amp;gt;&lt;br /&gt;#include &amp;lt;EthernetUdp.h&amp;gt;&lt;br /&gt;#include &amp;lt;&lt;span style="color:#CC6600;"&gt;WebServer&lt;/span&gt;.h&amp;gt;&lt;br /&gt;#include &amp;lt;util.h&amp;gt;&lt;br /&gt;#include &amp;lt;avr/pgmspace.h&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;byte&lt;/span&gt; lightLevel = 0;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;float&lt;/span&gt; temperatureCentigrade = 0;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;float&lt;/span&gt; temperatureFarenheit = 0;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;unsigned&lt;/span&gt; &lt;span style="color:#CC6600;"&gt;long&lt;/span&gt; then = 0;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;void&lt;/span&gt; getIndexHtml(&lt;span style="color:#CC6600;"&gt;WebServer&lt;/span&gt; &amp;amp; server, &lt;span style="color:#CC6600;"&gt;WebServer&lt;/span&gt;::&lt;span style="color:#CC6600;"&gt;ConnectionType&lt;/span&gt; type, &lt;span style="color:#CC6600;"&gt;char&lt;/span&gt; * urlTail, bool tailComplete) {&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;server.&lt;span style="color:#CC6600;"&gt;httpSuccess&lt;/span&gt;();&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;if&lt;/span&gt; (type == &lt;span style="color:#CC6600;"&gt;WebServer&lt;/span&gt;::&lt;span style="color:#CC6600;"&gt;HEAD&lt;/span&gt;) { &lt;span style="color:#CC6600;"&gt;return&lt;/span&gt;; }&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;server.&lt;span style="color:#CC6600;"&gt;print&lt;/span&gt;(&lt;span style="color:#006699;"&gt;"&amp;lt;h1&amp;gt;"&lt;/span&gt;);&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;server.&lt;span style="color:#CC6600;"&gt;print&lt;/span&gt;(lightLevel); server.&lt;span style="color:#CC6600;"&gt;print&lt;/span&gt;(&lt;span style="color:#006699;"&gt;'%'&lt;/span&gt;);&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;server.&lt;span style="color:#CC6600;"&gt;print&lt;/span&gt;(&lt;span style="color:#006699;"&gt;' '&lt;/span&gt;);&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;server.&lt;span style="color:#CC6600;"&gt;print&lt;/span&gt;(temperatureCentigrade); server.&lt;span style="color:#CC6600;"&gt;print&lt;/span&gt;(&lt;span style="color:#006699;"&gt;'C'&lt;/span&gt;);&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;server.&lt;span style="color:#CC6600;"&gt;print&lt;/span&gt;(&lt;span style="color:#006699;"&gt;' '&lt;/span&gt;);&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;server.&lt;span style="color:#CC6600;"&gt;print&lt;/span&gt;(temperatureFarenheit); server.&lt;span style="color:#CC6600;"&gt;print&lt;/span&gt;(&lt;span style="color:#006699;"&gt;'F'&lt;/span&gt;);&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;server.&lt;span style="color:#CC6600;"&gt;print&lt;/span&gt;(&lt;span style="color:#006699;"&gt;"&amp;lt;/h1&amp;gt;"&lt;/span&gt;);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;static&lt;/span&gt; const &lt;span style="color:#CC6600;"&gt;int&lt;/span&gt; referencePin = 3;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;static&lt;/span&gt; const &lt;span style="color:#CC6600;"&gt;int&lt;/span&gt; lightPin = 4;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;static&lt;/span&gt; const &lt;span style="color:#CC6600;"&gt;int&lt;/span&gt; temperaturePin = 5;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;void&lt;/span&gt; sense(&lt;span style="color:#CC6600;"&gt;unsigned&lt;/span&gt; &lt;span style="color:#CC6600;"&gt;long&lt;/span&gt; now) {&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;int&lt;/span&gt; referenceRaw = &lt;span style="color:#CC6600;"&gt;analogRead&lt;/span&gt;(referencePin);&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;int&lt;/span&gt; lightRaw = &lt;span style="color:#CC6600;"&gt;analogRead&lt;/span&gt;(lightPin);&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;lightLevel = 100 - ((100UL * lightRaw) / 1023);&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;int&lt;/span&gt; temperatureRaw = &lt;span style="color:#CC6600;"&gt;analogRead&lt;/span&gt;(temperaturePin);&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;float&lt;/span&gt; temperatureVolts = (temperatureRaw * 5.0) / 1023.0;&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;temperatureCentigrade = (temperatureVolts - 0.5) * 100.0;&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;temperatureFarenheit = (temperatureCentigrade * 1.8) + 32.0;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;b&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;Serial&lt;/b&gt;&lt;/span&gt;.&lt;span style="color:#CC6600;"&gt;print&lt;/span&gt;(referenceRaw);&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;b&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;Serial&lt;/b&gt;&lt;/span&gt;.&lt;span style="color:#CC6600;"&gt;print&lt;/span&gt;(&lt;span style="color:#006699;"&gt;' '&lt;/span&gt;);&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;b&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;Serial&lt;/b&gt;&lt;/span&gt;.&lt;span style="color:#CC6600;"&gt;print&lt;/span&gt;(lightRaw);&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;b&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;Serial&lt;/b&gt;&lt;/span&gt;.&lt;span style="color:#CC6600;"&gt;print&lt;/span&gt;(&lt;span style="color:#006699;"&gt;' '&lt;/span&gt;);&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;b&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;Serial&lt;/b&gt;&lt;/span&gt;.&lt;span style="color:#CC6600;"&gt;print&lt;/span&gt;(lightLevel);&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;b&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;Serial&lt;/b&gt;&lt;/span&gt;.&lt;span style="color:#CC6600;"&gt;print&lt;/span&gt;(&lt;span style="color:#006699;"&gt;' '&lt;/span&gt;);&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;b&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;Serial&lt;/b&gt;&lt;/span&gt;.&lt;span style="color:#CC6600;"&gt;print&lt;/span&gt;(temperatureRaw);&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;b&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;Serial&lt;/b&gt;&lt;/span&gt;.&lt;span style="color:#CC6600;"&gt;print&lt;/span&gt;(&lt;span style="color:#006699;"&gt;' '&lt;/span&gt;);&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;b&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;Serial&lt;/b&gt;&lt;/span&gt;.&lt;span style="color:#CC6600;"&gt;print&lt;/span&gt;(temperatureVolts);&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;b&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;Serial&lt;/b&gt;&lt;/span&gt;.&lt;span style="color:#CC6600;"&gt;print&lt;/span&gt;(&lt;span style="color:#006699;"&gt;' '&lt;/span&gt;);&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;b&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;Serial&lt;/b&gt;&lt;/span&gt;.&lt;span style="color:#CC6600;"&gt;print&lt;/span&gt;(temperatureCentigrade);&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;b&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;Serial&lt;/b&gt;&lt;/span&gt;.&lt;span style="color:#CC6600;"&gt;print&lt;/span&gt;(&lt;span style="color:#006699;"&gt;' '&lt;/span&gt;);&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;b&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;Serial&lt;/b&gt;&lt;/span&gt;.&lt;span style="color:#CC6600;"&gt;println&lt;/span&gt;(temperatureFarenheit);&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;then = now;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;delay&lt;/span&gt;(1);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;void&lt;/span&gt; sense() {&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;sense(&lt;span style="color:#CC6600;"&gt;millis&lt;/span&gt;());&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;static&lt;/span&gt; const &lt;span style="color:#CC6600;"&gt;byte&lt;/span&gt; __attribute__((__progmem__)) myMacAddress[] = { 0x90, 0xa2, 0xda, 0x0d, 0x03, 0x4c };&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;static&lt;/span&gt; const &lt;span style="color:#CC6600;"&gt;byte&lt;/span&gt; __attribute__((__progmem__)) myIpAddress[] = { 192, 168, 1, 223 };&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;static&lt;/span&gt; const &lt;span style="color:#CC6600;"&gt;byte&lt;/span&gt; __attribute__((__progmem__)) myGatewayAddress[] = { 192, 168, 1, 1 };&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;static&lt;/span&gt; const &lt;span style="color:#CC6600;"&gt;byte&lt;/span&gt; __attribute__((__progmem__)) mySubnetMask[] = { 255, 255, 255, 0 };&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;WebServer&lt;/span&gt; webServer;&lt;br /&gt;&lt;br /&gt;#define countof(_ARRAY_) (sizeof(_ARRAY_)/sizeof(_ARRAY_[0]))&lt;br /&gt;#define flash2sram(_TO_, _FROM_, _COUNT_) &lt;span style="color:#CC6600;"&gt;byte&lt;/span&gt; _TO_[_COUNT_]; memcpy_P(_TO_, _FROM_, sizeof(_TO_))&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;void&lt;/span&gt; &lt;span style="color:#CC6600;"&gt;&lt;b&gt;setup&lt;/b&gt;&lt;/span&gt;() {&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;b&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;Serial&lt;/b&gt;&lt;/span&gt;.&lt;span style="color:#CC6600;"&gt;begin&lt;/span&gt;(9600);&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;flash2sram(tempMacAddress, myMacAddress, countof(myMacAddress));&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;flash2sram(tempIpAddress, myIpAddress, countof(myIpAddress));&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;flash2sram(tempGatewayAddress, myGatewayAddress, countof(myGatewayAddress));&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;flash2sram(tempSubnetMask, mySubnetMask, countof(mySubnetMask));&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;Ethernet&lt;/span&gt;.&lt;span style="color:#CC6600;"&gt;begin&lt;/span&gt;(tempMacAddress, tempIpAddress, tempGatewayAddress, tempSubnetMask);&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;webServer.&lt;span style="color:#CC6600;"&gt;setDefaultCommand&lt;/span&gt;(&amp;amp;getIndexHtml);&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;webServer.&lt;span style="color:#CC6600;"&gt;addCommand&lt;/span&gt;(&lt;span style="color:#006699;"&gt;"index.html"&lt;/span&gt;, &amp;amp;getIndexHtml);&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;webServer.&lt;span style="color:#CC6600;"&gt;begin&lt;/span&gt;();&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;sense();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;void&lt;/span&gt; &lt;span style="color:#CC6600;"&gt;&lt;b&gt;loop&lt;/b&gt;&lt;/span&gt;() {&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;unsigned&lt;/span&gt; &lt;span style="color:#CC6600;"&gt;long&lt;/span&gt; now = &lt;span style="color:#CC6600;"&gt;millis&lt;/span&gt;();&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;if&lt;/span&gt; ((now - then) &amp;gt; 1000) {&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;sense(now);&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;}&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;webServer.&lt;span style="color:#CC6600;"&gt;processConnection&lt;/span&gt;();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;As is typical, I made this a little more difficult than it needed to be for pedagogical reasons.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;To assist in debugging, I displayed a lot of the partial and final results over the serial port that is part of the ATmega328 microcontroller. This travels back over the USB cable to my desktop where it can be displayed using the serial monitor tool that is part of the Arduino development environment. &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Serial&lt;/span&gt; is a C++ reference to a pre-built object in the Arduino run-time system that provides an API to do this.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/6755336073/" title="Serial Monitor: Remote Sensing by John Sloan, on Flickr"&gt;&lt;img src="http://farm8.staticflickr.com/7148/6755336073_5e577fbf0a.jpg" width="500" height="313" alt="Serial Monitor: Remote Sensing" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;When all of your storage for volatile variables has to fit in two kilobytes of SRAM, it pays to put data that doesn't change somewhere else. You'll notice that, for example, the hard-coded IP addresses all have a mysterious &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;__attribute__((__progmem__))&lt;/span&gt; as part of their definitions. The &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;__attribute__&lt;/span&gt; keyword is a special directive to GNU C++ that can be used to communicate special implementation details to the compiler. The &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;__progmem__&lt;/span&gt; argument, specific to this family of microcontrollers, tells the compiler that the variable to which it is applied resides not in volatile SRAM but in non-volatile &lt;i&gt;program memory&lt;/i&gt;, meaning the flash memory where executable code is normally stored persistently.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Access to program memory on this microcontroller has to be done through a different machine instruction, &lt;i&gt;load program memory&lt;/i&gt; (&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;lpm&lt;/span&gt;), than when accessing &lt;i&gt;data memory&lt;/i&gt; (SRAM). If you are into this kind of thing, you will now realize that the ATmega328 is an example of a &lt;i&gt;&lt;a href="http://en.wikipedia.org/wiki/Harvard_architecture"&gt;Harvard architecture&lt;/a&gt;&lt;/i&gt;, one in which data and instructions are stored and processed separately. The &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;lpm&lt;/span&gt; instruction bridges these two worlds by allowing you to copy from program memory into temporary variables in data memory. (A &lt;i&gt;&lt;a href="http://en.wikipedia.org/wiki/Von_Neumann_architecture"&gt;von Neumann&lt;/a&gt;&lt;/i&gt; architecture is one in which data and instructions are stored in the same memory and may be accessed similarly to one another.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The Arduino and underlying microcontroller software define C/C++ macros (for example, &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;PROGMEM&lt;/span&gt;), data types (&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;prog_char&lt;/span&gt;), and functions (&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;memcpy_P&lt;/span&gt;), that simplify using this mechanism. But I coded the &lt;span class="Apple-style-span"  style=" ;font-family:'courier new';"&gt;__attribute__((__progmem__))&lt;/span&gt; explicitly because the use of the GCC &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;__attribute__ &lt;/span&gt;directive is so common when developing close to bare metal, and for similar reasons, that I knew that many embedded developers reading this would immediately see something they recognize.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;loop&lt;/span&gt; function, the main work loop, I only interrogate the sensors once a second. The call to &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;processConnection&lt;/span&gt; looks to see if a web request has arrived, and if so processes it. The only request I've defined is an HTML &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;GET&lt;/span&gt; for the web page &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;index.html&lt;/span&gt;. Querying that web page on Arduino returns the latest sensed values.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It's pretty impressive what can be done within the resource footprint of a tiny microcontroller. This program takes a little more than half of the thirty-two kilobytes of flash, and a little less than a quarter of the two kilobytes of SRAM not including the stack. That's without much optimization on my part.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Small is beautiful.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28344720-377222610406172710?l=coverclock.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://coverclock.blogspot.com/feeds/377222610406172710/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28344720&amp;postID=377222610406172710' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/377222610406172710'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/377222610406172710'/><link rel='alternate' type='text/html' href='http://coverclock.blogspot.com/2012/01/remote-sensing-with-arduino.html' title='Remote Sensing with Arduino'/><author><name>Chip Overclock</name><uri>http://www.blogger.com/profile/11195242013008369733</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-1xNiFqWVjh8/TWQ1ru5Z6KI/AAAAAAAAABw/kMJyhvluNMI/s220/Chip%2BOverclock%2BAvatar%2B2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28344720.post-8930560830292286590</id><published>2012-01-20T09:20:00.001-07:00</published><updated>2012-01-20T09:22:54.156-07:00</updated><title type='text'>How to Contribute to the Robert Dixon Scholarship Fund</title><content type='html'>&lt;div&gt;I have already been contacted by several old friends and colleagues asking how to contribute to this &lt;a href="http://coverclock.blogspot.com/2012/01/robert-dixon-scholarship-fund.html"&gt;cause&lt;/a&gt;. Write a check, specify that it is to go to the "Robert Dixon Scholarship Fund", and mail it to&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;Wright State University Foundation&lt;/div&gt;&lt;div&gt;3640 Colonel Glenn Hwy.&lt;/div&gt;&lt;div&gt;Dayton, OH 45435&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;The account is already established and I assure that that the &lt;a href="http://www.wright.edu/advancement/foundation/"&gt;Foundation&lt;/a&gt; will be delighted to expeditiously cash your check and send you an official acknowledgement for your generous tax deductible contribution.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;You will also have my own undying gratitude and a promise that I will buy you an appropriate beverage of your choice the next time I see you.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Thanks!&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28344720-8930560830292286590?l=coverclock.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://coverclock.blogspot.com/feeds/8930560830292286590/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28344720&amp;postID=8930560830292286590' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/8930560830292286590'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/8930560830292286590'/><link rel='alternate' type='text/html' href='http://coverclock.blogspot.com/2012/01/how-to-contribute-to-robert-dixon.html' title='How to Contribute to the Robert Dixon Scholarship Fund'/><author><name>Chip Overclock</name><uri>http://www.blogger.com/profile/11195242013008369733</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-1xNiFqWVjh8/TWQ1ru5Z6KI/AAAAAAAAABw/kMJyhvluNMI/s220/Chip%2BOverclock%2BAvatar%2B2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28344720.post-8784931267824886611</id><published>2012-01-19T13:01:00.005-07:00</published><updated>2012-01-20T09:19:57.678-07:00</updated><title type='text'>The Robert Dixon Scholarship Fund</title><content type='html'>The &lt;a href="http://www.wright.edu/"&gt;Wright State University&lt;/a&gt; &lt;a href="http://www.wright.edu/advancement/foundation/"&gt;Foundation&lt;/a&gt; has a scholarship fund endowed in honor of Robert Dixon. Bob was the first faculty member hired by Wright State. His first office was in the farm house on the property while the campus was being built. He founded the &lt;a href="http://www.wright.edu/cosm/departments/math/"&gt;Department of Mathematics&lt;/a&gt; and the &lt;a href="http://www.cs.wright.edu/cse/"&gt;Department of Computer Science&lt;/a&gt;. He served as Chair of both of those departments (some more than once) as well as Vice President of the Faculty and occasionally the Director of the Computer Center. Bob was also my, and many others, mentor and thesis advisor. I first had him as a professor in 1975.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/1109253502/" title="Bob Dixon and John Sloan by John Sloan, on Flickr"&gt;&lt;img src="http://farm2.staticflickr.com/1348/1109253502_8877351664.jpg" width="355" height="500" alt="Bob Dixon and John Sloan" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Bob is still around, still writing software and doing math, which is his version of enjoying retirement. I had lunch with him back in November when we were both visiting Dayton Ohio, home of Wright State University. I have Bob to thank for much of what I am and have accomplished over the decades. I am pleased to have been able to contribute to the Robert Dixon Scholarship Fund. It would be great for others to do so too. It would also be great to see others honor their mentors in a similar fashion. Perhaps it's time to reflect on how lucky we have been and to whom we owe in part for our good fortune.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Thanks, Bob.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;Update (2012-01-20)&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I have already been contacted by several old friends and colleagues asking how to contribute to this cause. Write a check, specify that it is to go to the "Robert Dixon Scholarship Fund", and mail it to&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;Wright State University Foundation&lt;/div&gt;&lt;div&gt;3640 Colonel Glenn Hwy.&lt;/div&gt;&lt;div&gt;Dayton, OH 45435&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;The account is already established and I assure that that the Foundation will be delighted to expeditiously cash your check and send you an official acknowledgement for your generous tax deductible contribution.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;You will also have my own undying gratitude and a promise that I will buy you an appropriate beverage of your choice the next time I see you.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Thanks!&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28344720-8784931267824886611?l=coverclock.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://coverclock.blogspot.com/feeds/8784931267824886611/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28344720&amp;postID=8784931267824886611' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/8784931267824886611'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/8784931267824886611'/><link rel='alternate' type='text/html' href='http://coverclock.blogspot.com/2012/01/robert-dixon-scholarship-fund.html' title='The Robert Dixon Scholarship Fund'/><author><name>Chip Overclock</name><uri>http://www.blogger.com/profile/11195242013008369733</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-1xNiFqWVjh8/TWQ1ru5Z6KI/AAAAAAAAABw/kMJyhvluNMI/s220/Chip%2BOverclock%2BAvatar%2B2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28344720.post-3523222892571251795</id><published>2012-01-17T08:55:00.013-07:00</published><updated>2012-01-23T14:58:33.864-07:00</updated><title type='text'>Can what you don't know hurt you?</title><content type='html'>In my recent article &lt;i&gt;&lt;a href="http://coverclock.blogspot.com/2012/01/pulse-width-modulation-with-arduino.html"&gt;Pulse-Width Modulation with Arduino&lt;/a&gt;&lt;/i&gt; I showed a series of screen captures from a &lt;a href="http://www.saleae.com/"&gt;Saleae&lt;/a&gt; &lt;a href="http://www.saleae.com/Logic"&gt;Logic&lt;/a&gt; to illustrate the kinds of square waves you could generate using &lt;a href="http://en.wikipedia.org/wiki/Pulse-width_modulation"&gt;Pulse-Width Modulation&lt;/a&gt; (PWM). The use of the Logic was critical to my understanding of what was going on under the hood in my software. The Logic is a &lt;i&gt;&lt;a href="http://en.wikipedia.org/wiki/Logic_analyzer"&gt;logic analyzer&lt;/a&gt;&lt;/i&gt;: a tool that captures, interprets, and displays signals from digital circuits.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Logic analyzers have been a standard piece of kit for digital hardware designers for decades. They come in a broad range of prices, capabilities, and form factors, from units costing tens of thousands of dollars that support sub-microsecond measurements and require a dedicated equipment cart to wheel them around, to the latest generation of relatively inexpensive devices that connect to your laptop and fit in your shirt pocket. The Logic fits in the latter category. We'll talk more about it in a bit. I've become convinced that devices like the Logic need to become part of the everyday toolkit of software developers like me who routinely deal with real-time events and work close to bare metal.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If you've perused that article on PWM with Arduino, and if you have any experience with &lt;a href="http://www.arduino.cc/"&gt;Arduino&lt;/a&gt;, you can be excused if you thought I had gone off the deep end with my lengthy and seemingly overly complex software to generate a PWM square wave. Under other circumstances, I would have thought so as well. I had a Logic sitting in one of my tool bags and I thought it would be a great idea (and less effort than the alternatives) to use it to create snapshots of the PWM square wave output from my program. My original program was only a dozen or so lines long and was dirt simple. What could possibly go wrong?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The first clue that something was seriously amiss was one of my first Logic traces taken when I was hard-coding the duty cycle, before I'd added the code to read the potentiometer using the analog/digital convertor. (You can click on any of these images to get access to larger sizes.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/6714805443/" title="Saelae Logic: Software Latency by John Sloan, on Flickr"&gt;&lt;img src="http://farm8.staticflickr.com/7159/6714805443_e44487a975.jpg" width="500" height="127" alt="Saelae Logic: Software Latency" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;There are several things not to like about this trace.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;First, I had intended to generate a square wave with a 50% duty cycle, but in this trace the off phase is significantly longer than the on phase, by nearly 13%. The off part of the square wave had significantly more software latency: it was taking me 13% longer to get around to turning the GPIO pin back on. I couldn't account for that in my own code.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Second, the frequency was a lot lower than I thought it should be, given the tiny amount of code I thought I was executing and the real-time delays I had built into my code. I was using the Arduino &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;digitalWrite&lt;/span&gt; function and it was taking a long time to turn the GPIO bit on and off.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It was time to take a deep dive into the open-source of the Arduino run-time system. I was reminded of the various bootloaders I've had to hack in times past: no OS, no multi-threading, everything running in the equivalent of kernel mode, software accessing hardware as directly as possible and routinely using privileged machine instructions. This means that delays can't be accounted for by the kinds of scheduling latency you see when running software under non-real-time multi-tasking operating systems like Linux. Delays mean that my software was doing something, even if that something was busy-waiting for some peripheral hardware to respond.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The first step was to see who called the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;loop&lt;/span&gt; function that is the equivalent to the main function in every Arduino program. A common design pattern in this kind of low level OS-less software is to have a &lt;i&gt;work loop&lt;/i&gt; that is continuously executed. It's a loop because modern microprocessors don't have a &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;halt&lt;/span&gt; instruction; the only mode the central processing unit knows is to continuously execute machine code, even if it's just a tight loop. Operating systems like Linux also have such a work loop, you just don't see it. It consists of the Linux kernel looking for a runnable task to execute. There is always at least one such a task, if nothing else a do-nothing task typically referred to as the &lt;i&gt;idle task&lt;/i&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here's the code in Arduino that calls the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;setup&lt;/span&gt; and the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;loop&lt;/span&gt; functions that are part of every Arduino application program. It is the main program in Arduino that is automatically invoked by the C++ run-time system once it has completed initialization, and it is the complete contents of the file &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;main.cpp&lt;/span&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;p  style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color:#3344fc;"&gt;&lt;span style="color:#921e67;"&gt;#include &amp;lt;arduino.h&amp;gt;&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; min-height: 15.0px"&gt;&lt;br /&gt;&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span style="color:#921e67;"&gt;int&lt;/span&gt; main(&lt;span style="color:#921e67;"&gt;void&lt;/span&gt;)&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;{&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;init();&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; min-height: 15.0px"&gt;&lt;br /&gt;&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span style="color:#921e67;"&gt;#if&lt;/span&gt; defined(USBCON)&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;USB.attach();&lt;/p&gt; &lt;p  style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color:#921e67;"&gt;#endif&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; min-height: 15.0px"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;setup();&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; min-height: 15.0px"&gt;    &lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;&lt;span style="color:#921e67;"&gt;for&lt;/span&gt; (;;) {&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;loop();&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;&lt;span style="color:#921e67;"&gt;if&lt;/span&gt; (serialEventRun) serialEventRun();&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;}&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; min-height: 15.0px"&gt;        &lt;/p&gt; &lt;p color="#921e67" style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; "&gt;&lt;span style="color:#000000;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;&lt;/span&gt;return&lt;span style="color:#000000;"&gt; 0;&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;}&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Pretty simple. It calls its own &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;init&lt;/span&gt; function, it calls the application's &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;setup&lt;/span&gt; function, and then it enters an infinite loop that calls the application's &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;loop&lt;/span&gt; function followed by some code that checks for events on the serial port.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The function &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;serialEventRun&lt;/span&gt; is declared elsewhere as a &lt;i&gt;weak external reference&lt;/i&gt;: it's a function that may not be defined, and if it's not, its address will be set to zero (NULL) instead of causing an error when the Arduino is compiled and linked. This allows Arduino to be compiled for microcontroller chips that do not have a serial port, or in hardware speak, a Universal Asynchronous Receiver/Transmitter (UART), in which case the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;serialEventRun&lt;/span&gt; code is conditionally not included as part of the Arduino run-time system.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The ATmega328P microcontroller I'm using has a serial port, so this code was being executed. This explains why the timing of the off period in the square wave wasn't quite right: my original naive code turned the GPIO bit on, delayed for a while, turned the GPIO bit off, delayed for a while, and then the main program was doing some additional work. That's when I added the more complex mechanism that computed a variable delay.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I tackled the second problem by looking the implementation of the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;digitalWrite&lt;/span&gt; function.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span style="color:#921e67;"&gt;void&lt;/span&gt; digitalWrite(uint8_t pin, uint8_t val)&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;{&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;uint8_t timer = digitalPinToTimer(pin);&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;uint8_t bit = digitalPinToBitMask(pin);&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;uint8_t port = digitalPinToPort(pin);&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;&lt;span style="color:#921e67;"&gt;volatile&lt;/span&gt; uint8_t *out;&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; min-height: 15.0px"&gt;&lt;br /&gt;&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;&lt;span style="color:#921e67;"&gt;if&lt;/span&gt; (port == NOT_A_PIN) &lt;span style="color:#921e67;"&gt;return&lt;/span&gt;;&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; min-height: 15.0px"&gt;&lt;br /&gt;&lt;/p&gt; &lt;p  style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color:#508f73;"&gt;&lt;span style="color:#000000;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;&lt;/span&gt;// If the pin that support PWM output, we need to turn it off&lt;/p&gt; &lt;p  style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color:#508f73;"&gt;&lt;span style="color:#000000;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;&lt;/span&gt;// before doing a digital write.&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;&lt;span style="color:#921e67;"&gt;if&lt;/span&gt; (timer != NOT_ON_TIMER) turnOffPWM(timer);&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; min-height: 15.0px"&gt;&lt;br /&gt;&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;out = portOutputRegister(port);&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; min-height: 15.0px"&gt;&lt;br /&gt;&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;uint8_t oldSREG = SREG;&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;cli();&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; min-height: 15.0px"&gt;&lt;br /&gt;&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;&lt;span style="color:#921e67;"&gt;if&lt;/span&gt; (val == LOW) {&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;*out &amp;amp;= ~bit;&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;} &lt;span style="color:#921e67;"&gt;else&lt;/span&gt; {&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;*out |= bit;&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;}&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; min-height: 15.0px"&gt;&lt;br /&gt;&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;SREG = oldSREG;&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;}&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This function in Arduino is doing a lot of computation to derive a register address and bit mask from an pin number, and it does it every time. A pin number in Arduino is an abstraction that simplifies the use of the GPIO pins by mapping a number printed on the actual Arduino circuit board to a GPIO register address and bit mask.  This mapping may not seem like much overhead, but Jean-Claude Wippler of &lt;a href="http://jeelabs.org/about/"&gt;JeeLabs&lt;/a&gt; has &lt;a href="http://jeelabs.org/2010/01/06/pin-io-performance/"&gt;characterized&lt;/a&gt; the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;digitalWrite&lt;/span&gt; function as taking as long as &lt;i&gt;fifty-eight times&lt;/i&gt; (update from Jean-Claude: &lt;i&gt;twenty-nine times&lt;/i&gt;) more processor cycles than a direct register write. So I added the code to my own &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;setup&lt;/span&gt; function to compute the register address and bit mask once, and then added code to do direct register reads and writes in my &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;loop&lt;/span&gt; function. After that it was just some minor tweaks here and there to get the timing right.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Then I added the code using the Arduino &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;analogRead&lt;/span&gt; function to sense the value of the potentiometer at the beginning of every square wave period, which was every one hundred iterations of my &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;loop&lt;/span&gt; function. My next Logic trace looked like this.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/6696115107/" title="Saleae Logic: Bounce in Square Wave by John Sloan, on Flickr"&gt;&lt;img src="http://farm8.staticflickr.com/7157/6696115107_0a18d74db8.jpg" width="500" height="127" alt="Saleae Logic: Bounce in Square Wave" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;You can see the bounce in the GPIO pin output at the beginning of every square wave. So the next step was to look at the Arduino &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;analogRead&lt;/span&gt; function.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span style="color:#921e67;"&gt;int&lt;/span&gt; analogRead(uint8_t pin)&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;{&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;uint8_t low, high;&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; min-height: 15.0px"&gt;&lt;br /&gt;&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span style="color:#921e67;"&gt;#if&lt;/span&gt; defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)&lt;/p&gt; &lt;p  style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color:#508f73;"&gt;&lt;span style="color:#000000;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style="color:#921e67;"&gt;if&lt;/span&gt;&lt;span style="color:#000000;"&gt; (pin &amp;gt;= 54) pin -= 54; &lt;/span&gt;// allow for channel or pin numbers&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span style="color:#921e67;"&gt;#elif&lt;/span&gt; defined(__AVR_ATmega32U4__)&lt;/p&gt; &lt;p  style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color:#508f73;"&gt;&lt;span style="color:#000000;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style="color:#921e67;"&gt;if&lt;/span&gt;&lt;span style="color:#000000;"&gt; (pin &amp;gt;= 18) pin -= 18; &lt;/span&gt;// allow for channel or pin numbers&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color: #921e67"&gt;#else&lt;/p&gt; &lt;p  style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color:#508f73;"&gt;&lt;span style="color:#000000;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style="color:#921e67;"&gt;if&lt;/span&gt;&lt;span style="color:#000000;"&gt; (pin &amp;gt;= 14) pin -= 14; &lt;/span&gt;// allow for channel or pin numbers&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color: #921e67"&gt;#endif&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; min-height: 15.0px"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span style="color:#921e67;"&gt;#if&lt;/span&gt; defined(__AVR_ATmega32U4__)&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;pin = analogPinToChannel(pin);&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;ADCSRB = (ADCSRB &amp;amp; ~(1 &amp;lt;&amp;lt; MUX5)) | (((pin &amp;gt;&amp;gt; 3) &amp;amp; 0x01) &amp;lt;&amp;lt; MUX5);&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span style="color:#921e67;"&gt;#elif&lt;/span&gt; defined(ADCSRB) &amp;amp;&amp;amp; defined(MUX5)&lt;/p&gt; &lt;p  style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color:#508f73;"&gt;&lt;span style="color:#000000;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;&lt;/span&gt;// the MUX5 bit of ADCSRB selects whether we're reading from channels&lt;/p&gt; &lt;p  style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color:#508f73;"&gt;&lt;span style="color:#000000;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;&lt;/span&gt;// 0 to 7 (MUX5 low) or 8 to 15 (MUX5 high).&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;ADCSRB = (ADCSRB &amp;amp; ~(1 &amp;lt;&amp;lt; MUX5)) | (((pin &amp;gt;&amp;gt; 3) &amp;amp; 0x01) &amp;lt;&amp;lt; MUX5);&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color: #921e67"&gt;#endif&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; min-height: 15.0px"&gt;  &lt;/p&gt; &lt;p  style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color:#508f73;"&gt;&lt;span style="color:#000000;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;&lt;/span&gt;// set the analog reference (high two bits of ADMUX) and select the&lt;/p&gt; &lt;p  style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color:#508f73;"&gt;&lt;span style="color:#000000;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;&lt;/span&gt;// channel (low 4 bits).  this also sets ADLAR (left-adjust result)&lt;/p&gt; &lt;p  style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color:#508f73;"&gt;&lt;span style="color:#000000;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;&lt;/span&gt;// to 0 (the default).&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span style="color:#921e67;"&gt;#if&lt;/span&gt; defined(ADMUX)&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;ADMUX = (analog_reference &amp;lt;&amp;lt; 6) | (pin &amp;amp; 0x07);&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color: #921e67"&gt;#endif&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; min-height: 15.0px"&gt;&lt;br /&gt;&lt;/p&gt; &lt;p  style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color:#508f73;"&gt;&lt;span style="color:#000000;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;&lt;/span&gt;// without a delay, we seem to read from the wrong channel&lt;/p&gt; &lt;p  style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color:#508f73;"&gt;&lt;span style="color:#000000;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;&lt;/span&gt;//delay(1);&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; min-height: 15.0px"&gt;&lt;br /&gt;&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span style="color:#921e67;"&gt;#if&lt;/span&gt; defined(ADCSRA) &amp;amp;&amp;amp; defined(ADCL)&lt;/p&gt; &lt;p  style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color:#508f73;"&gt;&lt;span style="color:#000000;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;&lt;/span&gt;// start the conversion&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;sbi(ADCSRA, ADSC);&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; min-height: 15.0px"&gt;&lt;br /&gt;&lt;/p&gt; &lt;p  style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color:#508f73;"&gt;&lt;span style="color:#000000;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;&lt;/span&gt;// ADSC is cleared when the conversion finishes&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;&lt;span style="color:#921e67;"&gt;while&lt;/span&gt; (bit_is_set(ADCSRA, ADSC));&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; min-height: 15.0px"&gt;&lt;br /&gt;&lt;/p&gt; &lt;p  style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color:#508f73;"&gt;&lt;span style="color:#000000;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;&lt;/span&gt;// we have to read ADCL first; doing so locks both ADCL&lt;/p&gt; &lt;p  style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color:#508f73;"&gt;&lt;span style="color:#000000;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;&lt;/span&gt;// and ADCH until ADCH is read.  reading ADCL second would&lt;/p&gt; &lt;p  style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color:#508f73;"&gt;&lt;span style="color:#000000;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;&lt;/span&gt;// cause the results of each conversion to be discarded,&lt;/p&gt; &lt;p  style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color:#508f73;"&gt;&lt;span style="color:#000000;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;&lt;/span&gt;// as ADCL and ADCH would be locked when it completed.&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;low  = ADCL;&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;high = ADCH;&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color: #921e67"&gt;#else&lt;/p&gt; &lt;p  style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color:#508f73;"&gt;&lt;span style="color:#000000;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;&lt;/span&gt;// we &lt;span style="text-decoration: underline"&gt;dont&lt;/span&gt; have an ADC, return 0&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;low  = 0;&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;high = 0;&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color: #921e67"&gt;#endif&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; min-height: 15.0px"&gt;&lt;br /&gt;&lt;/p&gt; &lt;p  style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color:#508f73;"&gt;&lt;span style="color:#000000;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;&lt;/span&gt;// combine the two bytes&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;&lt;span style="color:#921e67;"&gt;return&lt;/span&gt; (high &amp;lt;&amp;lt; 8) | low;&lt;/p&gt; &lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco"&gt;}&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;There is again a lot of mapping from the abstract pin number to the actual hardware resources. But there isn't anything that obviously links this code to the square wave output pin, which is different from the input pin for the potentiometer. Next step was the &lt;i&gt;567 page&lt;/i&gt; Atmel &lt;a href="http://www.atmel.com/dyn/resources/prod_documents/doc8271.pdf"&gt;reference manual&lt;/a&gt; for this family of microcontrollers. Also, the Arduino Uno circuit board &lt;a href="http://arduino.cc/en/uploads/Main/Arduino_Uno_Rev3-schematic.pdf"&gt;schematic&lt;/a&gt; was worth a look.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/6721752027/" title="Atmel ATmega Data Sheet Title Page by John Sloan, on Flickr"&gt;&lt;img src="http://farm8.staticflickr.com/7169/6721752027_e070601a06.jpg" width="455" height="500" alt="Atmel ATmega Data Sheet Title Page" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;567 pages is not long compared to other processor reference manuals. When you are working close to bare metal you quickly learn that more detail is better. You'll groan when you find the manufacturer's reference manual for the microcontroller you are using is only 100 pages long. You know it's going to be relatively useless. (Simpler devices may have perfectly serviceable data sheets of only a dozen pages.) You'll be tempted to send candy and flowers to vendors whose reference manuals have a good table of contents and index. A searchable PDF is also a very good thing indeed.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/6721752157/" title="Arduino Uno Revision 3 Schematic by John Sloan, on Flickr"&gt;&lt;img src="http://farm8.staticflickr.com/7026/6721752157_5905576819.jpg" width="500" height="388" alt="Arduino Uno Revision 3 Schematic" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Even if you're not a hardware person, if you work close to bare metal you should get used to reading schematics. Regardless of your age and your eyesight, unless you have a printer that prints pages the size of movie posters, buy a magnifying glass and get used to using it. You will be amazed at what you learn when you start following circuit traces from a GPIO pin that is misbehaving and discover to what it is really connected. You might even earn some respect from your hardware colleagues. Maybe.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The Atmel documentation warns against making changes in digital output pins close in time to doing analog/digital conversions. Rather than hosing up my timing that I worked so hard to refine, I decided to limit the number of times I read the potentiometer to four times a second. I figured this would minimize the number of times I hosed up the square wave while still giving me a reasonable response time between turning the dial on the potentiometer and the electric motor speeding up or slowing down. That seemed to work okay.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So what's the point of all of this?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I wouldn't even have known of any of these issues had I not hooked up the Saleae Logic and looked in detail at what was happening on microsecond scales. In fact, even with my original naive software design, the electric motor sped up and slowed down appropriately when I turned the potentiometer. For most applications of Arduino, that's something we call success.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;But that's not always the case, with Arduino or other real-time applications of microcontrollers and microprocessors. For many products on which I've worked, what happens at the microsecond scale matters. If it doesn't matter to me, it may matter to another piece of hardware that has a much higher frequency attention span than I do. It may be that you, like me, routinely work on real-time systems which are expected to have 99.999% uptime. Or on which lives depend. Or perhaps you just don't want to be humiliated when something you wrote goes pear-shaped in the field in a failure that's visible to hundreds of people.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;That's why I think tools like logic analyzers in general, and for lower speed applications, PC and Mac based tools like the Saleae Logic in particular, need to be part of every real-time software developer's toolkit. The Saleae comes in eight and sixteen channel models at prices of around US$150 to US$300. The eight channel model samples at 24MHz and the sixteen channel model can sample at 100MHz. I have the less expensive model and it is likely to be all I will ever need for this kind of work. The Logic can also decode common serial communication and bus standards at signal levels of 5V and below such as asynchronous serial, I&lt;sup&gt;2&lt;/sup&gt;C, and SPI. I used it to &lt;a href="http://coverclock.blogspot.com/2011/04/deconstructing-ardrone-part-5.html"&gt;verify the pin-outs on the diagnostic serial port&lt;/a&gt; of the AR.drone.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The device has a tiny logic pod smaller than my penknife, barely big enough for a company property sticker, to which you connect a wiring harness with eight signal inputs plus ground. You can connect the wires on the harness directly to pins on a circuit board or use the detachable logic clips.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/5610306042/" title="Saleae Logic Contents by John Sloan, on Flickr"&gt;&lt;img src="http://farm6.staticflickr.com/5021/5610306042_30912cfee7.jpg" width="500" height="281" alt="Saleae Logic Contents" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The pod is a rugged piece made of machined aluminum, which, let's admit, is kind of sexy. It all goes into a little zippered case that fits handily in my tool bag.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/5610304710/" title="Saleae Logic Case by John Sloan, on Flickr"&gt;&lt;img src="http://farm6.staticflickr.com/5067/5610304710_3579294fef.jpg" width="500" height="281" alt="Saleae Logic Case" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The pod connects via USB 2.0 to your PC or Mac on which the Logic software runs. I run Logic on both a Windows 7 netbook I use for field troubleshooting and on my Mac Mini desktop in my home office. Here's a photograph of me using the Logic with the netbook on the AR.drone.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/5589314731/" title="Saleae Logic Analyzer and AR.drone by John Sloan, on Flickr"&gt;&lt;img src="http://farm6.staticflickr.com/5066/5589314731_ddecc8cced.jpg" width="500" height="281" alt="Saleae Logic Analyzer and AR.drone" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;Other similar tools provide comparable capabilities at competitive prices. There is really no excuse not to use one of these tools. Sometimes you really need to know what's going on under the hood. What you don't know might just hurt you.&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28344720-3523222892571251795?l=coverclock.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://coverclock.blogspot.com/feeds/3523222892571251795/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28344720&amp;postID=3523222892571251795' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/3523222892571251795'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/3523222892571251795'/><link rel='alternate' type='text/html' href='http://coverclock.blogspot.com/2012/01/can-what-you-dont-know-hurt-you.html' title='Can what you don&apos;t know hurt you?'/><author><name>Chip Overclock</name><uri>http://www.blogger.com/profile/11195242013008369733</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-1xNiFqWVjh8/TWQ1ru5Z6KI/AAAAAAAAABw/kMJyhvluNMI/s220/Chip%2BOverclock%2BAvatar%2B2.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28344720.post-1857202201922825654</id><published>2012-01-16T09:14:00.026-07:00</published><updated>2012-01-19T11:02:08.463-07:00</updated><title type='text'>Pulse-Width Modulation with Arduino</title><content type='html'>One of the most used features on microcontrollers and microprocessors that you find in embedded systems are the General Purpose I/O (GPIO) pins. These are pins directly on the chip that can be set to low (ground) or high (typically 3.3 or 5 volts) values, or whose digital voltages can be read and turned in to bits, under the control of software running on the chip.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;System-on-a-chip (SoC) solutions are so-called because they incorporate one or more processor cores with on-chip peripheral controllers that handle I/O and other functions commonly used in embedded systems. Although many of these controllers can handle relatively sophisticated functions like Ethernet physical layer protocols or specialized communication busses like I&lt;sup&gt;2&lt;/sup&gt;C, SoCs inevitably have at least a handful of pins that can be manipulated by an on-chip GPIO controller.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This capability gives the embedded developer a way to implement non-standard hardware protocols (or, sometimes, implement a protocol that the existing SoC controller didn't quite get right), to talk to application specific devices like a Field Programmable Gate Array (FPGA), to sense a button or switch on the front panel, or even to do something as mundane as blink a Light Emitting Diode (LED). This last example is exactly what was going on in my article &lt;i&gt;&lt;a href="http://coverclock.blogspot.com/2012/01/getting-to-hello-world-with-arduino.html"&gt;Getting to Hello World with Arduino&lt;/a&gt;&lt;/i&gt;: some simple software used the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;digitalWrite&lt;/span&gt; function to blink an LED. If you spend five minutes poking around in the Arduino run-time software you will see that ultimately this is implemented by just setting and clearing a bit at a memory location that represents a memory-mapped register in a GPIO controller built into the little eight-bit ATmega328P chip. (This is also exactly what was going on in my article &lt;i&gt;&lt;a href="http://coverclock.blogspot.com/2011/01/memory-mapped-devices-on-beagle-board_24.html"&gt;Memory Mapped Devices on the BeagleBoard with Android&lt;/a&gt;&lt;/i&gt; except with a Texas Instruments DM3730 SoC with a powerful thirty-two bit ARM Cortex-A8 processor running Linux and Android.)&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;So let's suppose that we hook up a &lt;a href="http://www.radioshack.com/home/index.jsp"&gt;Radio Shack&lt;/a&gt; &lt;a href="http://www.radioshack.com/product/index.jsp?productId=2103962"&gt;digital multimeter&lt;/a&gt; and a &lt;a href="http://www.saleae.com/"&gt;Saleae&lt;/a&gt; &lt;a href="http://www.saleae.com/logic/"&gt;Logic&lt;/a&gt; analyzer to an Arduino and look at a GPIO pin. What might we see? (Ignore for a moment the explosion of wiring on the breadboard. We'll get to that in a moment.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/6708381621/" title="Digital Voltmeter: Programmed 0% PWM Duty Cycle by John Sloan, on Flickr"&gt;&lt;img src="http://farm8.staticflickr.com/7021/6708381621_690bb86f93.jpg" width="500" height="281" alt="Digital Voltmeter: Programmed 0% PWM Duty Cycle" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The multimeter is reading negative millivolts, which I think is just noise below the logic level of the GPIO pin. (You can click on any of these photographs to get access to larger sizes.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/6708380555/" title="Saleae Logic: Programmed 0% PWM Duty Cycle by John Sloan, on Flickr"&gt;&lt;img src="http://farm8.staticflickr.com/7016/6708380555_0601378273.jpg" width="500" height="128" alt="Saleae Logic: Programmed 0% PWM Duty Cycle" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Channel zero on the logic analyzer is reading a logic zero. So far, not that interesting. So let's write a little Arduino code to set the GPIO pin to a logic one value, just as we did to blink the LED in the previous article.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/6708383271/" title="Digital Voltmeter: Programmed 100% PWM Duty Cycle by John Sloan, on Flickr"&gt;&lt;img src="http://farm8.staticflickr.com/7157/6708383271_e367768bcb.jpg" width="500" height="281" alt="Digital Voltmeter: Programmed 100% PWM Duty Cycle" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The multimeter reads about 4.5 volts. (That should nominally be five volts; the reason it's not I believe is that I'm actually driving four GPIO pins all at one time; it simplified the wiring.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/6708380979/" title="Saleae Logic: Programmed 100% PWM Duty Cycle by John Sloan, on Flickr"&gt;&lt;img src="http://farm8.staticflickr.com/7146/6708380979_17740ac38c.jpg" width="500" height="128" alt="Saleae Logic: Programmed 100% PWM Duty Cycle" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Channel zero on the logic analyzer reads a logic one. That's what my Digital Signal Processor (DSP) buddies would call a DC (for direct current) signal, by which they mean it's a constant value. They would use the term &lt;i&gt;unmodulated&lt;/i&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So lets say we write a little more Arduino code to modulate the output of the GPIO pin, that is, turn it on and off. We'll turn it on for the same amount of time we turn it off. That means the pin will be on half, or 50%, of the time, and off the other half of the time. When it's on, it will output its full voltage, and when it's off it will be zero volts or ground. We'll refer to this by saying that the output of the GPIO pin has a &lt;i&gt;50% duty cycle&lt;/i&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/6708380793/" title="Saleae Logic: Programmed 50% PWM Duty Cycle by John Sloan, on Flickr"&gt;&lt;img src="http://farm8.staticflickr.com/7158/6708380793_0e4d4bb3d4.jpg" width="500" height="128" alt="Saleae Logic: Programmed 50% PWM Duty Cycle" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;You can see that the output of the GPIO pin is a square wave with a period of a smidge over two milliseconds. In a bit you will see that I was shooting for a delay of two milliseconds in the Arduino software. The actual duty cycle, measured by the analyzer, and thanks to slop in timing, is a little over 50%. Any guess as to what the multimeter will read?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/6708382727/" title="Digital Voltmeter: Programmed 25% PWM Duty Cycle by John Sloan, on Flickr"&gt;&lt;img src="http://farm8.staticflickr.com/7165/6708382727_0a96394e3a.jpg" width="500" height="281" alt="Digital Voltmeter: Programmed 25% PWM Duty Cycle" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The multimeter reads this square wave as a voltage of a little over 50% of the maximum. That's because the  multimeter is expecting a constant DC input and it is reporting the average voltage over some time window. It turns out a lot of electrical devices work this way. So if we can generalize this, we can fool other devices to think they're getting different voltages the same way we fooled the multimeter, and do it all under software control. Let's try an 80% duty cycle.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/6708380897/" title="Saleae Logic: Programmed 80% PWM Duty Cycle by John Sloan, on Flickr"&gt;&lt;img src="http://farm8.staticflickr.com/7162/6708380897_98f9051338.jpg" width="500" height="128" alt="Saleae Logic: Programmed 80% PWM Duty Cycle" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So far so good. What does the multimeter say?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/6708383835/" title="Digital Voltmeter: Programmed 80% PWM Duty Cycle by John Sloan, on Flickr"&gt;&lt;img src="http://farm8.staticflickr.com/7029/6708383835_80a0e0b9a6.jpg" width="500" height="281" alt="Digital Voltmeter: Programmed 80% PWM Duty Cycle" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Yep, that's about right. What we've just done is reinvent &lt;a href="http://en.wikipedia.org/wiki/Pulse-width_modulation"&gt;Pulse-Width Modulation&lt;/a&gt; (PWM). PWM is a method of modulation that encodes a digital signal by altering the duty cycle of a square wave, that is, by changing the width of the pulse. PWM can be used as a way of encoding bits onto a wire, although not in any modern communications system of which I am aware. But its ability to fool electrical devices into thinking they are seeing different voltages is used in lots of applications.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Digital power supplies, ranging from the desktop unit you might see on a lab bench to the unit inside the wall wart that is powering your laptop, use PWM to change 120V from your wall outlet to whatever output voltage is desired. Digitally controlled PWM circuitry replaced old heavy transformers which were nothing more than heavy iron cores with a lot of copper wire wrapped around them, enabling wall warts to become pocket sized and to be much more efficient. The variable speed cooling fans in your computer are probably controlled by firmware that is reading a temperature sensor and then using PWM to apparently alter the voltage going to the electric motors in the fans. The popular &lt;a href="http://ardrone.parrot.com/parrot-ar-drone/usa/"&gt;AR.drone&lt;/a&gt;, a WiFi-controlled quadcopter toy that I've obsessively written about, uses PWM to individually control the speed of each of the four electric motors that drive its fan blades.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Indeed, PWM is so widely used that many SoC chips include a dedicated PWM controller that modulates the output of a GPIO pin at a frequency synchronized to a hardware timer. The ATmega328P chip used in Arduino is such an SoC. PWM requires no more work on the software developer's part than using the Arduino &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;analogWrite&lt;/span&gt; function to set a duty cycle encoded as a number from 0 to 255.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;But what would the fun be in that?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;PWM has long been on my list of things with which to experiment. Naturally, I insisted on doing it the hard way: by writing a PWM algorithm completely in software without taking advantage of the PWM controller built into the chip. I combined two of the circuits included in the &lt;a href="http://www.sparkfun.com/"&gt;SparkFun&lt;/a&gt; &lt;a href="http://www.sparkfun.com/products/10173"&gt;Inventor's Kit for Arduino&lt;/a&gt;, &lt;a href="http://www.oomlout.com/a/products/ardx/circ-03"&gt;CIRC-03&lt;/a&gt; ("Transistors and Motors") and &lt;a href="http://www.oomlout.com/a/products/ardx/circ-08"&gt;CIRC-08&lt;/a&gt; ("Potentiometers"), to create an electric motor whose speed could be digitally controlled by turning the dial on a potentiometer. The voltage drop across the potentiometer, a kind of variable resister that can be tuned by turning its dial, is read periodically by the software using an analog-to-digital (A/D) convertor built into the SoC that returns a value in the range 0 to 1023, corresponding to a range of zero to five volts from the reference source. That value is used to compute a duty cycle in the range 0 to 100 for the PWM square wave. The square wave is then fed into a transistor, which is used to switch power on and off to the electric motor. In the photographs above, you can see the electric motor sitting just above the SparkFun fixture, and the blue potentiometer in the lower center with an arrow on its dial.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here's the complete Arduino program. (As usual, the Blogger editor did violence to the indentation.) I broke up the square wave generator (function &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;square&lt;/span&gt;), the timing generator (function &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;timing&lt;/span&gt;), and the potentiometer sensing (function &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;control&lt;/span&gt;) to simplify trying different things, like hard-coding the duty cycle instead of reading it from the potentiometer. The specific mechanism of generating the square wave is a dirt simple one known as &lt;i&gt;time-proportioning&lt;/i&gt;: there is a counter that cycles in the range 0 to 99; the on portion of the square wave begins when the counter is greater than or equal to 100 minus the duty cycle. I also included function &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;toggle&lt;/span&gt; to toggle a GPIO pin as quickly as possible to see what my upper limit on frequency was (best case about 500 Hertz), and function &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;pwm&lt;/span&gt; to use the built-in PWM controller (which is a lot simpler and is what you should do in an actual PWM application).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;pre&gt;&lt;span style="color:#CC6600;"&gt;int&lt;/span&gt; sensorPin = 0;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;int&lt;/span&gt; motorPin = 9;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;int&lt;/span&gt; meterPin = 10;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;int&lt;/span&gt; logicPin = 11;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;int&lt;/span&gt; ledPin = 13;&lt;br /&gt;&lt;br /&gt;volatile uint8_t * pointer = 0;&lt;br /&gt;uint8_t mask = 0;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;int&lt;/span&gt; tick = 0;              &lt;span style="color:#7E7E7E;"&gt;/* 0..99 */&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;int&lt;/span&gt; dutyCycle = 0;         &lt;span style="color:#7E7E7E;"&gt;/* 0..100 */&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;unsigned&lt;/span&gt; &lt;span style="color:#CC6600;"&gt;int&lt;/span&gt; period = 20;  &lt;span style="color:#7E7E7E;"&gt;/* microseconds duration */&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;long&lt;/span&gt; sample = 0;           &lt;span style="color:#7E7E7E;"&gt;/* 0.5 seconds */&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;long&lt;/span&gt; iteration = 0;        &lt;span style="color:#7E7E7E;"&gt;/* 0..(sample - 1) */&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;boolean&lt;/span&gt; before = &lt;span style="color:#CC6600;"&gt;false&lt;/span&gt;;    &lt;span style="color:#7E7E7E;"&gt;/* true or false */&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;unsigned&lt;/span&gt; &lt;span style="color:#CC6600;"&gt;long&lt;/span&gt; then = 0;    &lt;span style="color:#7E7E7E;"&gt;/* microseconds elapsed */&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;void&lt;/span&gt; &lt;span style="color:#CC6600;"&gt;&lt;b&gt;setup&lt;/b&gt;&lt;/span&gt;() {&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;pinMode&lt;/span&gt;(motorPin, &lt;span style="color:#006699;"&gt;OUTPUT&lt;/span&gt;);&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;digitalWrite&lt;/span&gt;(motorPin, &lt;span style="color:#006699;"&gt;LOW&lt;/span&gt;);&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;pinMode&lt;/span&gt;(meterPin, &lt;span style="color:#006699;"&gt;OUTPUT&lt;/span&gt;);&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;digitalWrite&lt;/span&gt;(meterPin, &lt;span style="color:#006699;"&gt;LOW&lt;/span&gt;);&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;pinMode&lt;/span&gt;(logicPin, &lt;span style="color:#006699;"&gt;OUTPUT&lt;/span&gt;);&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;digitalWrite&lt;/span&gt;(logicPin, &lt;span style="color:#006699;"&gt;LOW&lt;/span&gt;);&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;pointer = portOutputRegister(digitalPinToPort(motorPin));&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;mask = digitalPinToBitMask(motorPin) | digitalPinToBitMask(meterPin) | digitalPinToBitMask(logicPin) | digitalPinToBitMask(ledPin);&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;sample = 1000000L / period / 4;&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;then = &lt;span style="color:#CC6600;"&gt;micros&lt;/span&gt;();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;void&lt;/span&gt; toggle() {&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;for&lt;/span&gt; (&lt;span style="color:#CC6600;"&gt;long&lt;/span&gt; ii = 0; ii &amp;lt; 25000000; ++ii) {&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;*pointer |= mask;&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;*pointer &amp;amp;= ~mask;&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;void&lt;/span&gt; square() {&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;boolean&lt;/span&gt; state = (tick &amp;gt;= (100 - dutyCycle));&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;if&lt;/span&gt; (state != before) {&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;uint8_t oldSREG = SREG;&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;cli();&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;if&lt;/span&gt; (state) {&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;   &lt;/span&gt;*pointer |= mask;&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;} &lt;span style="color:#CC6600;"&gt;else&lt;/span&gt; {&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;   &lt;/span&gt;*pointer &amp;amp;= ~mask;&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;}&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;SREG = oldSREG;&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;before = state;&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;}&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;tick = (tick + 1) % 100;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;void&lt;/span&gt; timing() {&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;unsigned&lt;/span&gt; &lt;span style="color:#CC6600;"&gt;long&lt;/span&gt; now = &lt;span style="color:#CC6600;"&gt;micros&lt;/span&gt;();&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;unsigned&lt;/span&gt; &lt;span style="color:#CC6600;"&gt;int&lt;/span&gt; duration = now - then;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;if&lt;/span&gt; (duration &amp;lt; period) {&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;delayMicroseconds&lt;/span&gt;(period - duration);&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;}&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;square();&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;then = now;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;void&lt;/span&gt; control() {&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;timing();&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;if&lt;/span&gt; (iteration == 0) {&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;long&lt;/span&gt; value = &lt;span style="color:#CC6600;"&gt;analogRead&lt;/span&gt;(sensorPin) / (1024 / 16);&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;dutyCycle = (value * 100) / 15;&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;}&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;iteration = (iteration + 1) % sample;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;void&lt;/span&gt; pwm() {&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;dutyCycle = &lt;span style="color:#CC6600;"&gt;analogRead&lt;/span&gt;(sensorPin) / 4; &lt;span style="color:#7E7E7E;"&gt;/* 0..255 */&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;analogWrite&lt;/span&gt;(motorPin, dutyCycle);&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;analogWrite&lt;/span&gt;(meterPin, dutyCycle);&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;analogWrite&lt;/span&gt;(logicPin, dutyCycle);&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;delay&lt;/span&gt;(250);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#CC6600;"&gt;void&lt;/span&gt; &lt;span style="color:#CC6600;"&gt;&lt;b&gt;loop&lt;/b&gt;&lt;/span&gt;() {&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;control();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;I used the hard-coded duty cycle capability to do the test cases presented above so I could get as close to the desired values as possible. But lest you think the potentiometer solution doesn't work, here's a test run in which I lovingly hand dialed the potentiometer to get a duty cycle of about 66% and a voltage of about three volts.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/6708381061/" title="Saleae Logic: Dialed 66% PWM Duty Cycle by John Sloan, on Flickr"&gt;&lt;img src="http://farm8.staticflickr.com/7006/6708381061_2ab7b128df.jpg" width="500" height="128" alt="Saleae Logic: Dialed 66% PWM Duty Cycle" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/6708384371/" title="Digital Voltmeter: Dialed 66% PWM Duty Cycle by John Sloan, on Flickr"&gt;&lt;img src="http://farm8.staticflickr.com/7146/6708384371_29e86f42f2.jpg" width="500" height="281" alt="Digital Voltmeter: Dialed 66% PWM Duty Cycle" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Just for comparison, here's a test run using my &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;pwm&lt;/span&gt; function that uses the built-in PWM generator, at about a 50% duty cycle dialed-in manually using the potentiometer, instead of my purely software-only version. The SoC PWM square wave generator has a higher frequency and its timing is more precise, hence it is able to generate more accurate voltages, and with a lot less effort on my part.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/6708567793/" title="Saleae Logic: Hardware PWM 50% Duty Cycle by John Sloan, on Flickr"&gt;&lt;img src="http://farm8.staticflickr.com/7157/6708567793_361d87659d.jpg" width="500" height="128" alt="Saleae Logic: Hardware PWM 50% Duty Cycle" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/6708568341/" title="Digital Voltmeter: Hardware PWM 50% Duty Cycle by John Sloan, on Flickr"&gt;&lt;img src="http://farm8.staticflickr.com/7147/6708568341_5ea13eceda.jpg" width="500" height="281" alt="Digital Voltmeter: Hardware PWM 50% Duty Cycle" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I don't recommend the do-it-yourself approach for an actual application using PWM. I had to do a lot of work to get the timing to be even as precise as you see here, and to deal with the odd side effect here and there like the A/D conversion causing bounce in the GPIO output pin. But along the way I did learn an awful lot about the Atmel hardware and the Arduino software, as I used the Saleae Logic analyzer to characterize the square wave I was generating. That, I do recommend.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28344720-1857202201922825654?l=coverclock.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://coverclock.blogspot.com/feeds/1857202201922825654/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28344720&amp;postID=1857202201922825654' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/1857202201922825654'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/1857202201922825654'/><link rel='alternate' type='text/html' href='http://coverclock.blogspot.com/2012/01/pulse-width-modulation-with-arduino.html' title='Pulse-Width Modulation with Arduino'/><author><name>Chip Overclock</name><uri>http://www.blogger.com/profile/11195242013008369733</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-1xNiFqWVjh8/TWQ1ru5Z6KI/AAAAAAAAABw/kMJyhvluNMI/s220/Chip%2BOverclock%2BAvatar%2B2.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28344720.post-3197635056804529735</id><published>2012-01-11T10:06:00.014-07:00</published><updated>2012-01-12T13:35:05.933-07:00</updated><title type='text'>Getting to Hello World with Arduino</title><content type='html'>&lt;div style="text-align: left;"&gt;I am not a hardware person. This admission might come as a surprise to my software buddies, who I am always boring with long rants about how things really work under the hood. My hardware buddies would all laugh at the very idea that I might ever claim to be a hardware person. The fact is, I haven't handled discrete electronic parts with intent to build since my undergraduate computer engineering classes circa 1975. That was back when a resistor was the size of a refrigerator. I confess too that I've always been a little jealous of a former colleague and office mate (Hi, Dan!) who was always doing really cool stuff with tiny microcontrollers.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I decided it was time to do something about my ignorance. I ordered a &lt;a href="http://www.sparkfun.com/"&gt;SparkFun&lt;/a&gt; &lt;a href="http://www.sparkfun.com/products/10173"&gt;Inventor's Kit for Arduino&lt;/a&gt;!&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238); -webkit-text-decorations-in-effect: underline; "&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 0); "&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/6679655633/" title="SparkFun Inventor's Kit by John Sloan, on Flickr"&gt;&lt;img src="http://farm8.staticflickr.com/7028/6679655633_25d4139361.jpg" width="500" height="281" alt="SparkFun Inventor's Kit" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.arduino.cc/"&gt;Arduino&lt;/a&gt; is an open-source/open-hardware project to create a platform on which to teach electronics and embedded development and to use as a basis for simple (or not so simple) multidisciplinary applications of small microcontrollers. Several versions of the Arduino board are available with variations in the microcontroller and available peripherals. Arduino includes a graphical integrated development environment [1] that supports a C-like language [2] and includes a library of functions [3] to control the various peripherals on the board. It has been widely applied to all sorts of cool stuff from controlling sensor networks in real-life laboratory experiments to animating Christmas lights. Arduino has become so popular that an broad ecosystem of hardware and software has become available based around the various versions of the board.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;(&lt;a href="http://www.sparkfun.com/"&gt;SparkFun&lt;/a&gt; is an online electronics retailer based just up the road in Boulder Colorado. It seems to be staffed with people who love doing interesting things with electronics. Their web site is worth a look. I am merely a satisfied continuing customer.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The Inventor's Kit is a plastic box full of embedded fun that includes an Arduino Uno (revision 3) board with an Atmel ATmega328P eight-bit RISC microcontroller [4] (I'm already getting excited here), a small breadboard for prototyping circuits, a USB cable that connects the board to your PC or MAC for both control and power, and a selection of electronic components ranging from LEDs to a solenoid and about which I know nothing.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/6679655035/" title="SparkFun Inventor's Kit: Contents by John Sloan, on Flickr"&gt;&lt;img src="http://farm8.staticflickr.com/7028/6679655035_a667137c00.jpg" width="500" height="281" alt="SparkFun Inventor's Kit: Contents" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Fortunately it also includes an instruction booklet. The booklet has a series of fourteen projects of increasing complexity that use the components in the kit.&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238); -webkit-text-decorations-in-effect: underline; "&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 0); "&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/6679656033/" title="SparkFun Inventor's Guide: Instruction Manual by John Sloan, on Flickr"&gt;&lt;img src="http://farm8.staticflickr.com/7005/6679656033_d7f2806135.jpg" width="281" height="500" alt="SparkFun Inventor's Guide: Instruction Manual" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238); -webkit-text-decorations-in-effect: underline; "&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 0); "&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I immediately set off to get CIRC-01 "Blink LED" working. The Kit comes with a series of overlays that you lay right on top of the little prototyping breadboard that tell you what to plug where, and the instruction booklet tells you why. It also includes the code to get the project working. The intent here is to teach you the basics about how the microcontroller and each individual component works so you can later unleash your inner mad scientist and use Arduino for your own nefarious purposes.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/6679656573/" title="CIRC-01: Getting Started - Blinking LED by John Sloan, on Flickr"&gt;&lt;img src="http://farm8.staticflickr.com/7002/6679656573_354b194269.jpg" width="500" height="281" alt="CIRC-01: Getting Started - Blinking LED" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In no more than a couple of hours, I managed to (1) assemble the little SparkFun prototyping fixture, (2) install the software off the web onto my Mac, (3)  hook the fixture to my Mac via the USB cable and get it to power up, (4) poke a hole in my thumb and get blood all over everything, (5) wire up the circuit diagram, (6) type in the handful of lines of source code from the booklet, and (7) do a pretty good imitation of a fat old guy who wrote some software to blink an LED.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here's the entire setup. That's the Arduino IDE on the Mac display on the left, and the tiny SparkFun fixture with the Arduino board on the right, with a USB cable providing both power to the fixture and communication with the IDE on the Mac. Yes, that's a magnifying class at the lower right. Did I mention I'm old?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/6679554569/" title="Arduino and SparkFun Inventor's Kit by John Sloan, on Flickr"&gt;&lt;img src="http://farm8.staticflickr.com/7158/6679554569_81479a225e.jpg" width="500" height="281" alt="Arduino and SparkFun Inventor's Kit" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here's a screen snapshot of the IDE. (You can click on any of these images to get access to a larger version.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/6679582245/" title="Arduino IDE on the Mac by John Sloan, on Flickr"&gt;&lt;img src="http://farm8.staticflickr.com/7148/6679582245_e36a1c5e32.jpg" width="500" height="339" alt="Arduino IDE on the Mac" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;And here's a closeup of the board with the LED blinking. Huzzah!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/6679555087/" title="CIRC-01 by John Sloan, on Flickr"&gt;&lt;img src="http://farm8.staticflickr.com/7003/6679555087_c5e9192412.jpg" width="500" height="281" alt="CIRC-01" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/span&gt;&lt;/span&gt;Trust me, if I can do this, anyone can do this. If you've ever wanted to learn some basic electronics and microcontroller programming, or if you have a hankering to put your latest evil experiment under digital control, this could be the platform for you. (You might skip the step requiring medical attention though.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;Update 2012-01-12&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;[1] Not satisfied with the &lt;a href="http://arduino.cc/en/Reference/HomePage"&gt;documentation&lt;/a&gt; nor the &lt;a href="http://en.wikipedia.org/wiki/Arduino"&gt;Wikipedia page&lt;/a&gt; on Arduino, I naturally downloaded the &lt;a href="http://arduino.googlecode.com/files/arduino-1.0-src.tar.gz"&gt;tarball&lt;/a&gt; of the &lt;a href="http://arduino.cc/en/Main/Software"&gt;open source code&lt;/a&gt; from the web site and sucked it into an Eclipse project. The IDE and related host-based tools are written in Java.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;[2] It's actually C++, but the run-time environment presents a much simplified API to the developer compared to other C++ environments with which you may be familiar. It might be too simple for a really complex application. But if you're that motivated you will, like me, want to dig under the hood anyway. Once you do, you'll see a lot of stuff familiar to anyone accustomed to doing embedded development. The lowest level routines to manipulate the hardware reminds me a lot of code in bootloaders that I've had to hack.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;[3] The API you'll use to do the projects in the Kit is written in a way such that you could be excused if you thought it was Java.  I admire the design because it is obvious that a lot of thought has been put into make it as simple as possible for someone who perhaps has only done some Java development to write useful embedded applications. You have programmatic access to the serial port on the microcontroller that connects to your desktop via USB. There is a console tool included in the IDE that gives you access to it, so you can for example print stuff to help you debug.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;[4] Data types: &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;char&lt;/span&gt;, &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;byte&lt;/span&gt; and &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;boolean&lt;/span&gt; are eight bits; &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;int&lt;/span&gt; and &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;word&lt;/span&gt; are sixteen bits; &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;long&lt;/span&gt;, &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;float&lt;/span&gt; and &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;double&lt;/span&gt; are thirty-two bits. The basic register set of the processor is thirty-two eight-bit registers. If you're anything like me, you want to know this.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28344720-3197635056804529735?l=coverclock.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://coverclock.blogspot.com/feeds/3197635056804529735/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28344720&amp;postID=3197635056804529735' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/3197635056804529735'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/3197635056804529735'/><link rel='alternate' type='text/html' href='http://coverclock.blogspot.com/2012/01/getting-to-hello-world-with-arduino.html' title='Getting to Hello World with Arduino'/><author><name>Chip Overclock</name><uri>http://www.blogger.com/profile/11195242013008369733</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-1xNiFqWVjh8/TWQ1ru5Z6KI/AAAAAAAAABw/kMJyhvluNMI/s220/Chip%2BOverclock%2BAvatar%2B2.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28344720.post-5585463474150721273</id><published>2012-01-10T12:36:00.011-07:00</published><updated>2012-01-11T08:19:15.992-07:00</updated><title type='text'>Since when has consistency not been eventual?</title><content type='html'>Database isn't really my area.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;But you don't have to be a database expert to understand what those folks mean when they use the acronym &lt;a href="http://en.wikipedia.org/wiki/ACID"&gt;ACID&lt;/a&gt; (Reuter and Härder, 1983) that states for every database transaction:&lt;div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;A&lt;/b&gt;tomicity: either all or none of its changes are made;&lt;/div&gt;&lt;div&gt;&lt;b&gt;C&lt;/b&gt;onsistency: before and after, the database is in a consistent state;&lt;/div&gt;&lt;div&gt;&lt;b&gt;I&lt;/b&gt;solation: it either succeeds or fails regardless of concurrent transactions;&lt;/div&gt;&lt;div&gt;&lt;b&gt;D&lt;/b&gt;urability: once it succeeds, its changes are persistent.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;These requirements of database transactions are necessary to make sure, for example, that when you make a withdrawal from your bank account, the money you had yesterday is still there. Real-time guys like me get this because underneath the hood the database systems uses the same or similar synchronization primitives as those on which we depend on a daily basis to make sure planes keep flying and telephones keep ringing. For those readers not into this stuff, a lot of the synchronization mechanisms amount to a bank teller saying to the next guy in line "I'll be with you in a moment once I'm finished with this customer", except it has to be implemented all the way down to the lowest level of the hardware.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This was challenging enough when databases were hosted on single servers so large they frequently needed multiple processors to keep up with the workload. But when databases got so huge that they had to be distributed across multiple servers on a network, satisfying ACID suddenly got really hard. &lt;i&gt;Brewer's Theorem&lt;/i&gt; (Brewer, 2000) and its more narrowly but formally defined cousin the &lt;i&gt;&lt;a href="http://en.wikipedia.org/wiki/CAP_theorem"&gt;CAP Theorem&lt;/a&gt;&lt;/i&gt; (Gilbert and Lynch, 2002), states that a distributed system can deliver at most two of the following three qualities:&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;C&lt;/b&gt;onsistency: each server sees the same data at the same time;&lt;/div&gt;&lt;div&gt;&lt;b&gt;A&lt;/b&gt;vailability: each request gets a response, success or failure;&lt;/div&gt;&lt;div&gt;&lt;b&gt;P&lt;/b&gt;artition tolerance: the system continues to run even when the network fails.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The need for availability and partition tolerance is especially compelling given that the network is basically unreliable. In fact, this assumption is at the very core of the initial design of what today we think of as the Internet, which started life out as a network for military communication in the face of a nuclear war. Network traffic would be briefly interrupted as cities were vaporized by megaton Soviet warheads and packets were routed around the flaming craters. Armageddon turns out to have been a good model for other catastrophic failures too, like someone accidentally powering down an equipment rack or inadvertently cutting a fiber optic cable with a back hoe.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Designers of software for distributed systems have to take this basic assumption of unreliability into account. It is in fact the first of the eight &lt;a href="http://en.wikipedia.org/wiki/Fallacies_of_Distributed_Computing"&gt;&lt;i&gt;Fallacies of Distributed Computing&lt;/i&gt;&lt;/a&gt; (Deutsch 1994, Gosling 1997, et al.):&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;1. The network is reliable.&lt;/div&gt;&lt;div&gt;2. Latency is zero.&lt;/div&gt;&lt;div&gt;3. Bandwidth is infinite.&lt;/div&gt;&lt;div&gt;4. The network is secure.&lt;/div&gt;&lt;div&gt;5. Topology doesn't change.&lt;/div&gt;&lt;div&gt;6. There is one administrator.&lt;/div&gt;&lt;div&gt;7. Transport cost is zero.&lt;/div&gt;&lt;div&gt;8. The network is homogeneous.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;For e-commerce giants like &lt;a href="http://www.amazon.com/"&gt;Amazon.com&lt;/a&gt;, it became a lot more important to tolerate some inconsistency issues than it was to have a system that didn't respond when I hit the &lt;i&gt;Buy now with 1-Click&lt;/i&gt; button. (Which I do. All too often. 1-Click ordering is the bane of my credit card.) Sure, sometimes you can order something that is actually out of stock. Or order something twice. But those kinds of consistency errors are infrequent, and when they do occur, they can be detected and cleaned up after the fact. The same approach has been adopted by many cloud computing architectures for the same reason: it's the only way to build scalable systems, because scalability requires distribution.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Amazon.com coined their architectural willingness to incur some inconsistency as &lt;i&gt;&lt;a href="http://en.wikipedia.org/wiki/Eventual_consistency"&gt;eventual consistency&lt;/a&gt;&lt;/i&gt; (Vogels, 2008), but the database folks adopted as the alternative to ACID the punnish acronym &lt;a href="http://en.wikipedia.org/wiki/Eventual_consistency"&gt;BASE&lt;/a&gt; (Pritchett, 2008):&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;B&lt;/b&gt;asically: more or less&lt;/div&gt;&lt;div&gt;&lt;b&gt;A&lt;/b&gt;vailable: reliable&lt;/div&gt;&lt;div&gt;&lt;b&gt;S&lt;/b&gt;oft state: with some inconsistencies here and there&lt;/div&gt;&lt;div&gt;&lt;b&gt;E&lt;/b&gt;ventual consistency: that we'll fix later.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This approach allows, for example, Amazon.com to spread their &lt;a href="http://aws.amazon.com/"&gt;Amazon Web Services&lt;/a&gt; (AWS) infrastructure across thousands of individual servers in a network that is distributed internationally. I've &lt;a href="http://coverclock.blogspot.com/2011/12/eventual-consistency-and-hayloft.html"&gt;mentioned before&lt;/a&gt; that in testing &lt;a href="http://www.diag.com/navigation/downloads/Hayloft.html"&gt;Hayloft&lt;/a&gt;, my C++ interface to Amazon &lt;a href="http://aws.amazon.com/s3/"&gt;Simple Storage Service&lt;/a&gt; (S3), I not only could see the effects on my subsequent transactions of S3 updating its bicoastal server farm in the United States to take into account my prior transactions, but I could see the increase in latency of those updates on &lt;a href="http://en.wikipedia.org/wiki/Black_Friday_(shopping)"&gt;Black Friday&lt;/a&gt;, the day after Thanksgiving in the U.S., which is typically the biggest day of the year for retail commerce here, e- or otherwise.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So here's the thing. Eventual consistency is not a new idea. Probably not to the database community, but certainly not to the community of developers I hang out with who write software for both small embedded and gigantic distributed systems. (Those are the same people.) Or at least it shouldn't be. Let me give you an example.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The biggest distributed system I ever worked on was a Private Branch eXchange (PBX). This system had several distributed redundant servers controlling up to sixty-four cabinets of hardware. Each cabinet had as many as five racks. Each rack had as many as a dozen or so boards. The most complex of these boards (which I happened to have worked on) had three microprocessor chips, twenty-four individual digital signal processor (DSP) chips, and several big field programmable gate array (FPGA) chips. At least one of the microprocessor chips had dozens of concurrent software threads running at all times. The main controlling server, which these days probably has multiple cores, also had dozens, if not hundreds, of parallel threads. A single PBX could (and did) span national boundaries. And each PBX typically communicated with other PBXes, with the public telephone network, and with other equally distributed systems.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;All of this stuff routinely communicated via message passing, over a combination of backplane wiring, dedicated telecommunications circuits, and internet connections. Even the simplest board in this system had at least one chip on it capable of responding to a limited set of messages coming across the backplane. When you look at the big picture, that's a lot of processors all independently doing stuff, all at the same time.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So what the heck was all this stuff doing? For the most part, each element was doing what it was told to do, either by a message from the main controlling server, from another board in the system, or in the case of inter-PBX connections from another system entirely. But whatever it was doing, it took time to do it. A typical pattern was: take a message from the queue of incoming messages, inject the message into a state machine that determines what to do given the current circumstances, and execute the resulting action. Some of these actions might (and typically did) result in one or more messages being dispatched to other threads on the same board, or other boards in the same cabinet, or back to the controlling server, or even to a completely different PBX.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;Remember those fallacies of distributed computing? Not only is the network &lt;i&gt;not&lt;/i&gt; reliable, but latency is &lt;i&gt;not&lt;/i&gt; zero, and bandwidth is &lt;i&gt;not&lt;/i&gt; infinite. So it takes a while for those messages to arrive at their destinations. If they arrive at all. Only to be queued up at the receiving end, perhaps behind other messages. Maybe many other messages, all waiting for a thread to finish what it's currently doing and go back and receive them. Thanks to &lt;/span&gt;communications&lt;span class="Apple-style-span"&gt; latency, queueing latency, and processing latency, it might be seconds between the time a state machine makes a decision, a message is dispatched, that message is received, and acted upon.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If you could somehow take an instantaneous snapshot of the entire, gigantic system, what you would see is dozens, hundreds, thousands of processors, each acting on a message that doesn't describe the current state of things at all, but instead the state of things a while ago. How long a while? It's different for every system, every processor, every application, every workload, every instant from one to the next. It's not just eventually consistent. It's more or less &lt;i&gt;perpetually inconsistent&lt;/i&gt;. Why? Because it was the only way to build a scalable system.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Being slightly out of sync all the time can result in a kind of positive feedback loop, where two threads, each having a different idea of the current state of affairs, both of them possibly being wrong, keep telling one another to do the wrong thing. The good news is that if this isn't addressed, it frequently results in something fairly obvious, like a communications system serving thousands of people crashing. But it can also lead to much more subtle emergent behavior in which the system as a whole acts mysteriously non-deterministic.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Once you appreciate the magnitude of it, it's a little miracle anything works at all. I used the example of a PBX because that's the biggest distributed system I could think of that I've worked on. But a similar analysis applies to any large distributed architecture: Amazon Web Services, traffic light systems, air traffic control systems, automated stock exchanges, Strategic Air Command. All of these systems have always had their own mechanisms for dealing with their special brand of eventual consistency. Here's some mechanisms I've seen used.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Audits. &lt;/b&gt;An audit simply means fixing a consistency issue when you encounter it, either in real-time (what the distributed database people call &lt;i&gt;read repair&lt;/i&gt; and &lt;i&gt;write repair&lt;/i&gt;), or by having software specifically tasked to go and look for it (&lt;i&gt;asynchronous repair&lt;/i&gt;). More than once I've received email from Amazon.com telling me that something I ordered was actually out of stock, or asking me to verify that I meant to order two of an item. These are all the results of audits. Big distributed systems like PBXes routinely have dozens of audits running, all the time, just to apply corrective action to achieve eventual consistency.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Out of Band Messaging, Priority Messaging. &lt;/b&gt;Not all messages are created equal. Some messages get to take the equivalent of the passing lane and jump ahead of all the other queued messages. This is either done by using a different communications path or by jumping the message ahead of all the others in the queue. Once a thread receives such a message, it still has to decide what to do with each of the stale messages behind it: throw it away, reply to it with failure, or even reply with success under the assumption of what the sender doesn't know won't hurt it. Sometimes the result of such a high priority message is for the receiver to exit, reset, or reboot. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Hysteresis, Feedback. &lt;/b&gt;For a lot of real-time processes, it makes sense to take your time when you are changing something visible to others. When you receive a message telling you that you can increase your bandwidth, don't jack up your bandwidth all at once. Instead, turn that tap slowly, injecting some hysteresis or delay into the process. This gives everyone downstream more time to adjust to your changes, and to complain about it if it doesn't work for them. If you get active feedback, if for example you are monitoring real-time error rates or you start getting flow control messages from your downstream neighbors, you can stop turning the tap.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Traffic Shaping, Traffic Policing, Flow Control. &lt;/b&gt;All of these are mechanisms for controlling the rate at which a thread may send or receive messages. For a lot of applications, real-time data has an expiration date, and it is better to just throw it away than to process it late. If a thread is told that a message it is about to send will arrive with an unusual amount of delay (we might say that the message exceeds the &lt;i&gt;traffic contract&lt;/i&gt; between the sender and the receiver), the sender might choose to implement a different strategy or take corrective action.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;This article is in some ways my love letter to real-time systems. I have known the joy of analyzing a post mortem &lt;/span&gt;hemorrhage&lt;span class="Apple-style-span"&gt; of thousands of lines of log messages late at night so that I could tell a customer why their multi-million dollar system crashed. Of watching LEDs flash on a board from across a data center equipment room and suddenly wondering "WHAT THE F...!?!?!?!" Of staring at a diagnostic laptop as I watched a system servicing an entire building increment error counters towards MAXINT. When I first starting reading about eventual consistency I knew that it was something with which I was already familiar.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;Even though database isn't really my area.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28344720-5585463474150721273?l=coverclock.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://coverclock.blogspot.com/feeds/5585463474150721273/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28344720&amp;postID=5585463474150721273' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/5585463474150721273'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/5585463474150721273'/><link rel='alternate' type='text/html' href='http://coverclock.blogspot.com/2012/01/since-when-has-consistency-not-been.html' title='Since when has consistency not been eventual?'/><author><name>Chip Overclock</name><uri>http://www.blogger.com/profile/11195242013008369733</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-1xNiFqWVjh8/TWQ1ru5Z6KI/AAAAAAAAABw/kMJyhvluNMI/s220/Chip%2BOverclock%2BAvatar%2B2.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28344720.post-2345533196804733405</id><published>2012-01-09T12:19:00.018-07:00</published><updated>2012-01-10T11:22:00.696-07:00</updated><title type='text'>Managing Actions in Simple Storage Service with Hayloft</title><content type='html'>&lt;a href="http://www.diag.com/navigation/downloads/Hayloft.html"&gt;Hayloft&lt;/a&gt; provides a object oriented interface to the &lt;a href="http://aws.amazon.com/"&gt;Amazon Web Services&lt;/a&gt; (AWS) &lt;a href="http://aws.amazon.com/s3/"&gt;Simple Storage Service&lt;/a&gt; (S3) in C++. When I started working on Hayloft, I had several goals. I'm wanted to learn something about cloud computing in general because I believe that's the direction everything is going and as someone else once said, "Amazon.com is the Coke of cloud computing, and there is no Pepsi". I wanted to learn something about S3 in particular because I have a background in mass storage systems and S3 might be the biggest one in the world. I wanted to write some software because I'm one of those people who can only learn by doing. I wanted to write it in C++ because I wanted to be able to use that software in small embedded systems and honking big distributed systems (turns out the skill sets are the same) where I've spent most of my career as a developer.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I didn't want to just slam out some code to talk to S3. I was interested in learning how to manage the individual operations, or what Hayloft refers to as an &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Action&lt;/span&gt;, with S3 using some of the patterns I've exploited in the past in the kinds of systems I've made a good living developing. I will show you some real, running code right from the Hayloft tarball (specifically in &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;example.cpp&lt;/span&gt;) that will illustrate some of the different ways applications can use &lt;i&gt;buckets&lt;/i&gt; and &lt;i&gt;objects&lt;/i&gt; in S3 by integrating Hayloft. In S3 parlance, a bucket can be thought of as a web site with unique domain name, and an object is a flat file that a web browser can retrieve from that web site. Each of these examples will perform exactly the same sequence of S3 actions:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;create &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;BUCKET1&lt;/span&gt; and &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;BUCKET2&lt;/span&gt; in S3;&lt;/li&gt;&lt;li&gt;put a local file &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;unittest.txt&lt;/span&gt; into &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;BUCKET1/OBJECT1&lt;/span&gt; in S3;&lt;/li&gt;&lt;li&gt;copy &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;BUCKET1/OBJECT1&lt;/span&gt; to &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;BUCKET2/OBJECT2&lt;/span&gt; in S3;&lt;/li&gt;&lt;li&gt;get &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;BUCKET2/OBJECT2&lt;/span&gt; from S3 into a second temporary local file;&lt;/li&gt;&lt;li&gt;delete &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;BUCKET1/OBJECT1&lt;/span&gt; and &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;BUCKET2/OBJECT2&lt;/span&gt; in S3;&lt;/li&gt;&lt;li&gt;delete &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;BUCKET1&lt;/span&gt; and &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;BUCKET2&lt;/span&gt; in S3;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;diff&lt;/span&gt; the first and second local files to verify they are the same.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;Other than some surround to include some header files and set the some environmental variables so that Hayloft knows parameters like my &lt;i&gt;access key ID&lt;/i&gt; and &lt;i&gt;secret access key&lt;/i&gt; that Hayloft uses to authenticate my application to AWS, in the examples below I'm showing you all the running code that is in &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;example.cpp&lt;/span&gt;.&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The first example executes all actions &lt;i&gt;synchronously&lt;/i&gt;. There is no need to start actions or wait for actions to complete. Each action is started in its C++ constructor, and the constructor blocks until that action completes. All processing is done in the calling thread.&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;span&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;const char * PATH = "unittest.txt";&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Bucket BUCKET1("Synchronicity1");&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Bucket BUCKET2("Synchronicity2");&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Object OBJECT1("Synchronicity1.txt", BUCKET1);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Object OBJECT2("Synchronicity2.txt", BUCKET2);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;PathInput input(PATH);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Octets length = size(PATH);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;PathOutput output(OBJECT2.getKey());&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;BucketCreate bucketcreate1(BUCKET1);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;BucketCreate bucketcreate2(BUCKET2);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (!bucketcreate1.isSuccessful()) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (!bucketcreate2.isSuccessful()) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ObjectPut objectput1(OBJECT1, input, length);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (!objectput1.isSuccessful()) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ObjectCopy objectcopy(OBJECT1, OBJECT2);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (!objectcopy.isSuccessful()) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ObjectGet objectget2(OBJECT2, output);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (!objectget2.isSuccessful()) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ObjectDelete objectdelete1(OBJECT1);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ObjectDelete objectdelete2(OBJECT2);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (!objectdelete1.isSuccessful()) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (!objectdelete2.isSuccessful()) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;BucketDelete bucketdelete1(BUCKET1);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;BucketDelete bucketdelete2(BUCKET2);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (!bucketdelete1.isSuccessful()) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (!bucketdelete2.isSuccessful()) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;std::string command = "diff ";&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;command += PATH;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;command += " ";&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;command += OBJECT2.getKey();&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (std::system(command.c_str()) &amp;lt; 0) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (::unlink(OBJECT2.getKey()) &amp;lt; 0) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/span&gt;&lt;/span&gt;&lt;div&gt;&lt;div&gt;There is no code here to recover from errors, although the extensive unit test suite for Hayloft, based on &lt;a href="http://code.google.com/p/googletest/"&gt;Google Test&lt;/a&gt;, includes examples of doing that using this paradigm. If you want to get started playing with S3 in C++ using Hayloft, this is the absolutely simplest way to do so. As with all the examples, local files are handled using &lt;a href="http://www.diag.com/navigation/downloads/Desperado.html"&gt;Desperado&lt;/a&gt; &lt;a href="http://coverclock.blogspot.com/2011/11/abstraction-in-c-using-io-functors.html"&gt;input and output functors&lt;/a&gt;. The &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;PathInput &lt;/span&gt;and &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;PathOutput&lt;/span&gt; functors provide an abstract mechanism to read and write data from the local file system.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;S3 actions can be managed by using a different C++ constructor that specifies a &lt;i&gt;manager&lt;/i&gt; or what Hayloft generically refers to as a &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Plex&lt;/span&gt;. The simplest manager is &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Simplex&lt;/span&gt;, which is a bit of a cheat: it still uses the synchronous interface, but actions are not automatically started in the constructor. You must &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;start&lt;/span&gt; each action explicitly, but when the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;start&lt;/span&gt; method returns, the action has completed. All actions are executed in the calling thread. I'll embolden the important differences between this and the prior example.&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;const char * PATH = "unittest.txt";&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Bucket BUCKET1("Simplexity1");&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Bucket BUCKET2("Simplexity2");&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Object OBJECT1("Simplexity1.txt", BUCKET1);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Object OBJECT2("Simplexity2.txt", BUCKET2);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;PathInput input(PATH);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Octets length = size(PATH);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;PathOutput output(OBJECT2.getKey());&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;b&gt;Simplex simplex;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;BucketCreate bucketcreate1(BUCKET1, &lt;b&gt;simplex&lt;/b&gt;);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;BucketCreate bucketcreate2(BUCKET2, &lt;b&gt;simplex&lt;/b&gt;);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;b&gt;bucketcreate1.start();&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;b&gt;bucketcreate2.start();&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (!bucketcreate1.isSuccessful()) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (!bucketcreate2.isSuccessful()) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ObjectPut objectput1(OBJECT1, &lt;b&gt;simplex&lt;/b&gt;, input, length);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;b&gt;objectput1.start();&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (!objectput1.isSuccessful()) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ObjectCopy objectcopy(OBJECT1, OBJECT2, &lt;b&gt;simplex&lt;/b&gt;);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;b&gt;objectcopy.start();&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (!objectcopy.isSuccessful()) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ObjectGet objectget2(OBJECT2, &lt;b&gt;simplex&lt;/b&gt;, output);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;b&gt;objectget2.start();&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (!objectget2.isSuccessful()) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ObjectDelete objectdelete1(OBJECT1, &lt;b&gt;simplex&lt;/b&gt;);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ObjectDelete objectdelete2(OBJECT2, &lt;b&gt;simplex&lt;/b&gt;);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;b&gt;objectdelete1.start();&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;b&gt;objectdelete2.start();&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (!objectdelete1.isSuccessful()) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (!objectdelete2.isSuccessful()) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;BucketDelete bucketdelete1(BUCKET1, &lt;b&gt;simplex&lt;/b&gt;);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;b&gt;bucketdelete1.start();&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;BucketDelete bucketdelete2(BUCKET2, &lt;b&gt;simplex&lt;/b&gt;);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;b&gt;bucketdelete2.start();&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (!bucketdelete1.isSuccessful()) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (!bucketdelete2.isSuccessful()) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;std::string command = "diff ";&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;command += PATH;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;command += " ";&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;command += OBJECT2.getKey();&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (std::system(command.c_str()) &amp;lt; 0) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (::unlink(OBJECT2.getKey()) &amp;lt; 0) { break; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;As before, there is no error recovery, although such recovery is important when using S3 or any other web or even internet based service. The most common errors will be failure to connect to the service. This can be due to connectivity problems at either end of the internet connection or indeed anywhere in between.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This next example uses a &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Multiplex&lt;/span&gt; to manage the actions. This will be the first example that uses the &lt;i&gt;asynchronous&lt;/i&gt; interface. Because actions are executed asynchronously, multiple actions can use the same &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Multiplex&lt;/span&gt; and will be executed in parallel. Each action must be started, and the processing of each action must be explicitly driven. In this example, I'll use the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Multiplex&lt;/span&gt; &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;complete&lt;/span&gt; method that automatically drives any pending actions to completion. I'll show other approaches in subsequent examples.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;const char * PATH = "unittest.txt";&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Bucket BUCKET1("MultiplexityComplete1");&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Bucket BUCKET2("MultiplexityComplete2");&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Object OBJECT1("MultiplexityComplete1.txt", BUCKET1);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Object OBJECT2("MultiplexityComplete2.txt", BUCKET2);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;PathInput input(PATH);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Octets length = size(PATH);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;PathOutput output(OBJECT2.getKey());&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;b&gt;Multiplex multiplex;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;BucketCreate bucketcreate1(BUCKET1, &lt;b&gt;multiplex&lt;/b&gt;);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;BucketCreate bucketcreate2(BUCKET2, &lt;b&gt;multiplex&lt;/b&gt;);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;bucketcreate1.start();&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;bucketcreate2.start();&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;b&gt;multiplex.complete();&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (!bucketcreate1.isSuccessful()) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (!bucketcreate2.isSuccessful()) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ObjectPut objectput1(OBJECT1, &lt;b&gt;multiplex&lt;/b&gt;, input, length);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;objectput1.start();&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;b&gt;multiplex.complete();&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (!objectput1.isSuccessful()) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ObjectCopy objectcopy(OBJECT1, OBJECT2, &lt;b&gt;multiplex&lt;/b&gt;);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;objectcopy.start();&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;multiplex.complete();&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (!objectcopy.isSuccessful()) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ObjectGet objectget2(OBJECT2, &lt;b&gt;multiplex&lt;/b&gt;, output);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;objectget2.start();&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;b&gt;multiplex.complete();&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (!objectget2.isSuccessful()) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ObjectDelete objectdelete1(OBJECT1, &lt;b&gt;multiplex&lt;/b&gt;);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ObjectDelete objectdelete2(OBJECT2, &lt;b&gt;multiplex&lt;/b&gt;);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;objectdelete1.start();&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;objectdelete2.start();&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;b&gt;multiplex.complete();&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (!objectdelete1.isSuccessful()) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (!objectdelete2.isSuccessful()) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;BucketDelete bucketdelete1(BUCKET1, &lt;b&gt;multiplex&lt;/b&gt;);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;bucketdelete1.start();&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;BucketDelete bucketdelete2(BUCKET2, &lt;b&gt;multiplex&lt;/b&gt;);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;bucketdelete2.start();&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;b&gt;multiplex.complete();&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (!bucketdelete1.isSuccessful()) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (!bucketdelete2.isSuccessful()) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;std::string command = "diff ";&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;command += PATH;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;command += " ";&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;command += OBJECT2.getKey();&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (std::system(command.c_str()) &amp;lt; 0) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (::unlink(OBJECT2.getKey()) &amp;lt; 0) { break; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This approach is useful for testing, but in practice there isn't a huge advantage between it and the prior example other than the ability to run some actions in parallel, which this example does.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This next example uses &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Multiplex&lt;/span&gt;, but uses its &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;service&lt;/span&gt; method to incrementally drive the underlying state machines to completion. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;const char * PATH = "unittest.txt";&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Bucket BUCKET1("MultiplexityService1");&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Bucket BUCKET2("MultiplexityService2");&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Object OBJECT1("MultiplexityService1.txt", BUCKET1);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Object OBJECT2("MultiplexityService2.txt", BUCKET2);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;PathInput input(PATH);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Octets length = size(PATH);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;PathOutput output(OBJECT2.getKey());&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Multiplex multiplex;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;BucketCreate bucketcreate1(BUCKET1, multiplex);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;BucketCreate bucketcreate2(BUCKET2, multiplex);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;bucketcreate1.start();&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;bucketcreate2.start();&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;b&gt;while (multiplex.service() &amp;gt; 0) { }&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (!bucketcreate1.isSuccessful()) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (!bucketcreate2.isSuccessful()) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ObjectPut objectput1(OBJECT1, multiplex, input, length);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;objectput1.start();&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;b&gt;while (multiplex.service() &amp;gt; 0) { }&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (!objectput1.isSuccessful()) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ObjectCopy objectcopy(OBJECT1, OBJECT2, multiplex);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;objectcopy.start();&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;b&gt;while (multiplex.service() &amp;gt; 0) { }&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (!objectcopy.isSuccessful()) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ObjectGet objectget2(OBJECT2, multiplex, output);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;objectget2.start();&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;b&gt;while (multiplex.service() &amp;gt; 0) { }&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (!objectget2.isSuccessful()) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ObjectDelete objectdelete1(OBJECT1, multiplex);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ObjectDelete objectdelete2(OBJECT2, multiplex);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;objectdelete1.start();&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;objectdelete2.start();&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;b&gt;while (multiplex.service() &amp;gt; 0) { }&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (!objectdelete1.isSuccessful()) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (!objectdelete2.isSuccessful()) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;BucketDelete bucketdelete1(BUCKET1, multiplex);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;bucketdelete1.start();&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;BucketDelete bucketdelete2(BUCKET2, multiplex);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;bucketdelete2.start();&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;b&gt;while (multiplex.service() &amp;gt; 0) { }&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (!bucketdelete1.isSuccessful()) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (!bucketdelete2.isSuccessful()) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;std::string command = "diff ";&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;command += PATH;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;command += " ";&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;command += OBJECT2.getKey();&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (std::system(command.c_str()) &amp;lt; 0) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (::unlink(OBJECT2.getKey()) &amp;lt; 0) { break; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I've just basically implemented the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;complete&lt;/span&gt; method by calling the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;service&lt;/span&gt; method iteratively until it reports that there is no more work to be done. But an application could instead time slice the calling of the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;service&lt;/span&gt; method with other work. The &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;service&lt;/span&gt; method has embedded in it a timed &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;select&lt;/span&gt; system call so that it relinquishes the processor while waiting for the sockets to S3 to become ready.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The next example is the first one in which you'll see &lt;i&gt;multi-threading&lt;/i&gt;. The &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Complex&lt;/span&gt; manager has a service thread that runs in the background and executes all pending actions. Instead of starting actions itself, the application instead submits each action to &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Complex&lt;/span&gt; and then waits on a POSIX thread &lt;i&gt;condition variable&lt;/i&gt; specific to that action. All action processing is done in the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Complex&lt;/span&gt; thread. No matter how many &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Complex&lt;/span&gt; objects you create, there is just one &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Complex&lt;/span&gt; thread doing all the work, and many actions may be executed in parallel in the background by that one thread.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;div&gt;const char * PATH = "unittest.txt";&lt;/div&gt;&lt;div&gt;Bucket BUCKET1("ComplexityWait1");&lt;/div&gt;&lt;div&gt;Bucket BUCKET2("ComplexityWait2");&lt;/div&gt;&lt;div&gt;Object OBJECT1("ComplexityWait1.txt", BUCKET1);&lt;/div&gt;&lt;div&gt;Object OBJECT2("ComplexityWait2.txt", BUCKET2);&lt;/div&gt;&lt;div&gt;PathInput input(PATH);&lt;/div&gt;&lt;div&gt;Octets length = size(PATH);&lt;/div&gt;&lt;div&gt;PathOutput output(OBJECT2.getKey());&lt;/div&gt;&lt;div&gt;&lt;b&gt;Complex complex;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;BucketCreate bucketcreate1(BUCKET1, &lt;b&gt;complex&lt;/b&gt;);&lt;/div&gt;&lt;div&gt;&lt;b&gt;complex.start(bucketcreate1);&lt;/b&gt;&lt;/div&gt;&lt;div&gt;BucketCreate bucketcreate2(BUCKET2, &lt;b&gt;complex&lt;/b&gt;);&lt;/div&gt;&lt;div&gt;&lt;b&gt;complex.start(bucketcreate2);&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;complex.wait(bucketcreate1);&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;complex.wait(bucketcreate2);&lt;/b&gt;&lt;/div&gt;&lt;div&gt;if (!bucketcreate1.isSuccessful()) { break; }&lt;/div&gt;&lt;div&gt;if (!bucketcreate2.isSuccessful()) { break; }&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;ObjectPut objectput1(OBJECT1, &lt;b&gt;complex&lt;/b&gt;, input, length);&lt;/div&gt;&lt;div&gt;&lt;b&gt;complex.start(objectput1);&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;complex.wait(objectput1);&lt;/b&gt;&lt;/div&gt;&lt;div&gt;if (!objectput1.isSuccessful()) { break; }&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;ObjectCopy objectcopy(OBJECT1, OBJECT2, &lt;b&gt;complex&lt;/b&gt;);&lt;/div&gt;&lt;div&gt;&lt;b&gt;complex.start(objectcopy);&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;complex.wait(objectcopy);&lt;/b&gt;&lt;/div&gt;&lt;div&gt;if (!objectcopy.isSuccessful()) { break; }&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;ObjectGet objectget2(OBJECT2, &lt;b&gt;complex&lt;/b&gt;, output);&lt;/div&gt;&lt;div&gt;&lt;b&gt;complex.start(objectget2);&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;complex.wait(objectget2);&lt;/b&gt;&lt;/div&gt;&lt;div&gt;if (!objectget2.isSuccessful()) { break; }&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;ObjectDelete objectdelete1(OBJECT1, &lt;b&gt;complex&lt;/b&gt;);&lt;/div&gt;&lt;div&gt;&lt;b&gt;complex.start(objectdelete1);&lt;/b&gt;&lt;/div&gt;&lt;div&gt;ObjectDelete objectdelete2(OBJECT2, &lt;b&gt;complex&lt;/b&gt;);&lt;/div&gt;&lt;div&gt;&lt;b&gt;complex.start(objectdelete2);&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;complex.wait(objectdelete1);&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;complex.wait(objectdelete2);&lt;/b&gt;&lt;/div&gt;&lt;div&gt;if (!objectdelete1.isSuccessful()) { break; }&lt;/div&gt;&lt;div&gt;if (!objectdelete2.isSuccessful()) { break; }&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;BucketDelete bucketdelete1(BUCKET1, &lt;b&gt;complex&lt;/b&gt;);&lt;/div&gt;&lt;div&gt;&lt;b&gt;complex.start(bucketdelete1);&lt;/b&gt;&lt;/div&gt;&lt;div&gt;BucketDelete bucketdelete2(BUCKET2, &lt;b&gt;complex&lt;/b&gt;);&lt;/div&gt;&lt;div&gt;&lt;b&gt;complex.start(bucketdelete2);&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;complex.wait(bucketdelete1);&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;complex.wait(bucketdelete2);&lt;/b&gt;&lt;/div&gt;&lt;div&gt;if (!bucketdelete1.isSuccessful()) { break; }&lt;/div&gt;&lt;div&gt;if (!bucketdelete2.isSuccessful()) { break; }&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;std::string command = "diff ";&lt;/div&gt;&lt;div&gt;command += PATH;&lt;/div&gt;&lt;div&gt;command += " ";&lt;/div&gt;&lt;div&gt;command += OBJECT2.getKey();&lt;/div&gt;&lt;div&gt;if (std::system(command.c_str()) &amp;lt; 0) { break; }&lt;/div&gt;&lt;div&gt;if (::unlink(OBJECT2.getKey()) &amp;lt; 0) { break; }&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;Unless you have some strenuous objection to multi-threading, this is the approach you should use in a real application. The background service thread does a lot more than just execute the actions. If the actions fail for any reason deemed to be recoverable, like a network connection failure, the background service thread attempts to automatically retry the action. It does so after an appropriate &lt;a href="http://coverclock.blogspot.com/2011/12/fibonacci-scaling_09.html"&gt;back off interval&lt;/a&gt; to prevent the application from overloading the network, S3, or the local processor. The number of retries for any one action is limited so that execution of each action is guaranteed to eventually terminate. Once the application thread wakes up from its &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;wait&lt;/span&gt;, the action will have either completed (either successfully or because of an unrecoverable error) or exceeded its retry limit.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;One thing the background service thread cannot do by itself is know how to &lt;i&gt;rewind&lt;/i&gt; the input or output functors if, for example, the network connection fails in the middle of the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ObjectPut&lt;/span&gt; or &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ObjectGet&lt;/span&gt;. Hayloft has a way around that that involves overriding the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;reset&lt;/span&gt; method in &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ObjectPut&lt;/span&gt; or &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ObjectGet&lt;/span&gt; to handle the rewinding of the underlying data source or sink. In the case of &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;PathInput&lt;/span&gt; and &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;PathOutput&lt;/span&gt;, this just means closing and reopening the underlying local file. Although I don't show this example here, you can find it in &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;example.cpp&lt;/span&gt;. It's trivial to implement in an application.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Hayloft currently doesn't offer a &lt;i&gt;timed&lt;/i&gt; &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;wait&lt;/span&gt;. I just haven't convinced myself it's either necessary or a good idea. But you can poll actions to see if the background service thread has completed them. In fact, if you don't mind burning a lot of processor cycles, you can dispense with the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;wait&lt;/span&gt; on the condition variable completely and just poll the actions until they complete.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;const char * PATH = "unittest.txt";&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Bucket BUCKET1("ComplexityPoll1");&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Bucket BUCKET2("ComplexityPoll2");&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Object OBJECT1("ComplexityPoll1.txt", BUCKET1);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Object OBJECT2("ComplexityPoll2.txt", BUCKET2);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;PathInput input(PATH);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Octets length = size(PATH);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;PathOutput output(OBJECT2.getKey());&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Complex complex;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;BucketCreate bucketcreate1(BUCKET1, complex);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;complex.start(bucketcreate1);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;BucketCreate bucketcreate2(BUCKET2, complex);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;complex.start(bucketcreate2);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;b&gt;while (bucketcreate1 != true) { Thread::yield(); }&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;b&gt;while (bucketcreate2 != true) { Thread::yield(); }&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (!bucketcreate1.isSuccessful()) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (!bucketcreate2.isSuccessful()) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ObjectPut objectput1(OBJECT1, complex, input, length);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;complex.start(objectput1);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;b&gt;while (objectput1 != true) { Thread::yield(); }&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (!objectput1.isSuccessful()) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ObjectCopy objectcopy(OBJECT1, OBJECT2, complex);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;complex.start(objectcopy);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;b&gt;while (objectcopy != true) { Thread::yield(); }&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (!objectcopy.isSuccessful()) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ObjectGet objectget2(OBJECT2, complex, output);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;complex.start(objectget2);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;b&gt;while (objectget2 != true) { Thread::yield(); }&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (!objectget2.isSuccessful()) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ObjectDelete objectdelete1(OBJECT1, complex);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;complex.start(objectdelete1);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ObjectDelete objectdelete2(OBJECT2, complex);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;complex.start(objectdelete2);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;b&gt;while (objectdelete1 != true) { Thread::yield(); }&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;b&gt;while (objectdelete2 != true) { Thread::yield(); }&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (!objectdelete1.isSuccessful()) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (!objectdelete2.isSuccessful()) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;BucketDelete bucketdelete1(BUCKET1, complex);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;complex.start(bucketdelete1);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;BucketDelete bucketdelete2(BUCKET2, complex);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;complex.start(bucketdelete2);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;b&gt;while (bucketdelete1 != true) { Thread::yield(); }&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;b&gt;while (bucketdelete2 != true) { Thread::yield(); }&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (!bucketdelete1.isSuccessful()) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (!bucketdelete2.isSuccessful()) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;std::string command = "diff ";&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;command += PATH;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;command += " ";&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;command += OBJECT2.getKey();&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (std::system(command.c_str()) &amp;lt; 0) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if (::unlink(OBJECT2.getKey()) &amp;lt; 0) { break; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;The polling queries a state variable inside every action that is protected by a mutex and is accessed using an overloaded C++ boolean cast operator.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It took me the better part of two solid months to slam out the code for Hayloft, including its extensive unit test suite. But once I did, writing these examples and getting them all running took just a morning, with occasional breaks to check out the latest LOLcats.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Even if you don't want to use Hayloft, or C++, there are many other libraries around for using S3 in other languages, or indeed for using other cloud-based services. I believe information technology is rapidly evolving into a model in which mobile wireless devices and their applications (driven by consumer-side economies of scale) act as front ends to very large distributed cloud based services (driven by information technology-side economies of scale). If you have a background in developing for embedded or distributed systems, I suspect that you are going to find your skills map well to those required for this kind of work.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28344720-2345533196804733405?l=coverclock.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://coverclock.blogspot.com/feeds/2345533196804733405/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28344720&amp;postID=2345533196804733405' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/2345533196804733405'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/2345533196804733405'/><link rel='alternate' type='text/html' href='http://coverclock.blogspot.com/2012/01/managing-actions-in-simple-storage.html' title='Managing Actions in Simple Storage Service with Hayloft'/><author><name>Chip Overclock</name><uri>http://www.blogger.com/profile/11195242013008369733</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-1xNiFqWVjh8/TWQ1ru5Z6KI/AAAAAAAAABw/kMJyhvluNMI/s220/Chip%2BOverclock%2BAvatar%2B2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28344720.post-6366582049685774924</id><published>2012-01-06T15:40:00.006-07:00</published><updated>2012-01-06T16:05:06.867-07:00</updated><title type='text'>Barnes &amp; Noble Probably Stocks The Innovator's Dilemma</title><content type='html'>&lt;span&gt;&lt;span&gt;&lt;a href="http://money.cnn.com/2012/01/05/technology/barnes_noble_nook/?source=cnn_bin"&gt;CNN reports that Barnes &amp;amp; Noble is considering spinning off its Nook business.&lt;/a&gt; I was thinking about this very thing just the other day as I was totally loving the Kindle Touch that CyberSanta brought me for Christmas. (Mrs. Overclock got one too.)&lt;/span&gt;&lt;/span&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;br /&gt;Amazon.com has this profitable business that they can use to subsidize their Kindle research, development, and manufacturing. There has been speculation by those who have reverse engineered the Kindle that they may lose money on each device, depending on what kinds of discounts they have managed to negotiate with their suppliers and contract manufacturers. But unlike, say, Apple, which is a hardware company, and Microsoft, which is a software company, Amazon.com is a retail and e-commerce company evolving into a media production and distribution company. They can, and probably do, price the Kindle below their cost to manufacture but make it up in selling media for it. It's the whole printer versus ink and toner cartridges strategy. Or for that matter, razor versus razor blades, which has been around for decades.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;B&amp;amp;N has no growing business with which to subsidize the Nook. In fact, it's the other way around: if they make money on the Nook, it may end up subsidizing the shrinking book store business. That makes it hard for them to make the Nook with the kind of tight (or even negative) margins that Amazon.com makes the Kindle. The only way they can compete with the Kindle is to spin-off the Nook into a separate business so it can't be used to subsidize the other side of the house. There, the Nook, and e-book distribution, can continue to be profitable, while the traditional brick-and-morter business evaporates.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;I very much admire the design of the Kindle Touch. It cleverly leverages the use model of how people read books: they stare at a single page for seconds or minutes at a time. The electronic ink display of the Kindle is persistent - it only consumes power when changes are being made. The Kindle software can take advantage of all the power-saving modes in modern microprocessors intended for hand-held appliances like mobile phones and turn virtually everything on the device off, except for some hardware and software dealing with the touch sensor portion of the screen. Then it spins everything up, updates the display, and quiesces again. The monochrome display is slow to update, making it unsuitable for moving pictures, but it's perfect for books. Most of the time the device is being used no wireless network access is necessary. No wonder a single charge lasts for so long.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;The design of these devices, and the evolution of their business models, is pretty darn interesting to a product developer like me who has made a good living doing development on embedded systems.&lt;/span&gt;&lt;/span&gt;&lt;div&gt;&lt;span class="Apple-style-span"   style="color: rgb(51, 51, 51);   line-height: 22px; font-family:Georgia, Times, 'Liberation Serif', serif;font-size:15px;"&gt; &lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28344720-6366582049685774924?l=coverclock.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://coverclock.blogspot.com/feeds/6366582049685774924/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28344720&amp;postID=6366582049685774924' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/6366582049685774924'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/6366582049685774924'/><link rel='alternate' type='text/html' href='http://coverclock.blogspot.com/2012/01/barnes-noble-probably-stocks-innovators.html' title='Barnes &amp; Noble Probably Stocks The Innovator&apos;s Dilemma'/><author><name>Chip Overclock</name><uri>http://www.blogger.com/profile/11195242013008369733</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-1xNiFqWVjh8/TWQ1ru5Z6KI/AAAAAAAAABw/kMJyhvluNMI/s220/Chip%2BOverclock%2BAvatar%2B2.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28344720.post-6947195704274306393</id><published>2011-12-16T14:46:00.006-07:00</published><updated>2011-12-19T08:01:31.354-07:00</updated><title type='text'>The Cost of Experimenting with the Cloud</title><content type='html'>So after two months of my part-time experimentation with the &lt;a href="http://aws.amazon.com/s3/"&gt;Simple Storage Service&lt;/a&gt; (S3) from &lt;a href="http://aws.amazon.com/"&gt;Amazon Web Services&lt;/a&gt; (AWS) using &lt;a href="http://www.diag.com/navigation/downloads/Hayloft.html"&gt;Hayloft&lt;/a&gt;, my company finally got charged for its usage. &lt;i&gt;Three cents&lt;/i&gt;. It will be interesting to see if it actually shows up on my company credit card bill, or if Amazon.com defers it until the amount gets a little larger.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It's going to take a while. Typically I run the automated test suite many times a day, and each execution issues dozens of transactions to S3, but each transaction involves a tiny amount of data. Still, considering all I've learned while working on this project, this is a bargain.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;Update 2011-12-18&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I just counted: 198 individual S3 operations in the Hayloft test suite as of today, each one involving at least one request and response with S3.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28344720-6947195704274306393?l=coverclock.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://coverclock.blogspot.com/feeds/6947195704274306393/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28344720&amp;postID=6947195704274306393' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/6947195704274306393'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/6947195704274306393'/><link rel='alternate' type='text/html' href='http://coverclock.blogspot.com/2011/12/cost-of-experimenting-with-cloud.html' title='The Cost of Experimenting with the Cloud'/><author><name>Chip Overclock</name><uri>http://www.blogger.com/profile/11195242013008369733</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-1xNiFqWVjh8/TWQ1ru5Z6KI/AAAAAAAAABw/kMJyhvluNMI/s220/Chip%2BOverclock%2BAvatar%2B2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28344720.post-4988372412397716067</id><published>2011-12-09T09:21:00.007-07:00</published><updated>2011-12-09T13:38:58.816-07:00</updated><title type='text'>Fibonacci Scaling</title><content type='html'>Circa 1996 I found myself in an ideal situation: spending long hours working on a very technically challenging project with a multi-disciplinary bunch of engineers who were all smarter than I was. Good times.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;During that project one of my esteemed colleagues, John Meiners, needed a way to scale up the bandwidth on communications channels allocated in real-time on an as-needed basis. We were using Asynchronous Transfer Mode (ATM), a technology in which endpoints have to negotiate with the network for the amount of bandwidth they needed. Asking for more bandwidth than we needed meant more cost for our customers. Asking for less meant data loss. Tearing down an existing channel to allocate a bigger one would be viewed as a catastrophic failure. Due to the hard real-time nature of the application, doing everything via best effort was not even on the table.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So we started small, then as load increased we allocated additional channels. But some back of the envelope calculations suggested that if we chose a fixed bandwidth increment, things could get out of hand quickly with the number of channels we had to manage. We needed to start small, but allocate larger channels as the need arose. What algorithm should we use?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;John looked at various exponential algorithms, like doubling the bandwidth request of each subsequent channel. But that got really big (and hence really expensive) really quickly, and the scaling didn't match our expected use cases. What he finally settled on was &lt;i&gt;&lt;a href="http://en.wikipedia.org/wiki/Fibonacci_number"&gt;Fibonacci numbers&lt;/a&gt;&lt;/i&gt;:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;F&lt;sub&gt;n&lt;/sub&gt; = F&lt;sub&gt;n-1&lt;/sub&gt; + F&lt;sub&gt;n-2&lt;/sub&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;where&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;F&lt;sub&gt;0&lt;/sub&gt; = 0&lt;/div&gt;&lt;div&gt;F&lt;sub&gt;1&lt;/sub&gt; = 1&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Starting with F&lt;sub&gt;1&lt;/sub&gt; just as Fibonacci himself did in 1202 (since using zero as a bandwidth multiplier doesn't make much sense) produces a sequence that looks like this:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;1, 1, 2, 3, 5, 8, 13, 21, 34, 55, ...&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This turned out to be pretty much ideal. It starts small and conservative, expands but not too quickly, and is trivially computed since you just have to keep track of the last two numbers in the sequence and merely do an addition.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Fibonacci numbers have been around a long time. Although Leonardo of Pisa (a.k.a. Fibonacci) gets the credit, the sequence was written down earlier by Indian mathematicians. It occurs frequently in nature, most noticeably in spirals such as those found in pine cones and shells. John's idea seems pretty innovative in 1996, but lots of high-technology applications of the Fibonacci sequence exist today, including network back off algorithms, lossy data compression, pseudo-random number generators, and tree and heap data structures. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I'm thinking about this because I am once again using this sequence as a way to scale up back off time delays when recovering from network errors in &lt;a href="http://www.diag.com/navigation/downloads/Hayloft.html"&gt;Hayloft&lt;/a&gt;, my little C++ research project using &lt;a href="http://aws.amazon.com/"&gt;Amazon Web Services&lt;/a&gt; &lt;a href="http://aws.amazon.com/s3/"&gt;Simple Storage Service&lt;/a&gt; (S3). I have no doubt that Fibonacci's simple little recursive algorithm will continue to serve me well.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28344720-4988372412397716067?l=coverclock.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://coverclock.blogspot.com/feeds/4988372412397716067/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28344720&amp;postID=4988372412397716067' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/4988372412397716067'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/4988372412397716067'/><link rel='alternate' type='text/html' href='http://coverclock.blogspot.com/2011/12/fibonacci-scaling_09.html' title='Fibonacci Scaling'/><author><name>Chip Overclock</name><uri>http://www.blogger.com/profile/11195242013008369733</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-1xNiFqWVjh8/TWQ1ru5Z6KI/AAAAAAAAABw/kMJyhvluNMI/s220/Chip%2BOverclock%2BAvatar%2B2.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28344720.post-2591421315744981778</id><published>2011-12-08T12:36:00.005-07:00</published><updated>2011-12-08T15:37:50.411-07:00</updated><title type='text'>Venkatesh Rao on Developernomics</title><content type='html'>&lt;div&gt;Venkatesh Rao had an article on the &lt;i&gt;&lt;a href="http://www.forbes.com/"&gt;Forbes&lt;/a&gt;&lt;/i&gt; web site on the valuation of software developers: "&lt;a href="http://www.forbes.com/sites/venkateshrao/2011/12/05/the-rise-of-developeronomics/"&gt;The Rise of Developeronomics&lt;/a&gt;". He comes closer than anyone else so far (including me) to describing how I see things going career wise for software developers, although it's written from the perspective of someone desperately trying to hire competent developers to compete in a world in which &lt;a href="http://www.forbes.com/sites/techonomy/2011/11/30/now-every-company-is-a-software-company/"&gt;every company has to become a software company&lt;/a&gt;, explicitly or implicitly. It's worth a read.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;[I]f you don’t have a skill, like baking, which the developer-centric economy can actually use, you are in deep trouble. One reason the Occupy Wall Street movement is not having the impact it seems like it should, based on sheer numbers of people involved, is that many participants simply have no cards left to play in this national game of economic poker.&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;blockquote&gt;Investing in good developers is such a good bet at the moment, that if you have money and you happen to find a talented developer who seems to like you and wants to work with you, you should give him/her your money to build something, anything, even if you have no really good product ideas (those are cheap; I’ll sell you a dozen for a dollar). If you don’t have money, you should offer up whatever other kind of surplus you do have. The NPV on a strong and positive relationship with a talented developer today is ridiculously high. If you gain the trust of a talented developer to the point that they are likely to drop any active gig in the future in favor of joining one of your projects, the value is through the roof. The world is your oyster, which you with your developer will open.&lt;/blockquote&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The idea of using &lt;a href="http://coverclock.blogspot.com/2007/01/lies-damn-lies-and-net-present-value.html"&gt;Net Present Value&lt;/a&gt; (NPV) to compare the value of a software developer with alternative investments is one of those things that for me is initially surprising yet obvious in hindsight. In today's economy, where instead of owning a factory and a warehouse of parts all of a company's worth is in intellectual capital (which really means, in the brains of its employees), it makes sense.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Rao writes the &lt;a href="http://www.ribbonfarm.com/"&gt;ribbonfarm.com&lt;/a&gt; blog where he ponders, among other things, organizational issues in high-technology firms, which is probably how he appeared on my radar screen. I don't always agree with him. Sometimes I'm not sure I'm smart enough to agree or disagree with him. But he's got some interesting ideas.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28344720-2591421315744981778?l=coverclock.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://coverclock.blogspot.com/feeds/2591421315744981778/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28344720&amp;postID=2591421315744981778' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/2591421315744981778'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/2591421315744981778'/><link rel='alternate' type='text/html' href='http://coverclock.blogspot.com/2011/12/venkatesh-rao-on-developernomics.html' title='Venkatesh Rao on Developernomics'/><author><name>Chip Overclock</name><uri>http://www.blogger.com/profile/11195242013008369733</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-1xNiFqWVjh8/TWQ1ru5Z6KI/AAAAAAAAABw/kMJyhvluNMI/s220/Chip%2BOverclock%2BAvatar%2B2.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28344720.post-1567313712900896436</id><published>2011-12-06T09:11:00.019-07:00</published><updated>2011-12-11T15:27:07.509-07:00</updated><title type='text'>Eventual Consistency and Hayloft</title><content type='html'>Given my thirty plus years of experience in distributed computing, it's a given that I've had to more or less continuously grapple with the &lt;i&gt;&lt;a href="http://en.wikipedia.org/wiki/Fallacies_of_distributed_computing_(Deutsch)"&gt;Fallacies of Distributed Computing&lt;/a&gt;&lt;/i&gt; as laid out by &lt;a href="http://en.wikipedia.org/wiki/L._Peter_Deutsch"&gt;L Peter Deutsch&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/James_Gosling"&gt;James Gosling&lt;/a&gt;, and others:&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;The network is reliable.&lt;/li&gt;&lt;li&gt;Latency is zero.&lt;/li&gt;&lt;li&gt;Bandwidth is infinite.&lt;/li&gt;&lt;li&gt;The network is secure.&lt;/li&gt;&lt;li&gt;Topology doesn't change.&lt;/li&gt;&lt;li&gt;There is one administrator.&lt;/li&gt;&lt;li&gt;Transport cost is zero.&lt;/li&gt;&lt;li&gt;The network is homogeneous.&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The implications of these myths led &lt;a href="http://en.wikipedia.org/wiki/Eric_Brewer_(scientist)"&gt;Eric Brewer&lt;/a&gt; to make &lt;i&gt;Brewer's Conjecture&lt;/i&gt;, which became the &lt;i&gt;&lt;a href="http://en.wikipedia.org/wiki/CAP_theorem"&gt;CAP Theorem&lt;/a&gt;&lt;/i&gt; once it was proven by Seth Gilbert and &lt;a href="http://en.wikipedia.org/wiki/Nancy_Lynch"&gt;Nancy Lynch&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;A distributed system can guarantee at most &lt;i&gt;two&lt;/i&gt; of the three following qualities:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;all nodes can see the same data at the same time (&lt;b&gt;c&lt;/b&gt;onsistency);&lt;/li&gt;&lt;li&gt;every request receives a response as to whether it succeeded or failed (&lt;b&gt;a&lt;/b&gt;vailability);&lt;/li&gt;&lt;li&gt;the system continues to operate despite message loss (&lt;b&gt;p&lt;/b&gt;artition tolerance).&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I've been thinking a lot about the implications of this for storage systems ever since attending the &lt;a href="http://coverclock.blogspot.com/2011/05/notes-on-msst-2011.html"&gt;27th IEEE Symposium on Massive Storage Systems and Technologies&lt;/a&gt;, a.k.a. MSST 2011. One of the big take aways I had from that conference was that distributed storage systems cannot reliably support &lt;a href="http://en.wikipedia.org/wiki/POSIX"&gt;POSIX&lt;/a&gt; semantics, in particular the POSIX features of file locking and consistency in file modification. Thanks to the CAP Theorem, POSIX semantics don't scale.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;(I find that all of the really interesting problems are scalability problems, regardless of the problem domain. If solving a problem at scale &lt;i&gt;n&lt;/i&gt; seems easy, trying applying the same solution at scale &lt;i&gt;n x 1000&lt;/i&gt;. Not so much. That's why domains like cloud computing and exascale high performance systems have caught my interest. You can't just take current architectures and multiple by one thousand.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This is one of the reasons that cloud storage has become popular: the various web-based mechanism for data transfer used by the cloud, like the &lt;a href="http://en.wikipedia.org/wiki/REST"&gt;RESTful&lt;/a&gt; &lt;a href="http://en.wikipedia.org/wiki/HTTP"&gt;HTTP&lt;/a&gt; GET and PUT, and &lt;a href="http://en.wikipedia.org/wiki/XML"&gt;XML&lt;/a&gt;-based &lt;a href="http://en.wikipedia.org/wiki/SOAP"&gt;SOAP&lt;/a&gt;, have semantics that have proven to be highly scalable. Hence they map well to large distributed system architectures.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It was this very issue that lead Amazon.com to adopt a strategy for its globally distributed Amazon Web Services (AWS), including S3, its non-POSIX-compliant Simple Storage Service, which its CTO Werner Vogels refers to as &lt;i&gt;&lt;a href="http://queue.acm.org/detail.cfm?id=1466448"&gt;eventually consistent&lt;/a&gt;&lt;/i&gt;, choosing availability and partition tolerance over consistency:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;blockquote&gt;Data inconsistency in large-scale reliable distributed systems has to be tolerated for two reasons: improving read and write performance under highly concurrent conditions; and handling partition cases where a majority model would render part of the system unavailable even though the nodes are up and running.&lt;/blockquote&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Indeed, the &lt;a href="http://www.infoworld.com/d/cloud-computing/the-failure-behind-the-amazon-outage-isnt-just-amazons-107"&gt;well publicized failures&lt;/a&gt; in AWS have been not in S3, but in its Elastic Block Store (EBS), which tries to support POSIX semantics on top of a globally distributed system.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I can see the Fallacies, and the eventual consistency architecture, at work when I play with &lt;a href="http://www.diag.com/navigation/downloads/Hayloft.html"&gt;Hayloft&lt;/a&gt;, my little C++ research project that uses S3. Any realistic application using S3 has to deal with network failures, where simply retrying the operation may be sufficient. But it also has to deal with the issues of consistency convergence: the fact that every S3 action may take place on a different AWS server that doesn't &lt;i&gt;yet&lt;/i&gt; know what actions have taken place on other AWS servers, even though those actions may have been performed on the same storage objects.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Hayloft features both a synchronous and an asynchronous interface. The former makes it easy to play with. The latter is more likely to be what a production application would use. The asynchronous interface features a mechanism to block until an S3 action completes, or to execute multiple S3 actions incrementally and in parallel. Unlike my &lt;a href="http://coverclock.blogspot.com/2011/12/amazons-simple-storage-service-and.html"&gt;prior article on Hayloft&lt;/a&gt;, I'll use the asynchronous interface here, but use the blocking completion mechanism because it's simpler. (As before, all of this code is taken from working unit tests in the Hayloft distribution, but edited for readability. Apologies for any typos.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here is a code snippet that creates a bucket to hold objects. It starts the action and blocks until it completes.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Multiplex multiplex;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;BucketCreate bucket("Bucket", multiplex);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;bucket.start();&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;multiplex.complete();&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;But that's not sufficient. Sometimes (rarely), the action will return a status indicating a temporary failure, like "connection failed", "name lookup error", or "request timed out". The network isn't reliable, and the failure more likely to be on my end, or somewhere along the convoluted path between my system and S3, than in S3 itself. Simply retrying the action after a one second delay is usually sufficient unless the outage is severe. (Note that "success" is not a retryable condition.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Multiplex multiplex;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style=" ;font-family:'courier new';"&gt;BucketCreate bucket("Bucket", multiplex);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;for (int ii = 0; ii &amp;lt; 10; ++ii) {&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;bucket.start();&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;multiplex.complete();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;if (!bucket.isRetryable()) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;platform.yield(platform.frequency());&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Once the bucket is created, we can store an object in it. Here's a code snippet similar to the one above except it has to deal with rewinding the input data source if we need to retry the action. You can see that this might get a smidge complicated depending on where your data is coming from.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;PathInput * source = new PathInput("./file.txt");&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Size bytes = size(*input);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style=" ;font-family:'courier new';"&gt;ObjectPut put("InputFile.txt", bucket, multiplex, &lt;/span&gt;&lt;span class="Apple-style-span"  style=" ;font-family:'courier new';"&gt;source&lt;/span&gt;&lt;span class="Apple-style-span"  style=" ;font-family:'courier new';"&gt;, bytes);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;for (int ii = 0; ii &amp;lt; 10; ++ii) {&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;put.start();&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;multiplex.complete();&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;if (!put.isRetryable()) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;platform.yield(platform.frequency());&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style=" ;font-family:'courier new';"&gt;source&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt; = new PathInput("./file.txt");&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;bytes = size(*input);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;put.reset(&lt;/span&gt;&lt;span class="Apple-style-span"  style=" ;font-family:'courier new';"&gt;source&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;, bytes);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;But network outages aren't the only failures we have to worry about. The following code snippet retrieves the metadata for the object we just created.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ObjectHead head(put, multiplex);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;for (int ii = 0; ii &amp;lt; 10; ++ii) {&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;head.start();&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;multiplex.complete();&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;if (!head.isRetryable()) { break; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;platform.yield(platform.frequency());&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This usually works. Except when it doesn't. Sometimes (and much more frequently than I see retries due to temporary network failures) the action will return a non-retryable status indicating the object wasn't found. WTF?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The object head action was serviced by a different AWS server than that of the object put action, one that hadn't yet been notified of the object put. This is eventual consistency in action. The unit test tries a code snippet like the following, treating the non-existence of the object as a retryable error, since it knows darn well the object put was successful.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ObjectHead head(put, multiplex);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;for (int ii = 0; ii &amp;lt; 10; ++ii) {&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-tab-span" style="white-space: pre; "&gt; &lt;/span&gt;head.start();&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-tab-span" style="white-space: pre; "&gt; &lt;/span&gt;multiplex.complete();&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-tab-span" style="white-space: pre; "&gt; &lt;/span&gt;if (head.isRetryable()) {&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;// Keep trying.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;} else if &lt;/span&gt;&lt;span class="Apple-style-span"  style=" ;font-family:'courier new';"&gt;(head.isNonexistent()) {&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style=" ;font-family:'courier new';"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;// Keep trying.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style=" ;font-family:'courier new';"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;} else {&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style=" ;font-family:'courier new';"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;break;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style=" ;font-family:'courier new';"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-tab-span" style="white-space: pre; "&gt; &lt;/span&gt;platform.yield(platform.frequency());&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style=" ;font-family:Georgia, serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;Eventually this works. But it's even more complicated than that. If you ran this exact same code snippet again, it might still fail at first, because it was run on yet another server which had not yet been updated to be consistent with the others. In fact, its success on a subsequent attempt may be because it just happened to be executed on the original server, not because all the servers had been updated. Applications have to be designed around this. Amazon's &lt;a href="http://aws.amazon.com/articles/1904"&gt;S3 best practices&lt;/a&gt; document recommends &lt;i&gt;not&lt;/i&gt; using code snippets like this to verify the successful put of an object.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The unit tests log a message every time they retry. I can actually watch how long it takes for the AWS servers to become consistent, and how this consistency convergence changes with the load on the system. Typically it converges so quickly that the unit test doesn't have to retry. Rarely, it takes a second or two. Or sometimes, not so rarely. I was testing a lot of this code on the day after the Thanksgiving holiday in the United States, also known as &lt;a href="http://en.wikipedia.org/wiki/Black_Friday_(shopping)"&gt;Black Friday&lt;/a&gt;, typically the busiest shopping day of the Christmas season. It frequently took two or three seconds for the system to converge to a consistent state. I haven't seen this kind of latency before or since. But, to its credit, S3 always converged and the unit tests all eventually ran successfully to completion.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Whether or not this is an issue for you depends on your S3 application. For a lot of applications, it won't matter. For applications where &lt;i&gt;read-after-write&lt;/i&gt; consistency is important, AWS offers a higher (more expensive) tier of service where objects are co-located in one of their big data centers instead of possibly being spread out among multiple centers; this tier offers read-after-write consistency. If &lt;i&gt;immediate&lt;/i&gt; consistency is an issue for you, S3 may not be right platform for your application. However, I would argue that distributed computing isn't the right paradigm for you.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The cloud is not the place for everyone.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28344720-1567313712900896436?l=coverclock.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://coverclock.blogspot.com/feeds/1567313712900896436/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28344720&amp;postID=1567313712900896436' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/1567313712900896436'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/1567313712900896436'/><link rel='alternate' type='text/html' href='http://coverclock.blogspot.com/2011/12/eventual-consistency-and-hayloft.html' title='Eventual Consistency and Hayloft'/><author><name>Chip Overclock</name><uri>http://www.blogger.com/profile/11195242013008369733</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-1xNiFqWVjh8/TWQ1ru5Z6KI/AAAAAAAAABw/kMJyhvluNMI/s220/Chip%2BOverclock%2BAvatar%2B2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28344720.post-3510110703472286394</id><published>2011-12-01T13:24:00.019-07:00</published><updated>2011-12-06T10:12:56.340-07:00</updated><title type='text'>Amazon.com's Simple Storage Service and Hayloft</title><content type='html'>Information technology is like fashion: you live long enough, you see it change many times. And sometimes the new stuff looks kinda like the old stuff. But that doesn't mean you don't get excited about it. Change is inevitable; you might as well learn to enjoy it.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I'm watching the IT world evolve to a model that is handheld battery powered consumer devices, which these days we're calling &lt;i&gt;smartphones&lt;/i&gt; and &lt;i&gt;tablets&lt;/i&gt;, communicating wirelessly with enormous distributed computing systems, which we now call &lt;i&gt;cloud computing&lt;/i&gt;. I'm all excited. For lots of reasons. Not the least of which is the fact that my professional career over the past thirty-five years as wobbled back and forth between developing software for small embedded systems and for high performance computers, gigantic distributed systems, and server farms. Turns out, the skill sets are the same. I am not the first person to have &lt;a href="http://www.eecs.berkeley.edu/Pubs/TechRpts/2006/EECS-2006-183.html"&gt;noticed this&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;My most recent project is to develop &lt;a href="http://www.diag.com/navigation/downloads/Hayloft.html"&gt;Hayloft&lt;/a&gt;, a C++ object oriented interface to &lt;a href="http://aws.amazon.com/"&gt;Amazon Web Services&lt;/a&gt; (AWS) &lt;a href="http://aws.amazon.com/s3/"&gt;Simple Storage Service&lt;/a&gt; (S3). My goal is for Hayloft to make it easy to use S3 from embedded devices. S3 is Amazon.com's web-based storage service that can (if you do it right) reliably and inexpensively store blobs of arbitrary data. How much data? A single blob, or &lt;i&gt;object&lt;/i&gt;, can be up to five terabytes in size. And you can store a lot of objects. Objects are organized into &lt;i&gt;buckets&lt;/i&gt;. Each bucket can be thought of as a web site with its own domain name, which means bucket names have to conform to the internet's Domain Name System (DNS) syntax. Each object is independently addressable via its own URL. To S3, these objects are simply opaque data files in the classic &lt;a href="http://www.ssswg.org/public_documents/MSSRM/ref.model.ver4.pdf"&gt;mass storage system reference model&lt;/a&gt; sense: they can range from HTML pages to scientific databases to virtual machine images to what have you. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;(Indeed, I strongly suspect you could build a distributed mass storage system from S3 just as &lt;a href="http://www.cyclecomputing.com/"&gt;Cycle Computing&lt;/a&gt; built a 10,000 core &lt;a href="http://www.networkworld.com/news/2011/040611-linux-supercomputer.html"&gt;distributed supercomputer&lt;/a&gt; from Amazon.com's &lt;a href="http://aws.amazon.com/ec2/"&gt;Elastic Computing Cloud&lt;/a&gt; (EC2) for one of their customers. I'm pretty excited about that, too.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Why would you you want to access S3 from an embedded device? Can you think of any applications for an infinitely large, internet-accessible, web-addressable, reliable, secure, storage system? Whether you are building clever consumer applications for the commercial space, developing sensor platforms for the defense and intelligence domain, or information processing applications for the industrial, financial, or medical markets, if the thought of this doesn't make your hands shake, you aren't thinking clearly. Seriously. Terabytes of storage are just a wireless connection away from your handheld and embedded applications.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here's a little taste of what Hayloft is like. These examples are taken directly from the unit test suite included with Hayloft with all the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;EXPECT&lt;/span&gt; and &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ASSERT&lt;/span&gt; statements removed. I've also removed all of the &lt;i&gt;error recovery&lt;/i&gt; and &lt;i&gt;consistency convergence&lt;/i&gt; code which in any practical circumstances are very necessary; I'll talk more about that in later articles. Hayloft presents both a synchronous and an asynchronous interface. These examples use the simpler synchronous interface: when the C++ constructor completes, all the S3 work is done.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here's a code snippet that creates a new bucket, and writes a local file into an object in it. The &lt;i&gt;user key id&lt;/i&gt; and&lt;i&gt; secret access key&lt;/i&gt;, which are sort of like your login and password for AWS, and which are provided by Amazon.com, are in environmental variables. Also in an environmental variable is a &lt;i&gt;bucket suffix&lt;/i&gt; appended to all bucket names to make them globally unique; I use my internet domain name. All of the other S3 parameters, like location constraint, endpoint, access control list, and so forth can be omitted, because for experimenting, the defaults are reasonable. Input and output is handled using &lt;a href="http://coverclock.blogspot.com/2011/11/abstraction-in-c-using-io-functors.html"&gt;Desperado I/O functors&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;BucketCreate create("bucket");&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;PathInput input("./oldfile.txt");&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Size bytes = size(input);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style=" ;font-family:'courier new';"&gt;ObjectPut put("Object.txt", create, input, bytes);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;By default, buckets and objects are created by Hayloft with private access. With just a few more lines you can specify public read access so that you can (and I have) retrieve this object using your web browser.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style=" ;font-family:'courier new';"&gt;AccessPublicRead access;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Context context;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;context.setAccess(access);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;BucketCreate create("bucket", context);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Properties properties;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;properties.setAccess(access);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;PathInput input("./oldfile.txt");&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Size bytes = size(input);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style=" ;font-family:'courier new';"&gt;ObjectPut put("Object.txt", create, input, bytes, properties);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style=" ;font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;This object can now be accessed using the following URL.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;http://bucket.hayloft.diag.com.s3.amazonaws.com/Object.txt&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This is a code snippet that reads the object into a local file, then deletes the object.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;PathOutput output("./newfile.txt");&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ObjectGet get("Object.txt", create, output);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ObjectDelete delete("Object.txt", create);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Other than some &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;#include&lt;/span&gt; statements for header files, and some curly brackets and what not, that's about all there is to it, if you ignore (at your peril) error recovery. Here's a snippet that gets a table of contents from an existing bucket, then uses the C++ Standard Template Library (STL) to iterate through it and print the object names.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;BucketManifest manifest("bucket");&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;BucketManifest::Manifest::const_iterator here = &lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;manifest.getManifest().begin();&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;BucketManifest::Manifest::const_iterator there = &lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;manifest.getManifest().end();&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;while (here != there) {&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;const char * key = here-&amp;gt;first.c_str();&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;printf("%s\n", key);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;++here;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;While using Hayloft is easy, installing it may take a few minutes. Hayloft is built for GNU and Linux on top of &lt;a href="http://www.diag.com/navigation/downloads/Desperadito.html"&gt;Desperadito&lt;/a&gt;, my C++ systems programming library (a subset of the much larger &lt;a href="http://www.diag.com/navigation/downloads/Desperado.html"&gt;Desperado&lt;/a&gt;), and &lt;a href="http://aws.amazon.com/developertools/1648"&gt;libs3&lt;/a&gt;, Bryan Ischo's excellent C-based S3 library. libs3 is built on top of CURL, Open SSL, and XML2, all of which can be probably acquired through the standard package manager on your Linux system. The unit tests for Hayloft are built with &lt;a href="http://code.google.com/p/googletest/"&gt;Google Test&lt;/a&gt; (or &lt;a href="http://code.google.com/p/googlemock/"&gt;Google Mock&lt;/a&gt;, which includes Google Test), Google's outstanding C++ unit testing framework, and &lt;a href="http://www.diag.com/navigation/downloads/Lariat.html"&gt;Lariat&lt;/a&gt;, my thin layer over Google Test.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;But once you get past the installation, starting to play with S3 in C++ applications is as simple as pulling out your credit card, &lt;a href="https://www.amazon.com/ap/signin?_encoding=UTF8&amp;amp;openid.assoc_handle=aws&amp;amp;openid.return_to=https%3A%2F%2Faws-portal.amazon.com%2Fgp%2Faws%2Fdeveloper%2Fregistration%2Findex.html&amp;amp;openid.mode=checkid_setup&amp;amp;openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&amp;amp;openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&amp;amp;openid.pape.max_auth_age=600&amp;amp;siteState=awsMode%3A%3Aregistration%3A%3AheaderMessage%3A%3AAmazon%20Web%20Services%20Sign%20Up%3A%3A&amp;amp;pageId=aws.ssop&amp;amp;openid.pape.preferred_auth_policies=http%3A%2F%2Fschemas.openid.net%2Fpape%2Fpolicies%2F2007%2F06%2Fmulti-factor-physical&amp;amp;marketplaceId=ATVPDKIKX0DER&amp;amp;accountStatusPolicy=P1&amp;amp;openid.ns.pape=http%3A%2F%2Fspecs.openid.net%2Fextensions%2Fpape%2F1.0&amp;amp;openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&amp;amp;authCookies=1"&gt;signing up&lt;/a&gt; for an AWS account, and writing a few lines of code.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28344720-3510110703472286394?l=coverclock.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://coverclock.blogspot.com/feeds/3510110703472286394/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28344720&amp;postID=3510110703472286394' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/3510110703472286394'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/3510110703472286394'/><link rel='alternate' type='text/html' href='http://coverclock.blogspot.com/2011/12/amazons-simple-storage-service-and.html' title='Amazon.com&apos;s Simple Storage Service and Hayloft'/><author><name>Chip Overclock</name><uri>http://www.blogger.com/profile/11195242013008369733</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-1xNiFqWVjh8/TWQ1ru5Z6KI/AAAAAAAAABw/kMJyhvluNMI/s220/Chip%2BOverclock%2BAvatar%2B2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28344720.post-26553854081585321</id><published>2011-11-26T10:05:00.005-07:00</published><updated>2011-11-26T10:19:27.122-07:00</updated><title type='text'>Making Both Archives and Shared Objects</title><content type='html'>It's not uncommon to want to support both static linking, with a library archive, and dynamic linking, with a shared object. I almost always choose the latter, but it is not uncommon for small embedded applications to be statically linked. This can actually reduce the memory footprint of the entire system when not many object files are shared. Or sometimes it's necessary for esoteric reasons of shared memory or what not. &lt;a href="http://code.google.com/p/googletest/"&gt;Google Test&lt;/a&gt;, my favorite C++ unit testing framework, actually recommends static linking against its &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;libgtest.a&lt;/span&gt; archive.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;When supporting both static and dynamic linking, I always generate the library archive, for example &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;libhayloft.a&lt;/span&gt;, then automate the generation of the shared object, &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;libhayloft.so&lt;/span&gt;. Here's a &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Makefile&lt;/span&gt; snippet that does that. It simply unloads the entire archive into a temporary directory, creates a shared object, then removes the directory. (I've resolved all the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;make&lt;/span&gt; variable names to make this a little more comprehensible.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;libhayloft.so:&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;libhayloft.a&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;HERE="`pwd`"; \&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;THERE="`mktemp -d /tmp/hayloft.XXXXXXXXXX`"; \&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;( cd $$THERE; ar xv $$HERE/libhayloft.a ); \&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;gcc -shared -Wl,-soname,libhayloft.so -o \&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;libhayloft.so $$THERE/*.o; \&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;rm -rf $$THERE&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28344720-26553854081585321?l=coverclock.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://coverclock.blogspot.com/feeds/26553854081585321/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28344720&amp;postID=26553854081585321' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/26553854081585321'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/26553854081585321'/><link rel='alternate' type='text/html' href='http://coverclock.blogspot.com/2011/11/making-both-archives-and-shared-objects.html' title='Making Both Archives and Shared Objects'/><author><name>Chip Overclock</name><uri>http://www.blogger.com/profile/11195242013008369733</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-1xNiFqWVjh8/TWQ1ru5Z6KI/AAAAAAAAABw/kMJyhvluNMI/s220/Chip%2BOverclock%2BAvatar%2B2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28344720.post-3783790143901968835</id><published>2011-11-24T07:55:00.011-07:00</published><updated>2011-11-26T03:03:34.856-07:00</updated><title type='text'>Dependency Generation with Subdirectories using gcc</title><content type='html'>Here I am on Thanksgiving morning working on my latest project, &lt;a href="http://www.diag.com/navigation/downloads/Hayloft.html"&gt;Hayloft&lt;/a&gt;. As is not uncommon, Mrs. Overclock (a.k.a. Dr. Overclock, Medicine Woman) has to work today, leaving your fearless leader to finish up the dinner preparations later in the day. So I thought I'd debug an issue that's been driving me to distraction: automatic dependency generation using the GNU &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;gcc/g++ &lt;/span&gt;compilers.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In Hayloft, I have translation units (that's what the standards call C and C++ source files) organized into subdirectories, for example &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;hayloft/Logger.cpp&lt;/span&gt; and &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;s3/BucketCreate.cpp&lt;/span&gt;, but using just one &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Makefile&lt;/span&gt;. This makes it easier to manage the code base, with absolutely no additional effort on my part, since the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;make&lt;/span&gt; command's pattern matching causes a rule like&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;%.o:&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;%.cpp&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;g++ -o $@ -c $&amp;lt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;to do exactly what I want: The &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;%&lt;/span&gt; in the target &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;%.o&lt;/span&gt; matches the entire file name path, for example &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;s3/BucketCreate&lt;/span&gt;, and is propagated into the prerequisite &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;%.cpp&lt;/span&gt;. The object file ends up in the same subdirectory. Life is good.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Alas, if I do the usual command to generate dependencies&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;g++ -MM -MG s3/BucketCreate.cpp&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;it creates a rule &lt;i&gt;not&lt;/i&gt; with the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;s3/BucketCreate.o&lt;/span&gt; target (which is what I want) but with &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;BucketCreate.o&lt;/span&gt;. Since I'm running the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Makefile&lt;/span&gt; from the project's root directory, there will never be a &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;BucketCreate.o&lt;/span&gt; nor a requirement for it. If I edit a prerequisite for &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;s3/BucketCreate.cpp&lt;/span&gt; (that is, any header file that it includes), &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;s3/BucketCreate.o&lt;/span&gt; will never be automatically regenerated.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So I had to write a little rule to go through the source code base, generate the dependencies for each source file individually, and prepend the directory path for that source file onto the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;make&lt;/span&gt; target. Here's what this looks like. (Apologies as usual for any Blogger editor weirdness.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;DEPENDS:=${shell find . -type f \( -name '*.c' \&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;-o -name '*.cpp' \) -print}&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;depend:&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;cp /dev/null dependencies.mk&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;for F in $(DEPENDS); do \&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;D=`dirname $$F | sed "s/^\.\///"`; \&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;echo -n "$$D/" &amp;gt;&amp;gt; dependencies.mk; \&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;$(CXX) $(CPPFLAGS) -MM -MG $$F \&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;   &lt;/span&gt;&amp;gt;&amp;gt; dependencies.mk; \&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;done&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;-include dependencies.mk&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It's a bit of a tribute to &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;make&lt;/span&gt; and the shell that this is even possible.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28344720-3783790143901968835?l=coverclock.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://coverclock.blogspot.com/feeds/3783790143901968835/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28344720&amp;postID=3783790143901968835' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/3783790143901968835'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/3783790143901968835'/><link rel='alternate' type='text/html' href='http://coverclock.blogspot.com/2011/11/dependency-generation-with.html' title='Dependency Generation with Subdirectories using gcc'/><author><name>Chip Overclock</name><uri>http://www.blogger.com/profile/11195242013008369733</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-1xNiFqWVjh8/TWQ1ru5Z6KI/AAAAAAAAABw/kMJyhvluNMI/s220/Chip%2BOverclock%2BAvatar%2B2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28344720.post-5325786339166469548</id><published>2011-11-14T08:52:00.010-07:00</published><updated>2011-11-14T14:43:32.350-07:00</updated><title type='text'>Abstraction in C++ using I/O Functors</title><content type='html'>In &lt;i&gt;&lt;a href="http://coverclock.blogspot.com/2009/01/abstraction-in-c-using-sources-and.html"&gt;Abstraction in C Using Source and Sinks&lt;/a&gt;,&lt;/i&gt; I wrote about how useful I've found it to abstract out I/O interfaces so that I could write software that didn't have to know from where its input was coming or to where its output was going: sockets, standard I/O library FILE pointers, memory buffers, the system log, etc. That C-based project, &lt;a href="http://www.diag.com/navigation/downloads/Concha.html"&gt;Concha&lt;/a&gt;, was a clean room reimplementation of work I had done for a client back in 2007. What I didn't mention was that it was in turn inspired by work I had done in 2006 for a C++-based project, &lt;a href="http://www.diag.com/navigation/downloads/Desperado.html"&gt;Desperado&lt;/a&gt;. Now that I'm building yet another project, &lt;a href="http://www.diag.com/navigation/downloads/Hayloft.html"&gt;Hayloft&lt;/a&gt;, on top of Desperado, I'm reminded how much I like the Desperado I/O abstraction.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;The Desperado I/O abstraction defines two interfaces, &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Input&lt;/span&gt; and &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Output&lt;/span&gt;. These interfaces make use of the ability in C++ to overload the parentheses operators to create &lt;i&gt;functors (&lt;/i&gt;a.k.a. &lt;i&gt;&lt;a href="http://en.wikipedia.org/wiki/Function_object"&gt;function objects&lt;/a&gt;&lt;/i&gt;): objects that can be manipulated through a function call interface. Looking at code, you will think you are looking at function calls. What you are really seeing are instance method calls against an object that overrides the &lt;/span&gt;parentheses&lt;span class="Apple-style-span"&gt; operators.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Input&lt;/span&gt; interface defines the following four operations.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;int operator() ();&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This returns the next character as an integer, or &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;EOF&lt;/span&gt; (end of file) to indicate that no more input is available.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;int operator() (int ch);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This pushes a single character back into the input stream. (This vastly simplifies the implementation of many common parsing algorithms that require one-token look ahead.) The interface guarantees that at least one character can be pushed back. It need not be the most recent character read. How the push back is actually done is up to the underlying implementation; buffering it inside the object in the derived class implementation is acceptable. If the push back is successful, the character is returned, otherwise &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;EOF&lt;/span&gt; is returned.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ssize_t operator() (char * buffer, size_t size);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This returns a line terminated by a newline character (&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;/n&lt;/span&gt;) or &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;EOF&lt;/span&gt;. The optional &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;size&lt;/span&gt; parameter allows the caller to place a limit on the number of characters returned. The result is guaranteed to be &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;NUL&lt;/span&gt; terminated as long as the buffer is at least one byte in length. The actual number of characters input is returned, or &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;EOF&lt;/span&gt; if none.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ssize_t operator() (void * buffer, size_t minimum, size_t maximum);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This is typically used for unformatted data. The &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;minimum&lt;/span&gt; parameter indicates the minimum number of characters to be returned. The implementation blocks until that many characters are available or &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;EOF&lt;/span&gt; is reached. The &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;maximum&lt;/span&gt; parameter indicates the maximum number of characters to be returned if it can be done without blocking. Specifying a &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;minimum&lt;/span&gt; of zero is a common way to implement non-blocking I/O using polling. Specifying the same value for &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;minimum&lt;/span&gt; and &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;maximum&lt;/span&gt; simply blocks for a fixed amount of data. Using the value one for &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;minimum&lt;/span&gt; results in something similar to the POSIX &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;read&lt;/span&gt; system call. The actual number of characters input is returned, or &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;EOF&lt;/span&gt; if none.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;That's it. No &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;open&lt;/span&gt; or &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;close&lt;/span&gt;: those are the job of either the caller, or of the implementation's constructor and destructor. The &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Input&lt;/span&gt; base class isn't pure: it actually implements all of these operators, returning &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;EOF&lt;/span&gt; for all operations. That makes the base class the equivalent of &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;/dev/null&lt;/span&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Since all implementations derive from the Input base class, you can pass a pointer or reference to any implementation to a function expecting an Input pointer or reference and it will read its data from that object without having any idea what the actual underlying data source is. Desperado implements a variety of derived classes, such as &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;DescriptorInput&lt;/span&gt; (its constructor takes a file descriptor as an argument), &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;FileInput&lt;/span&gt; (a FILE pointer), &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;BufferInput&lt;/span&gt; (a read/write memory buffer), &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;DataInput&lt;/span&gt; (a read-only memory buffer), and &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;PathInput&lt;/span&gt; (a path name in the file system). All of these derived classes implement the full &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Input&lt;/span&gt; interface.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The Hayloft project leverages this in its &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Parameter&lt;/span&gt; class. &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Parameter&lt;/span&gt; takes an &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Input&lt;/span&gt; reference or pointer, uses the line input functor, and reads a parameter value into a C++ &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;std::string&lt;/span&gt; that is a instance variable named &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;parameter&lt;/span&gt;. It has no idea where this value is coming from: a file, a socket, a memory location, what have you. Here's the complete implementation of the method in &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Parameter&lt;/span&gt; that does this.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;(I apologize in advance for any violence done to this and other code snippets by the Blogger formatter - which truly sucks at code examples even when editing raw HTML - and for any typos I make when transcribing this from actual working source code.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;void Parameter::source(Input &amp;amp; &lt;b&gt;input&lt;/b&gt;, size_t maximum) {&lt;br /&gt;int ch;&lt;br /&gt;while (maximum &amp;gt; 0) {&lt;br /&gt;ch = &lt;b&gt;input&lt;/b&gt;();&lt;br /&gt;if ((ch == EOF) || (ch == '\0') || (ch == '\n')) { break; }&lt;br /&gt;parameter += ch;&lt;br /&gt;--maximum;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;You can see the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Input&lt;/span&gt; functor called on the fourth line: the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;input&lt;/span&gt; object reference is used just as if it were a function.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;The &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Output&lt;/span&gt; interface defines the following five operations.&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;int operator() (int c);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A single character in an integer is emitted. The character is returned or &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;EOF&lt;/span&gt; if unsuccessful.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ssize_t operator() (const char * s, size_t size);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A null terminated string is emitted. The optional size parameter places a limit on the number of characters emitted. The actual number of characters emitted is returned or &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;EOF&lt;/span&gt; if none.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ssize_t operator() (const char * format, va_list ap);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A variable length argument list is emitted according to the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;printf&lt;/span&gt;-style format string. The actual number of characters emitted is returned or &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;EOF&lt;/span&gt; if none.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ssize_t operator() (const void * buffer, size_t minimum, size_t maximum);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;At least a &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;minimum&lt;/span&gt; and no more than a &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;maximum&lt;/span&gt; number of bytes are emitted. As before, more than the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;minimum&lt;/span&gt; is emitted if it can be done without blocking. The actual number of characters emitted is returned or &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;EOF&lt;/span&gt; if none.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;int operator() ();&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Any data buffered in the underlying implementation are flushed to the output stream. A non-negative number is returned for success, &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;EOF&lt;/span&gt; for failure.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Similar to the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Input&lt;/span&gt; interface, the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Output&lt;/span&gt; base class is not pure: it implements all of these functors, each of which throws the data away and returns success. The &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Output&lt;/span&gt; base class is also the equivalent of &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;/dev/null&lt;/span&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;As you might expect, Desperado implements a variety of derived classes: &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;DescriptorOutput&lt;/span&gt;, &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;FileOutput&lt;/span&gt;, &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;BufferOutput&lt;/span&gt;, &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;PathOutput&lt;/span&gt;, and &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;SyslogOutput&lt;/span&gt; (which writes all of its output to the system log).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The Desperado &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Print&lt;/span&gt; class makes effective of &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Output&lt;/span&gt; functors. Its constructor takes a single &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Output&lt;/span&gt; reference as its only parameter.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Print:Print(Output &amp;amp; &lt;b&gt;output&lt;/b&gt;);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Print&lt;/span&gt; defines its own functor which takes a variable length argument list. Here is its entire implementation.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ssize_t Print::operator() (const char * format ...) {&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt; va_list ap;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt; ssize_t rc;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt; va_start(ap, format);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt; rc = &lt;b&gt;output&lt;/b&gt;(format, ap);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt; va_end(ap);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt; return rc;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;You can see the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;output&lt;/span&gt; constructor reference used just like a function call on the fifth line.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In an application, you can now write code like this, which I do all the time. (&lt;i&gt;Warning: head explosion may be imminent.&lt;/i&gt;)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;extern Output * myoutputp;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Print &lt;b&gt;printf&lt;/b&gt;(*myoutputp);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;b&gt;printf&lt;/b&gt;("An error occurred!\n");&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;b&gt;printf&lt;/b&gt;("errno=%d\n", errno);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This illustrates one of the greatest strengths and greatest weaknesses of C++: if you encountered this while reading code, you would likely to assume that the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;printf&lt;/span&gt; was the standard I/O statement you know and love. But it isn't at all; it's a &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Print&lt;/span&gt; object. And that &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Print&lt;/span&gt; object has no idea where it's output is going. Depending on actual type of its constructor argument, it could be a socket, a file, or even a memory buffer.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It is possible to have a class that offers both an &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Input&lt;/span&gt; and an &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Output&lt;/span&gt; interface. Hayloft does this for its &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Packet&lt;/span&gt; class. &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Packet&lt;/span&gt; implements an infinite (as long as memory holds out anyway) bi-directional memory buffer. Although it offers specialized methods to prepend and append data, it also exposes both an &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Input&lt;/span&gt; and &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Output&lt;/span&gt; interface so that a &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Packet&lt;/span&gt; can be used as a data sink (by passing its &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Output&lt;/span&gt; interface) or as a data source (through its &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Input&lt;/span&gt; interface). A &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Packet&lt;/span&gt; can be used in this manner as a ring buffer.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This pattern is so common that Desperado defines an &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;InputOutput&lt;/span&gt; interface for such implementations. This interface defines two methods that each return a reference to the appropriate interface.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Input &amp;amp; input();&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Output &amp;amp; output();&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This allows you to do things like&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;extern Packet * mypacketp;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Print printf(mypacketp-&amp;gt;output());&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;to collect printed output into a Packet.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I/O functors illustrate one of those capabilities that makes C++ both extremely powerful and often hard to understand, because it allows one to use C++ not just as a programming language but as a &lt;i&gt;meta-language&lt;/i&gt;, effectively creating a new domain specific language with its own operations, one that just happens to look vaguely like C++. It also means that while reading C++ code, especially in large code bases, it can be very difficult to make any assumptions about what is going on without both a broad and a deep understanding of both C++ and the underlying code.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28344720-5325786339166469548?l=coverclock.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://coverclock.blogspot.com/feeds/5325786339166469548/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28344720&amp;postID=5325786339166469548' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/5325786339166469548'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/5325786339166469548'/><link rel='alternate' type='text/html' href='http://coverclock.blogspot.com/2011/11/abstraction-in-c-using-io-functors.html' title='Abstraction in C++ using I/O Functors'/><author><name>Chip Overclock</name><uri>http://www.blogger.com/profile/11195242013008369733</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-1xNiFqWVjh8/TWQ1ru5Z6KI/AAAAAAAAABw/kMJyhvluNMI/s220/Chip%2BOverclock%2BAvatar%2B2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28344720.post-615798196885706008</id><published>2011-10-31T11:59:00.029-06:00</published><updated>2011-11-14T08:52:38.357-07:00</updated><title type='text'>Up the Source Code Organization</title><content type='html'>&lt;span&gt;&lt;span&gt;I've spent decades working in humongous C and C++ source code bases. Humongous means many millions of lines of code. Some of it I even wrote. Most of it I didn't. Most of it didn't even originate in the organization in which I found myself working. Integrating large source bases in which major components weren't necessarily designed to work together can be a challenge. &lt;/span&gt;&lt;/span&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;With the plethora of open source software now available, it's not unusual that to use that new software stack that could save you months of development time, you discover you need to install a handful of other software stacks on which it depends. And those stacks have their own dependencies. And so on. Gone are the days in which you could just get by with the standard C library.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;These days at Digital Aggregates I've been working on a project that incorporates not only several third-party software stacks written in C or C++, but some of my own software libraries, some of which I wrote years ago. My integration experience has caused me to revisit how I put those libraries together. Laziness being a virtue among software developers, I've come up with some organizational techniques to make my life easier at least when using my own software. These techniques exploit two things: the Digital Aggregates domain name, diag.com, and a project name unique within the company, and borrows from similar techniques used in the Java world.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;Every Digital Aggregates project gets a project name. The name itself doesn't have to have any significance to the project, although it usually does in at least a pun-ish way that may only have meaning to me. The name is not an acronym, nor is it a name already used at the time by some well known (to me, anyway) software package&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;For example, today I wrote code using &lt;a href="http://www.diag.com/navigation/downloads/Desperado.html"&gt;Desperado&lt;/a&gt;, a collection of C++ classes that implement design patterns I've found useful in embedded software development; &lt;a href="http://www.diag.com/navigation/downloads/Diminuto.html"&gt;Diminuto&lt;/a&gt;, a collection of C functions that implement design patterns I've found useful in systems programming on Linux and GNU based systems; &lt;a href="http://www.diag.com/navigation/downloads/Lariat.html"&gt;Lariat&lt;/a&gt;, a small software wrapper around &lt;a href="http://code.google.com/p/googletest/"&gt;Google Test&lt;/a&gt;, Goggle's excellent C++ unit testing framework, that allows you to set resource limits like real-time execution duration on unit tests from the command line; and &lt;a href="http://www.diag.com/navigation/downloads/Hayloft.html"&gt;Hayloft&lt;/a&gt;, a work in progress. The project names help me keep everything straight.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;As mundane as it sounds, the project name starts life on a manilla file folder. I keep at least some paper documentation around, either temporarily or permanently. The manilla file folder keeps all of it together and it can be easily identified as it lays on my desk or is filed in the file cabinet. On my desk in my home office right now I have file folders labelled Biscuit, Lariat, and Hayloft. Just minutes ago I consulted the file folder labelled Desperado in the file cabinet.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;I keep lab notebooks that are organized not by project but chronologically and by client. I use the project name to identify notes I make in the notebook.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;Obviously, I use the project name when I write about my work here in my blog, as in &lt;a href="http://coverclock.blogspot.com/2011/10/automating-maintenance-on-embedded.html" style="font-style: italic; "&gt;Automating Maintenance on Embedded Systems with Biscuits&lt;/a&gt; where &lt;a href="http://www.diag.com/navigation/downloads/Biscuit.html"&gt;Biscuit&lt;/a&gt; is the project name.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;I also use it as part of the URL for the project page on the Digital Aggregates web site, for example&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;a href="http://www.diag.com/navigation/downloads/Desperado.html"&gt;http://www.diag.com/navigation/downloads/Desperado.html&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;which of course incorporates the Digital Aggregates domain name as well. Furthermore, the project name becomes part of the tar ball name. For example&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;a href="http://www.diag.com/ftp/desperado-zinc.tgz"&gt;http://www.diag.com/ftp/desperado-zinc.tgz&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;is a compressed tar ball for the Zinc distribution of Desperado.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;I use the project name as the repository name in &lt;a href="http://subversion.apache.org/"&gt;Subversion&lt;/a&gt;, my current source code control system of choice. My Subversion layout for every project follows the pattern I used for Desperado, and is more or less right out of the Subversion documentation.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span style="font-family:'courier new';"&gt;desperado/trunk/Desperado&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span style="font-family:'courier new';"&gt;desperado/tag/Desperado&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;desperado/branches/Desperado&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;desperado&lt;/span&gt; is the Subversion repository name. The directory &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;trunk&lt;/span&gt; contains the main development branch, &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;tag&lt;/span&gt; contains a check point of each major release, and &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;branches&lt;/span&gt; contains any temporary or ancillary development branches.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;Directory names on disk incorporate the project name. For example, the implementation files for Desperado are in&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;${HOME}/src/Desperado&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;where this is just a check out of the main development branch from Subversion.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;I'm a big fan of &lt;a href="http://www.eclipse.org/"&gt;Eclipse&lt;/a&gt;, the open source GUI-based IDE, for C, C++, and Java development. The project name becomes the Eclipse project name, so the name Desperado shows up in the Project Explorer or C/C++ views in Eclipse, with all the source files underneath it.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;Organizing header files for projects which use multiple components can be especially challenging, and I frequently see it done especially poorly. For my C and C++ projects that result in libraries intended to be used in other work, I've borrowed from some Java best practices and use both the domain name and project name as part of the header file path name. For example, a source file I was edited today had the following #include statements.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="font-family:'courier new';"&gt;#include "com/diag/hayloft/Packet.h"&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="font-family:'courier new';"&gt;#include "com/diag/desperado/Platform.h"&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="font-family:'courier new';"&gt;#include "com/diag/desperado/Print.h"&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;#include "com/diag/desperado/Dump.h"&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;The domain name becomes part of the path used to include the header file for a specific project. This approach is used not just by source files using the libraries, but also in the source files that implement the library. This makes it perfectly clear from which project a header file is being included, and prevents any header file name collisions. For example, the Desperado header files are under&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;${HOME}/src/Desperado/include/com/diag/desperado&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;while the Hayloft header files are under&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;${HOME}/src/Hayloft/include/com/diag/hayloft&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;and the GNU &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;g++&lt;/span&gt; or &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;gcc&lt;/span&gt; command line options&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;-I${HOME}/src/Desperado/include&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;and&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;-I${HOME}/src/Hayloft/include&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;are used to point the compiler to the right places. (You might choose to use the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;-iquote&lt;/span&gt; option instead.) Although these point to the source code directories where I do development, they could just as easily point to &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;/usr/include&lt;/span&gt; or maybe &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;/usr/local/include&lt;/span&gt; and the same naming system would prevent any conflicts with other header files.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;I'm also a fan of namespaces in C++, where I use a similar approach. All of the Desperado C++ symbols are in the namespace&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;::com::diag::desperado&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;where as all of the Hayloft C++ symbols are in the namespace&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;::com::diag::hayloft&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;which results in code snippets that look like the one below.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span style="font-family:'courier new';"&gt;namespace com {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span style="font-family:'courier new';"&gt;namespace diag {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span style="font-family:'courier new';"&gt;namespace hayloft {&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span style="font-family:'courier new';"&gt;/**&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span style="font-family:'courier new';"&gt; * Ctor.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span style="font-family:'courier new';"&gt;*/&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span style="font-family:'courier new';"&gt;explicit Logger(::com::diag::desperado::Output &amp;amp;ro)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span style="font-family:'courier new';"&gt;: ::com::diag::desperado::Logger(ro)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span style="font-family:'courier new';"&gt;, mask(0)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span style="font-family:'courier new';"&gt;{}&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span style="font-family:'courier new';"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span style="font-family:'courier new';"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;}&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;This is a constructor for the Hayloft class &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Logger&lt;/span&gt; that derives from the Desperado class &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Logger&lt;/span&gt; and uses a reference to an object of the Desperado &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Output&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; class as an argument.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;Furthermore, some projects require more complex namespace organizations, and this is reflected in both the implementation and header file directory hierarchies. For example, C++ symbols in the namespace&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;::com::diag::hayloft::s3&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;find their header files in&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;${HOME}/src/Hayloft/include/com/diag/hayloft/s3&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;and their implementation files in&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;${HOME}/src/Hayloft/s3&lt;/span&gt; .&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This may sound complex, but it is in practice easily done.&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;I predict now you are wondering what I do for C functions, where namespaces aren't an option. Using the Digital Aggregates domain name as part of C functions violates my laziness rule. It just seems to be more work than it's worth. But I do include the project name and a name roughly equivalent to a C++ class name into the function name. For example&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;void * diminuto_map_map(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt; uintptr_t start,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt; size_t length,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt; void ** startp,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt; size_t * lengthp&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;is a prototype for a C function in the Diminuto library that is part of the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;map&lt;/span&gt; feature for a function that maps a physical memory address to a virtual memory address.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;I use a similar approach when defining macros that are expanded by the C preprocessor, resulting in names like&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;DIMINUTO_LOG_PRIORITY_NOTICE&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;or&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;diminuto_list_next&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;which can sometimes seem a little cumbersome.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;I try not to use preprocessor macros at all when writing C++. But I do use the expanded naming system in both C and C++ when defining preprocessor guard symbols that prevent header files from being included more than once. This results, for example, in the guard preprocessor symbol&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span style="font-family:'courier new';"&gt;_H_COM_DIAG_HAYLOFT_S3_LOCATIONCONSTRAINT&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;for a C++ header file in the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;s3&lt;/span&gt; sub-directory and sub-namespace.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I do use the domain name in the name of any environmental variables. For example, you can set the log level in Hayloft by setting the value of an environmental variable&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;COM_DIAG_HAYLOFT_LOGGER_MASK&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;which incorporates the domain name, the project name, and even the class name. Since environmental variables are in a global namespace that is be shared among pretty much all of the software being used by a particular user, and because you typically don't have to type the environmental variable name very often, this seems the safest approach.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;In a future article I'll be talking about how I apply Google Test in projects like Hayloft, where I use a similar naming scheme that differs slightly to prevent collisions between the header files and classes under test and the test and mock classes themselves.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28344720-615798196885706008?l=coverclock.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://coverclock.blogspot.com/feeds/615798196885706008/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28344720&amp;postID=615798196885706008' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/615798196885706008'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/615798196885706008'/><link rel='alternate' type='text/html' href='http://coverclock.blogspot.com/2011/10/up-cc-organization.html' title='Up the Source Code Organization'/><author><name>Chip Overclock</name><uri>http://www.blogger.com/profile/11195242013008369733</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-1xNiFqWVjh8/TWQ1ru5Z6KI/AAAAAAAAABw/kMJyhvluNMI/s220/Chip%2BOverclock%2BAvatar%2B2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28344720.post-2222708216413356128</id><published>2011-10-14T12:44:00.025-06:00</published><updated>2011-10-18T08:11:16.611-06:00</updated><title type='text'>Automating Maintenance on Embedded Systems with Biscuits</title><content type='html'>If you make a living, as I have from time to time, developing embedded systems, it's not unusual to find your work day interrupted on a regular basis by application developers that want their own development systems updated to the latest platform release, or firmware installed to support a new version of an FPGA, or some other routine system maintenance chore. Even embedded systems based on Linux and GNU are frequently too small to implement the tools used by big iron, graphical interfaces like the &lt;i&gt;Synaptic Package Manager&lt;/i&gt; for Ubuntu, or even command line tools like &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;yum&lt;/span&gt;, &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;apt&lt;/span&gt;, or &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;dpkg&lt;/span&gt;. Sometimes the chore is as mundane as creating a tar ball of the system logs to ship back to you so you can debug a field problem. But you still don't want to burden a non-geek user with all the skills, and maybe even the root password, necessary to do that. What would be great is if you could automate that system maintenance chore in a secure fashion and get it done by just handing the user a USB thumb drive and telling them where to stick it. &lt;i&gt;Biscuits&lt;/i&gt; do that.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A biscuit is a &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;cpio&lt;/span&gt; archive that has been compressed with &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;bzip2&lt;/span&gt; and then encrypted using &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;gpg&lt;/span&gt; (&lt;i&gt;&lt;a href="http://www.gnupg.org/"&gt;GNU Privacy Guard&lt;/a&gt;&lt;/i&gt; a.k.a. GNUPG) into a binary file. The &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;biscuit&lt;/span&gt; command decrypts and decompresses the file, by default named &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;biscuit.bin&lt;/span&gt; in the current working directory, and extracts its contents into a temporary directory. It then looks for an unencrypted executable file named &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;biscuit&lt;/span&gt;, script or binary, in that directory. If it finds it, it modifies the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;PATH&lt;/span&gt; and &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;LD_LIBRARY_PATH&lt;/span&gt; environmental variables to include the temporary directory, changes its current working directory to the original delivery media (for example, a USB drive), and then runs the executable. What happens next is up to the executable. When the executable exits, the temporary directory is cleaned up and and deleted. While it runs, the executable has access to both the temporary directory, where any other collateral material from inside the biscuit can be found, and the working directory, where results may be placed.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Usage: biscuit [ -C &lt;i&gt;working_directory&lt;/i&gt; ] [ -f &lt;i&gt;biscuit_file&lt;/i&gt; ]&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;The encryption defaults to &lt;i&gt;&lt;a href="http://en.wikipedia.org/wiki/ElGamal_encryption"&gt;EIGamal&lt;/a&gt;&lt;/i&gt; (ELG-E), an asymmetric key encryption algorithm based on Diffie-Hellman key exchange, using 1024 bit keys. EIGamal is not patent encumbered, and although longer keys are possible, 1024 bits strikes a good balance between speed and security for slower embedded processors. The server where biscuits are packaged maintains a key ring containing the &lt;i&gt;public&lt;/i&gt; (encrypting) keys for all the embedded systems on which biscuits may be deployed.  Each embedded system has a key ring containing its own &lt;i&gt;secret &lt;/i&gt;(decrypting) keys.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Different unique public/secret key pairs can be created, allowing you to distinguish between product lines, architectures, even individual systems, whatever makes sense for your business. This allows you to create biscuits for product flavor A that cannot be executed on product flavor B: the wrong biscuits simply won't successfully decrypt. The encryption serves as both an authentication mechanism (the biscuit comes from a reputable source) and an authorization mechanism (the biscuit can be executed using root privileges). Since users can't crack open biscuits, they not only can't create their own biscuits, they can't even see what your biscuits do. Biscuits are opaque binary files. They cannot be easily reverse engineered without cracking the encryption. They can be delivered on removable media such as USB thumb drives, CD-ROMs, or DVDs, or they can be downloaded across a network via &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ftp&lt;/span&gt;, &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;tftp,&lt;/span&gt;or &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;scp&lt;/span&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I've been using this or similar approaches to automating system maintenance of embedded systems for several years now. A link to a clean room implementation of biscuits can be found on the &lt;a href="http://www.diag.com/navigation/downloads/Biscuit.html"&gt;Biscuit project web page&lt;/a&gt;. It's mostly just a Makefile to build GNUPG for multiple architectures, generate and manage the keys for both the build server and the embedded hosts, create the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;biscuit&lt;/span&gt; command, and package up biscuit binary files, plus a couple of example biscuit scripts. But the distribution tar ball also contains some useful stuff for automating the use of biscuits in your embedded system, depending on your needs and comfort level.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Users can just run the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;biscuit&lt;/span&gt; command manually and point it at a &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;biscuit.bin&lt;/span&gt; binary file. You can set your embedded host up so that only root can do so, so that users must use &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;sudo&lt;/span&gt; to run &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;biscuit&lt;/span&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If your embedded Linux system uses &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;udev&lt;/span&gt;, like big iron distributions like Ubuntu, you can install the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;99-com-diag-biscuit.rules&lt;/span&gt; file into &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;/etc/udev/rules.d/99-com-diag-biscuit.rules&lt;/span&gt; . That will cause your system to temporarily mount any block device that is inserted, look for a &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;biscuit.bin&lt;/span&gt; file, run the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;biscuit&lt;/span&gt; command against it, and unmount the device when it completes. The &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;udev&lt;/span&gt; rules I wrote for my use only apply to removable storage devices by excluding the device names used for permanently attached block storage. You should customize these rules to fit your own platform.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If your system uses a simpler version of &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;udev&lt;/span&gt;, like embedded distributions like Angström, you can install the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;mount.sh&lt;/span&gt; script into &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;/etc/udev/scripts/mount.sh&lt;/span&gt; to do the same thing. Or just look at the one line I inserted into Angström's &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;mount.sh&lt;/span&gt; that runs &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;biscuit&lt;/span&gt; against the auto-mounted media, and do something similar on your system.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If you have an older embedded system that doesn't use &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;udev&lt;/span&gt; but instead uses &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;hotplug&lt;/span&gt;, you can install the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;biscuit.hotplug.sh&lt;/span&gt; script into &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;/etc/hotplug.d/block/biscuit.hotplug&lt;/span&gt; to accomplish the same thing.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If your kernel was configured to support &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;hotplug&lt;/span&gt;, but you don't have any of the infrastructure, you can still do the above, plus you can install &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;hotplug.sh&lt;/span&gt; into &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;/sbin/hotplug&lt;/span&gt;. Look for &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;/proc/sys/kernel/hotplug&lt;/span&gt; on your embedded host. If it exists, your kernel is built to support it. If its contents are blank, then you need to tell the kernel to invoke &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;/sbin/hotplug&lt;/span&gt; by &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;echo&lt;/span&gt;-ing that string into &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;/proc/sys/kernel/hotplug&lt;/span&gt; every time you boot your system, or rebuild your kernel configured to do this automatically.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;There are some caveats you would be wise to heed.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Once biscuits are released into the wild, you must assume that they will go feral. People will dig up a USB drive you gave them years before, and insert it into a system. They may do so out of desperation, remembering that this did something useful long ago. Or they may simply have forgotten where the drive came from and don't even know that there is a biscuit on it. This is the dark side of biscuits: they are effectively viruses.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Biscuit scripts deal with the former by being paranoid: for example, before loading new firmware on a system, the script makes sure that the system isn't already running an even newer version of the firmware. I have also written scripts that deleted the original encrypted file from the USB drive, making it a &lt;i&gt;use once&lt;/i&gt; biscuit. Or the script dropped an identifying file on the USB drive (I like using a &lt;a href="http://en.wikipedia.org/wiki/MAC_address"&gt;MAC address&lt;/a&gt; from the host embedded system as a file name), and checked for the presence of this &lt;i&gt;breadcrumb&lt;/i&gt; first whenever it runs to check whether it has passed this way before. This approach works well because the user can delete the breadcrumb manually to force the biscuit to rerun.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If you include collateral material on the USB drive, for example scripts, shared libraries, binaries, data, try hard to put it &lt;i&gt;inside&lt;/i&gt; the biscuit. I have seen scripts that invoked another script in cleartext on the USB drive outside of the encrypted file. This allows a villain to simply rewrite the cleartext script to do whatever they want, like starting a root shell on the console, subverting the authentication and authorization provided by the encryption. Sometimes the collateral is simply too large to put inside the biscuit because of limits in available temporary storage, which on embedded systems is often RAM disk, into which the biscuit binary file is unpacked. If that's the case, put checksums or hashes (I like &lt;a href="http://en.wikipedia.org/wiki/MD5"&gt;MD5&lt;/a&gt; or &lt;a href="http://en.wikipedia.org/wiki/SHA-1"&gt;SHA-1&lt;/a&gt;) of the collateral inside the biscuit and have the script verify the likely integrity of the collateral before using it.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Similarly, use some care when the biscuit script executes commands that are on the embedded host. This is of course typically done, for example running fundamental stuff like &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;bash&lt;/span&gt;. But don't run scripts or binaries that can be altered by unprivileged users. Your security is only as good as that of your root password.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It is important that you build both the build server &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;gpg&lt;/span&gt; and the host embedded system &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;gpg&lt;/span&gt; from the same GNUPG source tree. You must not assume that different versions of GNUPG are interoperable. That may be the case, but if it isn't you'll end up creating biscuits on your build server that your embedded hosts can't use. If you do upgrade to a new version of GNUPG on your build server while you have deployed embedded hosts using the older version, be very thorough in your interoperability testing.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Once you build keys and have installed them on embedded hosts, check the keys into source code control or otherwise archive them. You will not get the same keys if you generate them again, even if you use exactly the same parameters. Again, you can render biscuits unusable if you are not careful. However, with some not too mad skills, you can recover lost keys from your deployed embedded systems themselves should a crisis occur.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Be paranoid about your keys, not just on the build server, but on your embedded hosts too. On the embedded hosts, which may be deployed into the field and hence presumably beyond your physical control, the keys and the directory that holds them should be accessible only by root. Unprivileged users should use &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;sudo&lt;/span&gt; to run the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;biscuit&lt;/span&gt; command manually, if they can do so at all.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;But with some care, biscuits are a means of safely automating a variety of system maintenance functions without giving away the keys to the kingdom or forcing end users or even application developers to become embedded systems programmers. For complex tasks like software update, they are a way of implementing complex logic and making it a part of the software distribution package, not part of a command in the embedded host itself.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28344720-2222708216413356128?l=coverclock.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://coverclock.blogspot.com/feeds/2222708216413356128/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28344720&amp;postID=2222708216413356128' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/2222708216413356128'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/2222708216413356128'/><link rel='alternate' type='text/html' href='http://coverclock.blogspot.com/2011/10/automating-maintenance-on-embedded.html' title='Automating Maintenance on Embedded Systems with Biscuits'/><author><name>Chip Overclock</name><uri>http://www.blogger.com/profile/11195242013008369733</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-1xNiFqWVjh8/TWQ1ru5Z6KI/AAAAAAAAABw/kMJyhvluNMI/s220/Chip%2BOverclock%2BAvatar%2B2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28344720.post-713129922846435725</id><published>2011-07-27T17:03:00.003-06:00</published><updated>2011-07-27T18:04:50.651-06:00</updated><title type='text'>Hidden Variables</title><content type='html'>Ever wonder what preprocessor symbols your GNU C and C++ compiler automatically includes in your program? I'm talking about symbols above and beyond those specified in the ANSI C and ISO C++ standards, like &lt;span style="font-family:courier new;"&gt;__FILE__&lt;/span&gt;, &lt;span style="font-family:courier new;"&gt;__LINE__&lt;/span&gt;, &lt;span style="font-family:courier new;"&gt;__func__&lt;/span&gt;, and &lt;span style="font-family:courier new;"&gt;__cplusplus&lt;/span&gt;. Having gotten bit by this once or twice, I've learned it pays to know these things. Try&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;gcc -dM -E - &amp;lt; /dev/null&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;or&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;g++ -dM -E - &amp;lt; /dev/null&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;which produce the same set of &lt;span style="font-family:courier new;"&gt;#define&lt;/span&gt; lines for me.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;div&gt;#define __DBL_MIN_EXP__ (-1021)&lt;/div&gt;&lt;div&gt;#define __FLT_MIN__ 1.17549435e-38F&lt;/div&gt;&lt;div&gt;#define __CHAR_BIT__ 8&lt;/div&gt;&lt;div&gt;#define __WCHAR_MAX__ 2147483647&lt;/div&gt;&lt;div&gt;#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 1&lt;/div&gt;&lt;div&gt;#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 1&lt;/div&gt;&lt;div&gt;#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1&lt;/div&gt;&lt;div&gt;#define __DBL_DENORM_MIN__ 4.9406564584124654e-324&lt;/div&gt;&lt;div&gt;#define __FLT_EVAL_METHOD__ 2&lt;/div&gt;&lt;div&gt;#define __unix__ 1&lt;/div&gt;&lt;div&gt;#define __DBL_MIN_10_EXP__ (-307)&lt;/div&gt;&lt;div&gt;#define __FINITE_MATH_ONLY__ 0&lt;/div&gt;&lt;div&gt;#define __GNUC_PATCHLEVEL__ 3&lt;/div&gt;&lt;div&gt;#define __DEC64_MAX_EXP__ 385&lt;/div&gt;&lt;div&gt;#define __SHRT_MAX__ 32767&lt;/div&gt;&lt;div&gt;#define __LDBL_MAX__ 1.18973149535723176502e+4932L&lt;/div&gt;&lt;div&gt;#define __UINTMAX_TYPE__ long long unsigned int&lt;/div&gt;&lt;div&gt;#define __linux 1&lt;/div&gt;&lt;div&gt;#define __DEC32_EPSILON__ 1E-6DF&lt;/div&gt;&lt;div&gt;#define __unix 1&lt;/div&gt;&lt;div&gt;#define __LDBL_MAX_EXP__ 16384&lt;/div&gt;&lt;div&gt;#define __linux__ 1&lt;/div&gt;&lt;div&gt;#define __SCHAR_MAX__ 127&lt;/div&gt;&lt;div&gt;#define __DBL_DIG__ 15&lt;/div&gt;&lt;div&gt;#define _FORTIFY_SOURCE 2&lt;/div&gt;&lt;div&gt;#define __SIZEOF_INT__ 4&lt;/div&gt;&lt;div&gt;#define __SIZEOF_POINTER__ 4&lt;/div&gt;&lt;div&gt;#define __USER_LABEL_PREFIX__ &lt;/div&gt;&lt;div&gt;#define __STDC_HOSTED__ 1&lt;/div&gt;&lt;div&gt;#define __LDBL_HAS_INFINITY__ 1&lt;/div&gt;&lt;div&gt;#define __FLT_EPSILON__ 1.19209290e-7F&lt;/div&gt;&lt;div&gt;#define __LDBL_MIN__ 3.36210314311209350626e-4932L&lt;/div&gt;&lt;div&gt;#define __DEC32_MAX__ 9.999999E96DF&lt;/div&gt;&lt;div&gt;#define __SIZEOF_LONG__ 4&lt;/div&gt;&lt;div&gt;#define __DECIMAL_DIG__ 21&lt;/div&gt;&lt;div&gt;#define __gnu_linux__ 1&lt;/div&gt;&lt;div&gt;#define __LDBL_HAS_QUIET_NAN__ 1&lt;/div&gt;&lt;div&gt;#define __GNUC__ 4&lt;/div&gt;&lt;div&gt;#define __FLT_HAS_DENORM__ 1&lt;/div&gt;&lt;div&gt;#define __SIZEOF_LONG_DOUBLE__ 12&lt;/div&gt;&lt;div&gt;#define __BIGGEST_ALIGNMENT__ 16&lt;/div&gt;&lt;div&gt;#define __DBL_MAX__ 1.7976931348623157e+308&lt;/div&gt;&lt;div&gt;#define __DBL_HAS_INFINITY__ 1&lt;/div&gt;&lt;div&gt;#define __DEC32_MIN_EXP__ (-94)&lt;/div&gt;&lt;div&gt;#define __LDBL_HAS_DENORM__ 1&lt;/div&gt;&lt;div&gt;#define __DEC128_MAX__ 9.999999999999999999999999999999999E6144DL&lt;/div&gt;&lt;div&gt;#define __DEC32_MIN__ 1E-95DF&lt;/div&gt;&lt;div&gt;#define __DBL_MAX_EXP__ 1024&lt;/div&gt;&lt;div&gt;#define __DEC128_EPSILON__ 1E-33DL&lt;/div&gt;&lt;div&gt;#define __LONG_LONG_MAX__ 9223372036854775807LL&lt;/div&gt;&lt;div&gt;#define __SIZEOF_SIZE_T__ 4&lt;/div&gt;&lt;div&gt;#define __SIZEOF_WINT_T__ 4&lt;/div&gt;&lt;div&gt;#define __GXX_ABI_VERSION 1002&lt;/div&gt;&lt;div&gt;#define __FLT_MIN_EXP__ (-125)&lt;/div&gt;&lt;div&gt;#define __DBL_MIN__ 2.2250738585072014e-308&lt;/div&gt;&lt;div&gt;#define __DECIMAL_BID_FORMAT__ 1&lt;/div&gt;&lt;div&gt;#define __DEC128_MIN__ 1E-6143DL&lt;/div&gt;&lt;div&gt;#define __REGISTER_PREFIX__ &lt;/div&gt;&lt;div&gt;#define __DBL_HAS_DENORM__ 1&lt;/div&gt;&lt;div&gt;#define __NO_INLINE__ 1&lt;/div&gt;&lt;div&gt;#define __i386 1&lt;/div&gt;&lt;div&gt;#define __FLT_MANT_DIG__ 24&lt;/div&gt;&lt;div&gt;#define __VERSION__ "4.4.3"&lt;/div&gt;&lt;div&gt;#define __DEC64_EPSILON__ 1E-15DD&lt;/div&gt;&lt;div&gt;#define __DEC128_MIN_EXP__ (-6142)&lt;/div&gt;&lt;div&gt;#define __i486__ 1&lt;/div&gt;&lt;div&gt;#define unix 1&lt;/div&gt;&lt;div&gt;#define __i386__ 1&lt;/div&gt;&lt;div&gt;#define __SIZE_TYPE__ unsigned int&lt;/div&gt;&lt;div&gt;#define __ELF__ 1&lt;/div&gt;&lt;div&gt;#define __FLT_RADIX__ 2&lt;/div&gt;&lt;div&gt;#define __LDBL_EPSILON__ 1.08420217248550443401e-19L&lt;/div&gt;&lt;div&gt;#define __SIZEOF_PTRDIFF_T__ 4&lt;/div&gt;&lt;div&gt;#define __DEC32_SUBNORMAL_MIN__ 0.000001E-95DF&lt;/div&gt;&lt;div&gt;#define __FLT_HAS_QUIET_NAN__ 1&lt;/div&gt;&lt;div&gt;#define __FLT_MAX_10_EXP__ 38&lt;/div&gt;&lt;div&gt;#define __LONG_MAX__ 2147483647L&lt;/div&gt;&lt;div&gt;#define __DEC128_SUBNORMAL_MIN__ 0.000000000000000000000000000000001E-6143DL&lt;/div&gt;&lt;div&gt;#define __FLT_HAS_INFINITY__ 1&lt;/div&gt;&lt;div&gt;#define __DEC64_MAX__ 9.999999999999999E384DD&lt;/div&gt;&lt;div&gt;#define __CHAR16_TYPE__ short unsigned int&lt;/div&gt;&lt;div&gt;#define __DEC64_MANT_DIG__ 16&lt;/div&gt;&lt;div&gt;#define __DEC32_MAX_EXP__ 97&lt;/div&gt;&lt;div&gt;#define linux 1&lt;/div&gt;&lt;div&gt;#define __LDBL_MANT_DIG__ 64&lt;/div&gt;&lt;div&gt;#define __DBL_HAS_QUIET_NAN__ 1&lt;/div&gt;&lt;div&gt;#define __WCHAR_TYPE__ int&lt;/div&gt;&lt;div&gt;#define __SIZEOF_FLOAT__ 4&lt;/div&gt;&lt;div&gt;#define __DEC64_MIN_EXP__ (-382)&lt;/div&gt;&lt;div&gt;#define __FLT_DIG__ 6&lt;/div&gt;&lt;div&gt;#define __INT_MAX__ 2147483647&lt;/div&gt;&lt;div&gt;#define __i486 1&lt;/div&gt;&lt;div&gt;#define __FLT_MAX_EXP__ 128&lt;/div&gt;&lt;div&gt;#define __DBL_MANT_DIG__ 53&lt;/div&gt;&lt;div&gt;#define __DEC64_MIN__ 1E-383DD&lt;/div&gt;&lt;div&gt;#define __WINT_TYPE__ unsigned int&lt;/div&gt;&lt;div&gt;#define __SIZEOF_SHORT__ 2&lt;/div&gt;&lt;div&gt;#define __LDBL_MIN_EXP__ (-16381)&lt;/div&gt;&lt;div&gt;#define __SSP__ 1&lt;/div&gt;&lt;div&gt;#define __LDBL_MAX_10_EXP__ 4932&lt;/div&gt;&lt;div&gt;#define __DBL_EPSILON__ 2.2204460492503131e-16&lt;/div&gt;&lt;div&gt;#define __SIZEOF_WCHAR_T__ 4&lt;/div&gt;&lt;div&gt;#define __DEC_EVAL_METHOD__ 2&lt;/div&gt;&lt;div&gt;#define __INTMAX_MAX__ 9223372036854775807LL&lt;/div&gt;&lt;div&gt;#define __FLT_DENORM_MIN__ 1.40129846e-45F&lt;/div&gt;&lt;div&gt;#define __CHAR32_TYPE__ unsigned int&lt;/div&gt;&lt;div&gt;#define __FLT_MAX__ 3.40282347e+38F&lt;/div&gt;&lt;div&gt;#define __SIZEOF_DOUBLE__ 8&lt;/div&gt;&lt;div&gt;#define __FLT_MIN_10_EXP__ (-37)&lt;/div&gt;&lt;div&gt;#define __INTMAX_TYPE__ long long int&lt;/div&gt;&lt;div&gt;#define i386 1&lt;/div&gt;&lt;div&gt;#define __DEC128_MAX_EXP__ 6145&lt;/div&gt;&lt;div&gt;#define __GNUC_MINOR__ 4&lt;/div&gt;&lt;div&gt;#define __DEC32_MANT_DIG__ 7&lt;/div&gt;&lt;div&gt;#define __DBL_MAX_10_EXP__ 308&lt;/div&gt;&lt;div&gt;#define __LDBL_DENORM_MIN__ 3.64519953188247460253e-4951L&lt;/div&gt;&lt;div&gt;#define __STDC__ 1&lt;/div&gt;&lt;div&gt;#define __PTRDIFF_TYPE__ int&lt;/div&gt;&lt;div&gt;#define __DEC64_SUBNORMAL_MIN__ 0.000000000000001E-383DD&lt;/div&gt;&lt;div&gt;#define __DEC128_MANT_DIG__ 34&lt;/div&gt;&lt;div&gt;#define __LDBL_MIN_10_EXP__ (-4931)&lt;/div&gt;&lt;div&gt;#define __SIZEOF_LONG_LONG__ 8&lt;/div&gt;&lt;div&gt;#define __LDBL_DIG__ 18&lt;/div&gt;&lt;div&gt;#define __GNUC_GNU_INLINE__ 1&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28344720-713129922846435725?l=coverclock.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://coverclock.blogspot.com/feeds/713129922846435725/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28344720&amp;postID=713129922846435725' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/713129922846435725'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/713129922846435725'/><link rel='alternate' type='text/html' href='http://coverclock.blogspot.com/2011/07/hidden-variables.html' title='Hidden Variables'/><author><name>Chip Overclock</name><uri>http://www.blogger.com/profile/11195242013008369733</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-1xNiFqWVjh8/TWQ1ru5Z6KI/AAAAAAAAABw/kMJyhvluNMI/s220/Chip%2BOverclock%2BAvatar%2B2.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28344720.post-8621531551098249391</id><published>2011-07-23T11:33:00.007-06:00</published><updated>2011-07-23T14:16:05.195-06:00</updated><title type='text'>Value Subtract</title><content type='html'>Back in the mid 1990s I spent a few years as a manager at the National Center for Atmospheric Research, a national lab that was chock full of supercomputers and smart people. Apparently I wasn't one of the smart people. It wasn't the first time I'd made the career misstep to go into management. This is how I came to understand that I added no value to that organization while I was in that role.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I went off to the People's Republic of China for a month on a scientific exchange program sponsored by the U.S. National Science Foundation and it's PRC counterpart. This was a pretty major departure, pun intended.  Nowadays I'd probably be able to keep up just carrying my Blackberry world phone and maybe my iPad. But way back then I was effectively cut off for a month pretty much from the entire English speaking and writing world.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Before I left, I programmed my desktop Solaris workstation to reply automatically to all of my incoming electronic mail, while filtering, categorizing, and filing it all away. At the time, I got maybe seventy email messages a day. That may seem like a low volume now, but remember this was BS, Before Spam, before the general public at large had access to electronic mail.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I had many adventures in China. I gave several talks. I kept a &lt;a href="http://www.diag.com/ftp/China_Journal.pdf"&gt;journal&lt;/a&gt;. I took &lt;a href="http://www.flickr.com/photos/johnlsloan/sets/72157601307321881/"&gt;photographs&lt;/a&gt;. It was like being on another planet. My journal could be read as a first contact story.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I returned to my office a month later, twelve pounds lighter and sporting a beard. I discovered that I had botched my email script. It had thrown all of the incoming email away. All of it. An entire month's worth of vitally important information consisting of status and problem reports, conference and request for proposal announcements, meeting summaries, vendor pleas, and cover their ass memos. All gone.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here is what I learned in the days and weeks to come: it didn't matter. It &lt;i&gt;never&lt;/i&gt; mattered. Ever. I never needed to know what was in any of those electronic communiques.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Perhaps you might have chosen to interpret this as a reflection on the low value of most of that email. Or on my ability to come back up to speed quickly. But I figured it meant I had actually very little to contribute to this organization, which for the most part ran just fine without me while I was gone for a twelfth of a year. If I wanted to make a difference, it was time for me to find something else to do with my life.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So I did. I quit that job just a few months later when an opportunity came along to join Bell Labs and return to being a technologist. I didn't fully appreciate at the time the impact, positive for the most part, this move would have on my career. And of course that job change would bring with it its own major life lessons.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;But those are stories for another day.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28344720-8621531551098249391?l=coverclock.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://coverclock.blogspot.com/feeds/8621531551098249391/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28344720&amp;postID=8621531551098249391' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/8621531551098249391'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/8621531551098249391'/><link rel='alternate' type='text/html' href='http://coverclock.blogspot.com/2011/07/value-subtract.html' title='Value Subtract'/><author><name>Chip Overclock</name><uri>http://www.blogger.com/profile/11195242013008369733</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-1xNiFqWVjh8/TWQ1ru5Z6KI/AAAAAAAAABw/kMJyhvluNMI/s220/Chip%2BOverclock%2BAvatar%2B2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28344720.post-2560360623523940089</id><published>2011-07-19T15:21:00.009-06:00</published><updated>2011-07-20T09:40:41.449-06:00</updated><title type='text'>Cyberspace Is The Next Battlefield</title><content type='html'>The U.S. Department of Defense just released an unclassified version of the document &lt;i&gt;&lt;a href="http://www.defense.gov/news/d20110714cyber.pdf"&gt;Department of Defense Strategy for Operating in Cyberspace&lt;/a&gt;&lt;/i&gt;. Yes, this is what I read for fun. It's only thirteen pages long. It's worth a look.&lt;div&gt;&lt;br /&gt;&lt;div&gt; &lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/5956043614/" title="Department of Defense Strategy for Operating in Cyberspace by John Sloan, on Flickr"&gt;&lt;img src="http://farm7.static.flickr.com/6136/5956043614_2eb9e49a7e.jpg" alt="Department of Defense Strategy for Operating in Cyberspace" width="385" height="500" /&gt;&lt;/a&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This very readable document outlines five strategic initiatives in how the DoD is going to deal with threats on the battlefield of cyberspace. But it's not really the initiatives I'm so concerned with. I like getting some insight into what this over &lt;a href="http://www.defense.gov/pdf/SUMMARY_OF_THE_DOD_FISCAL_2012_BUDGET_PROPOSAL_%283%29.pdf"&gt;half a trillion dollar&lt;/a&gt; agency is actually worried about and where they are likely to be spending their money. When it comes to technology, I feel about the DoD the way I do about high performance computing and the big cloud providers: whither they go, soon I shall be.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here are some snippets from the document that caught my eye. Emphasis is mine.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;/i&gt;&lt;blockquote&gt;&lt;i&gt;Low barriers to entry&lt;/i&gt; for malicious cyber activity, including the widespread availability of hacking tools, mean that an individual or small group of determined cyber actors can potentially cause significant damage ... &lt;i&gt;Small-scale technologies have an impact disproportionate to their size&lt;/i&gt; ... (p. 3)&lt;/blockquote&gt;&lt;/div&gt;&lt;div&gt;&lt;blockquote&gt;The potential for small groups to have an &lt;i&gt;asymmetric impact&lt;/i&gt; in cyberspace creates very real incentives for malicious activity. ... Whether the goal is &lt;i&gt;monetary, access to intellectual property, or the disruption of critical DoD systems&lt;/i&gt;, the rapidly evolving thread landscape presents a complex and vital challenge for national and economic security. ... (p. 3)&lt;/blockquote&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;blockquote&gt;... DoD is particularly concerned with three areas of potential adversarial activity: &lt;i&gt;theft or exploitation of data&lt;/i&gt;; &lt;i&gt;disruption or denial of access or service&lt;/i&gt; ...; and &lt;i&gt;destructive action including corruption, manipulation, or direct activit&lt;/i&gt;y ... (p. 3)&lt;/blockquote&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;blockquote&gt;... &lt;i&gt;computer-induced failure of power grids, transportation networks, or financial systems&lt;/i&gt; could cause massive physical damage and economic disruption. (p. 4)&lt;/blockquote&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;When I've seen the term &lt;i&gt;&lt;a href="http://en.wikipedia.org/wiki/Asymmetric_warfare"&gt;asymmetric warfare&lt;/a&gt;&lt;/i&gt; in the past, it has usually been used in the context of a high-technology opponent versus a low-technology opponent, or adversaries using traditional versus guerrilla strategies. But it applies here in an economic sense: it doesn't take a weapons program the scope of the Manhattan Project to bring economic ruin in the realm of cyberspace.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The &lt;a href="http://en.wikipedia.org/wiki/Stuxnet"&gt;Stuxnet&lt;/a&gt; worm completely changed the way I think about threats. Although it was surely an expensive program, requiring huge amounts of technical talent, the impact it had on Iran's nuclear program was surely disproportionately large compared to its cost. It is not hard to imagine either state or non-state actors bringing similar talent to bear on other critical technical infrastructure in the U.S. or elsewhere.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;At a &lt;a href="http://coverclock.blogspot.com/2011/05/notes-on-msst-2011.html"&gt;recent conference&lt;/a&gt;, I got chills thinking what malware inspired by Stuxnet could do if it infiltrated the firmware of tape drives used in a mass storage system. Don't laugh: most of the data in the world is still stored in tape. Son of Stuxnet could modify or remove data as it is being written to tape or as it is read back. This could render ground installations invisible in satellite photographs or accounts untraceable in financial records. A colleague of mine quipped that this kind of thing already happens by accident due to firmware bugs. The idea of it happening deliberately with specific intent is alarming.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;... Every year, &lt;i&gt;an amount of intellectual property larger than that contained in the Library of Congress is stolen&lt;/i&gt; from networks maintained by U.S. businesses, universities, and government departments and agencies. ... military strength ultimately depends on economic vitality ... (p. 4)&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;... Many &lt;i&gt;U.S. technology firms outsource software and hardware factors of production, and in some cases their knowledge base, to firms overseas&lt;/i&gt;. Additionally, increases in the number of counterfeit products and components demand procedures to both reduce risk and increase quality. ... (p. 9)&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Globalization is here to stay. That means it's now more important than ever to manage your supply chain and understand where your parts, both software and hardware, are really coming from.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;... DoD's acquisition processes and regulations must match the technology development life cycle. With information technology, this means &lt;i&gt;cycles of 12 to 36 months, not seven to eight years&lt;/i&gt;. ... DoD will be willing to sacrifice or defer some customization to achieve speedy internal improvements. ... (p. 11)&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;In &lt;i&gt;&lt;a href="http://coverclock.blogspot.com/2009/12/product-development-as-warfighting.html"&gt;Product Development as War Fighting&lt;/a&gt;&lt;/i&gt; I applied the principles espoused by the late John Boyd, the U.S. Air Force officer who revolutionized both air and ground combat, to software development. The kind of rapid iteration that this document discusses is just the kind of thing Boyd was talking about about when he referred to &lt;i&gt;fast transients&lt;/i&gt; and his &lt;i&gt;Observe, Orient, Decide Act&lt;/i&gt; (OODA) cycle in combat. Victory goes to the opponent who can make the correct decision and act upon it the most quickly. This applies to the choice of technology and its deployment as well.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If your organization is developing its own strategy to deal with information security, it is worth your time to read this document and see if they thought of something that you missed. For sure, they have a lot more eyes on the problem.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28344720-2560360623523940089?l=coverclock.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://coverclock.blogspot.com/feeds/2560360623523940089/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28344720&amp;postID=2560360623523940089' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/2560360623523940089'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/2560360623523940089'/><link rel='alternate' type='text/html' href='http://coverclock.blogspot.com/2011/07/cyberspace-is-next-battlefield.html' title='Cyberspace Is The Next Battlefield'/><author><name>Chip Overclock</name><uri>http://www.blogger.com/profile/11195242013008369733</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-1xNiFqWVjh8/TWQ1ru5Z6KI/AAAAAAAAABw/kMJyhvluNMI/s220/Chip%2BOverclock%2BAvatar%2B2.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm7.static.flickr.com/6136/5956043614_2eb9e49a7e_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28344720.post-6110270956891819721</id><published>2011-07-16T11:18:00.004-06:00</published><updated>2011-07-16T11:51:14.559-06:00</updated><title type='text'>Smaller Is Better</title><content type='html'>&lt;div&gt;The desktop that I use for software development is an Apple Mac Mini. It's mostly an X window server for a couple of Linux systems that are my build and repository servers. Below you can see the tiny silver Mac Mini sitting on a shelf above the Cinema Display.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/5336396923/" title="Contraption using Android FroYo, SSH, and Bash by John Sloan, on Flickr"&gt;&lt;img src="http://farm6.static.flickr.com/5002/5336396923_37bc443fe1.jpg" width="500" height="281" alt="Contraption using Android FroYo, SSH, and Bash" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here are the servers in the basement, next to a spare LCD display, a honking big H-P full duplex color laser printer, and two two-drawer fire-rated filing cabinets. My backup strategy is as follows: I backup my two principle laptops, a MacBook Air and a ThinkPad X61t, to USB disk drives; I backup the two servers by doing disk-to-disk copies to removable disk drives; I do smaller incremental backups to media like CD and DVD ROMs and USB thumb drives; I also keep backups of individual projects on an off-site server.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/5943596186/" title="Fire Safes by John Sloan, on Flickr"&gt;&lt;img src="http://farm7.static.flickr.com/6143/5943596186_5c47fccf5e.jpg" width="500" height="281" alt="Fire Safes" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The backups are kept in one of the fire safe drawers. When I travel, any of the laptops that don't travel with me also go into the drawer. The ThinkPad actually fits in a file folder. The Air doesn't quite fit, but there is enough clearance for it to just sit length-wise on top of the file folders.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/5943042749/" title="Fire Safe: Backups by John Sloan, on Flickr"&gt;&lt;img src="http://farm7.static.flickr.com/6024/5943042749_7c2bfbbc13.jpg" width="500" height="281" alt="Fire Safe: Backups" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;On a recent trip I was just taking my Blackberry and my iPad. Both laptops went into the safe. I was regretting not having done a recent backup of my desktop system, when I realized I was thinking about this all wrong. The Mac Mini is small. Really small. File folder small.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/5943595778/" title="Mac Mini by John Sloan, on Flickr"&gt;&lt;img src="http://farm7.static.flickr.com/6147/5943595778_24e2f21cfd.jpg" width="500" height="281" alt="Mac Mini" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;All of the connectors on the business end of the Mini disconnect easily.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/5943043221/" title="Mac Mini Desktop: The Business End by John Sloan, on Flickr"&gt;&lt;img src="http://farm7.static.flickr.com/6027/5943043221_f2db486959.jpg" width="500" height="281" alt="Mac Mini Desktop: The Business End" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This makes it trivial to shutdown my desktop, disconnect it from the network, display, and USB cables, and place the entire desktop system in a file folder in the fire safe, leaving the cables velcro-tied together and just dangling.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/5943043729/" title="Mac Mini Desktop: Cables by John Sloan, on Flickr"&gt;&lt;img src="http://farm7.static.flickr.com/6138/5943043729_34344212d3.jpg" width="500" height="281" alt="Mac Mini Desktop: Cables" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Good luck doing that with a standard-sized white box PC cabinet.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Smaller is better.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28344720-6110270956891819721?l=coverclock.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://coverclock.blogspot.com/feeds/6110270956891819721/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28344720&amp;postID=6110270956891819721' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/6110270956891819721'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/6110270956891819721'/><link rel='alternate' type='text/html' href='http://coverclock.blogspot.com/2011/07/smaller-is-better.html' title='Smaller Is Better'/><author><name>Chip Overclock</name><uri>http://www.blogger.com/profile/11195242013008369733</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-1xNiFqWVjh8/TWQ1ru5Z6KI/AAAAAAAAABw/kMJyhvluNMI/s220/Chip%2BOverclock%2BAvatar%2B2.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm6.static.flickr.com/5002/5336396923_37bc443fe1_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28344720.post-2946340450548244729</id><published>2011-07-06T09:00:00.008-06:00</published><updated>2011-07-09T08:52:13.516-06:00</updated><title type='text'>We've all got time enough to cry.</title><content type='html'>David Finkleman and his colleagues have published an article, "&lt;a href="http://www.americanscientist.org/issues/feature/2011/4/the-future-of-time-utc-and-the-leap-second"&gt;The Future of Time: UTC and the Leap Second&lt;/a&gt;", in the July-August 2011 issue of &lt;i&gt;&lt;a href="http://www.americanscientist.org/"&gt;American Scientist&lt;/a&gt;&lt;/i&gt; (Vol. 99, No. 4, pp. 312-319; also: &lt;a href="http://www.agi.com/downloads/media-center/in-the-news/Future-Of-Time-American-Scientist-July-Aug-2011.pdf"&gt;here&lt;/a&gt; and &lt;a href="http://arxiv.org/pdf/1106.3141"&gt;here&lt;/a&gt;) on the proposal by the Radiocommunications Sector of the International Telecommunications Union (ITU-R) to cease adding leap seconds to Coordinated Universal Time (UTC) so that it would no longer be kept in sync with the earth's rotation. The ITU-R organization is proposing this because &lt;i&gt;it's just too hard&lt;/i&gt;.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;GPS time already forgoes the use of leap seconds, and as a result, just in the time that GPS time has existed, the wall clock time we know from the rotation of the Earth, slowing due to the drag caused by the lunar tides, has drifted fifteen seconds from the time GPS keeps through the use of its atomic clocks. Hardware and software that displays wall clock time, but which synchronizes to GPS time, has to keep track of those missing leap seconds and add them back in. If such a change were to be made, it would mean UTC would be completely abstracted away from the wall clock time we use on a day to day basis.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Is this a good thing, or a bad thing? I don't know. But it sure as heck is not a minor thing. I got into the study of time for two reasons: it turned out to be critical to many of the products I've worked on in the past two decades, and much of the software I've used gets it wrong. UTC diverging from the wall clock time we use to manage our systems will only make this harder.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I've added an update to my 2006 article on date and time keeping "&lt;a href="http://coverclock.blogspot.com/2006/11/does-anybody-really-know-what-time-it.html"&gt;Does anybody really know what time it is?&lt;/a&gt;".&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28344720-2946340450548244729?l=coverclock.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://coverclock.blogspot.com/feeds/2946340450548244729/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28344720&amp;postID=2946340450548244729' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/2946340450548244729'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/2946340450548244729'/><link rel='alternate' type='text/html' href='http://coverclock.blogspot.com/2011/07/david-finkleman-and-his-colleagues-have.html' title='We&apos;ve all got time enough to cry.'/><author><name>Chip Overclock</name><uri>http://www.blogger.com/profile/11195242013008369733</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-1xNiFqWVjh8/TWQ1ru5Z6KI/AAAAAAAAABw/kMJyhvluNMI/s220/Chip%2BOverclock%2BAvatar%2B2.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28344720.post-2021018864270171474</id><published>2011-06-20T08:10:00.033-06:00</published><updated>2011-08-12T15:30:51.684-06:00</updated><title type='text'>Data Remanence and Solid State Drives</title><content type='html'>Deep in the subterranean bowels of the Palatial Overclock Estate (a.k.a. the Heavily Armed Overclock Compound) is a box containing every disk drive from every computer that has ever graced our home. There is another box containing every personal digital assistant, every mobile phone, and any other device featuring persistent read-write storage that may contain personal information about myself or Mrs. Overclock.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;We're not paranoid. We're just thinking clearly.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The issue here is &lt;i&gt;&lt;a href="http://en.wikipedia.org/wiki/Data_remanence"&gt;data remanence&lt;/a&gt;&lt;/i&gt;: how to insure that data has really been erased from a storage device. Data that may contain passwords, account numbers, records, schedules, notes, and anything else that could be used and misused by a miscreant, a competitor, or a court of law.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;We're not the only ones concerned about this. Mrs. Overclock, a.k.a. Dr. Overclock, Medicine Woman, has to carefully conform to regulations and laws concerning the privacy of the personal medical records of her patients, and that includes computerized medical records. Several times I've been on site at a major financial firm back east whose privacy policies to deal with their clients' personal financial data required their security people to roam their multi-building campus and confiscate any device, ranging from laptop to thumb drive, that was left unsecured and unattended at some poor careless slob's desk. And it seems like every day brings another news story about someone who bought a used computer only to discover that it contained a fascinating wealth of personal data from the previous owner.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I'm writing this article on my beloved MacBook Air, a slim, light, beautifully designed laptop. It is the first laptop I've ever used that does not contain a rotating disk like my other laptops and desktops. I'm using the term "rotating" here quite deliberately to refer to traditional disk drives that have rotating platters that store information magnetically. Nor does it have flash memory, which is a semiconductor device that stores data even when powered off but unlike a rotating disk has no moving mechanical parts, like my personal digital assistants. Instead it has a hybrid device: a solid-state drive (SSD). An SSD stores data persistently in a semiconductor device with no moving parts but which emulates a traditional rotating disk drive. This allows the SSD to be used transparently (more or less, as we shall soon see) in applications which expect a disk drive.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;SSDs offer extreme ruggedness, lower power consumption, and potentially much higher performance than rotating disk drives, albeit at a much higher price. This makes them attractive in applications ranging from hand-held portable devices such as mobile phones and laptops (where the attraction is principally the ruggedness and lower power consumption) to very high end servers (for the performance and lower power consumption). At the same time, SSDs bring exciting, some might say terrifying, new issues to the realm of data remanence. To understand why, we have to briefly look at other forms of digital storage, and kind of sneak up from behind on how SSDs actually work on the inside.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Rotating Disks and Tapes&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;Rotating disks and tapes are inherently mechanical devices that store data magnetically and have to go through a lot of drama involving moving parts which you never see to read and write your data. While they require power to read and write, when powered-off they are capable of storing data for a long long time, years or even decades, without significant degradation. With some extremely expensive equipment you can actually see the tiny magnetic dots that form the bits of your data. How tiny? Modern magnetic media store many gigabits per square inch. A single disk or tape that you can hold in your hand can store several terabytes of data. A terabyte is a million million bytes. That's a lot of bytes.&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Both rotating disks and tapes store data in a chunk or &lt;i&gt;block&lt;/i&gt; of bytes, and the disk or tape drive reads or writes an entire block at a time. A typical disk drive like you have in your laptop stores data in fixed sized blocks of 512 bytes each. Lots of software, including the operating system running on your laptop, was designed, implemented, and optimized under the assumption on the data being stored in 512 byte blocks. This assumption will become important when we look at SSDs.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Both rotating disks and tapes incur a lot of latency in both read and write operations. In the case of a random read or write to a rotating disk, a mechanical arm containing a read-write head has to swing laterally across the surface of the magnetic platter to be positioned over the correct &lt;i&gt;cylinder&lt;/i&gt; where the data resides, and then wait for the correct &lt;i&gt;sector&lt;/i&gt; where the data resides within the cylinder to travel beneath the head as the platter rotates. These two delays are referred to as the &lt;i&gt;seek &lt;/i&gt;latency and the &lt;i&gt;rotational&lt;/i&gt; latency respectively, and together can amount to several milliseconds. Tapes incur seek latency as well, but since tapes are typically used for strictly sequential reads and writes, and tape drive hardware and software is optimized to keep the tape moving, tape drives can and typically do out perform disk drives in terms of raw read and write performance. Only a mad man, or someone with lots of time on their hands, uses tapes for random reads and writes. I've done it.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;With rotating disk drives and tapes, the issue of data remanence has been explored thoroughly since the 1960s. The gold-standard in paranoia is the U.S. National Security Agency (NSA), whose publicly available document on this topic, the &lt;i&gt;&lt;a href="http://www.nsa.gov/ia/_files/government/MDG/NSA_CSS_Storage_Device_Declassification_Manual.pdf"&gt;Storage Device Declassification Manual&lt;/a&gt;,&lt;/i&gt; recommends degaussing a disk or tape, that is, using a strong electro-magnetic to disrupt the magnetic properties of the media, then physically damaging the drive so that it is a little more obvious to the casual observer that it cannot be used. In both cases, incineration is a second option. Other sources recommend dropping the disk drive in an industrial shredder that reduces it to tiny metal bits. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Note that merely deleting a disk file is entirely inadequate. As everyone who has not been living in a cave realizes, deleting a file merely deletes its &lt;i&gt;metadata&lt;/i&gt;, its name and information about its location on the disk, from a directory that is also stored on the disk. It may not even do that; it may just mark the file as deleted, leaving all the metadata at least temporarily in place. Unless you are using some very clever software, the data bits in the original file are all still on disk, where they can be recovered by some even cleverer software, as a lot of crooked politicians, child pornographers, and bent accountants have all discovered to their woe.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;To truly erase a file from disk or tape, you must write new bits directly over the old bits of the file. This will keep all but the most motivated and technically advanced individuals from recovering the data. But there as been a lot research that has shown that even then, some, many, or even most of the overwritten bits can be recovered, or at least inferred with a high degree of certainty, using devices like electronic microscopes. Which is exactly why the NSA requires destructive degaussing if not outright incineration. Nuke it from orbit. It's the only way to be sure.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Random Access Memory&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Random access memory (RAM) is a semiconductor device, a hunk of metal and silicon, with no moving parts. It is used to store data and software temporarily while it is in active use. RAM is what software developers mean when they say "memory". RAM stores data reliably only as long as power is applied to it. Although we think of RAM as been read or written a byte at a time, modern memory systems only read and write a word at a time to a single RAM device, where a word might be two, four, or even eight bytes in width. There is a lot of hard-wired logic in current microprocessors to handle the conversion between byte access and word access.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The NSA seems quite confident that RAM data is not recoverable after loss of power. However, there has been some research regarding supercooling certain types of RAM right at power off, then using yet more extremely expensive devices to read or infer the bits from the deeply frozen device. As paranoid as I am, I can't say I'm concerned about data remanence in RAM. But people who are looking at the ability to extract secret keys from cryptographic devices that are used, for example, in automated teller machines, are.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Flash Memory&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Like RAM, flash memory is also a semiconductor device with no moving parts. It stores your data at the atomic level, as electrons that are trapped in the physical material of the device. Like rotating disk drives, flash memory is persistent, maintaining its data after being powered off. Data storage in flash memory isn't permanent, and its longevity isn't measured in decades like that of the magnetic storage of rotating disks or tapes. But it takes years for the electrical charges stored in a flash device to bleed out, long after you have upgraded to a larger thumb drive.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;There are broadly two kinds of flash memory: NOR flash and NAND flash. NOR (literally "not or") and NAND ("not and") describe the kinds of logical operations the device emulates in its very low level operation. That's of less interest to us here than the other properties that make NOR and NAND flash differ from one another, and that makes flash memory of either variety very different from rotating disks, tapes, or even RAM.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;NOR flash can read just like like random access memory: data in memory are referenced directly using just an address and hence read by software without much drama. In fact, if the hardware and operating system is suitably designed, software programs can be executed directly out of NOR flash where the system is none the wiser as long as it doesn't try to write to the NOR flash as if it were RAM. This capability is called &lt;i&gt;execute in place&lt;/i&gt; (XIP).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;NOR flash is written more like a disk drive: commands are sent to a hardware controller implemented inside the NOR flash device that writes data a fixed-sized &lt;i&gt;page&lt;/i&gt; at a time. The size of a single flash page depends on the specific flash device, but typical sizes are two or four kilobytes, or several times the size of a typical logical disk block. So you can't just write a single byte or even word of NOR flash. You have to write an entire page, and you have to go through a pretty arcane series of steps to do it. That's how NOR flash differs functionally from RAM, and is also why NOR flash is used as a read-only memory (ROM).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;NAND flash extends this disk drive-like interface to both writing and reading. Writes and reads to and from NAND flash is done in a fixed sized page of bytes at a time. Unlike NOR flash, you can't just read a single word. That's how NAND flash differs functionally from NOR flash.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Now here's how both NOR and NAND flash differ from everything we've talked about so far. Whereas blocks on disk and tapes, and words on RAM, can be read, written and over-written, flash memory of either variety requires a third operation: erase. This isn't an optional operation like exists in some disk or tape drives that overwrites existing data. A write operation in flash can only change a binary one to a binary zero. That's how it works right down at the atomic level.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If you want to change the value of that bit, you first have to erase it, turning it back into a binary one. A virgin flash device right from the factory will read as all binary ones, because it arrives at your door in the fully erased state. When you write to it a page at a time, the silicon is selectively turning ones to zeros in the semiconductor media of the flash device. If you want to turn zeros back into ones, you must first erase. Furthermore, an erase operation is done not a &lt;i&gt;page&lt;/i&gt; at a time, but a &lt;i&gt;block&lt;/i&gt; at a time. The size of a flash block again depends on the specific flash device, but a typical size is 128 kilobytes, many times the size of a flash page.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;You can see this is getting complicated. You read and write pages, but you erase blocks, and you must erase an entire block in order to write over even a single page within that block. But it gets worse. Erases don't come for free. Every time you erase a block in a flash device, you are actually permanently altering the device. Do enough erases and eventually the flash device quits working. Unlike RAM and other semiconductor devices, flash &lt;i&gt;wears out&lt;/i&gt;. And yes, this applies to consumer devices that use NAND flash, like a USB thumb drive or your tiny digital music player.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Again broadly speaking, flash memory is manufactured in two basic flavors: single-level cell (SLC), and multi-level cell (MLC), depending on how many bits are stored in each flash cell, the basic unit of flash storage. SLC stores a single bit, MLC more than one bit. SLC can endure about a hundreds of thousand erase cycles of each block before it quits working. MLC can endure about a tenth of that amount. On a price per bit, SLC is much more expensive, so most of the flash you find in consumer devices is MLC.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In terms of data remanence, both the NSA and I are pretty confident that when you erase a flash block, whether it be of the NOR or NAND variety, you run very little risk of that data ever being recovered.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Solid State Drives&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;Flash memory, and in particular NAND flash, fills in interesting niche in the ecosystem of persistent digital storage devices. A read of a page of NAND flash takes on the order of tens of microseconds, making it a thousand times faster than a rotating disk drive with all the mechanical bits it has to move. The write of a page of NAND flash takes on the order of hundreds of microseconds, still pretty good. But the erase of a block of NAND flash takes on the order of thousands of microseconds, meaning milliseconds. Not so good.&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It is NAND flash that is used in SSDs. Underneath the hood, SSDs are one or more NAND flash devices on top of which is layered a very smart (or in my personal experience, sometimes not so smart) controller that tries to make the NAND flash look like a rotating disk drive. This is no small feat, since the controller has to emulate the disk by handling application reads and writes in 512 byte blocks, while physically reading and writing two or four kilobyte pages, erasing 128 kilobyte blocks, and trying its best to hide the hideous erase latency inherent in the flash device.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This real-time juggling act is the responsibility of what is generically referred to as the &lt;i&gt;flash translation layer&lt;/i&gt; (FTL). The FTL has the following sometimes contradictory goals: transparently map logical disk blocks to pages of flash; hide the write page and most especially the erase block latency; and even out erasing and writing across the entire device so that all erase blocks wear at more or less at the same rate, a process that is called &lt;i&gt;wear leveling&lt;/i&gt;. All of these goals are accomplished through an interlocking set of design and implementation strategies in the SSD controller.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;An SSD contains more flash storage capacity than the capacity of the disk drive it emulates. It uses this extra flash capacity so that it can maintain a pool of pre-erased blocks to which to write, instead of forcing the application to wait for a lengthly erase cycle to complete. This is called &lt;i&gt;over provisioning&lt;/i&gt;. SSD vendors are for the most part quiet on the amount of over provisioning, but at a recent SSD seminar I attended one vendor quoted 28% as being typical for their SSDs.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The mapping of logical disk blocks to flash pages is completely abstract. On a rotating disk, when you write to logical block 42, you are always writing to the same logical block in the same physical location on the disk platter. Okay, this is not strictly speaking true: bad block replacement management in the disk controller firmware may map logical block 42 to a replacement block somewhere else on disk, but it is always the same replacement block. But when you write to logical block 42 on an SSD you are always writing to a completely different flash page than the last time you wrote to logical block 42.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This means the controller embedded in the SSD has to maintain a very complex and dynamic mapping of logical disk blocks to flash pages, not just because disk blocks and flash pages are different sizes, but because the mapping changes every time you think you are overwriting a logical disk block with new data. Because this mapping has to persist between power cycles on the SSD, it is stored in the very same flash device in the SSD, in overhead flash pages inaccessible to you, to be re-read the next time the SSD is powered up. These overhead flash pages are themselves subject to the same wear leveling and mapping algorithms as the flash pages that hold your data.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;When you write logical disk block 42, your data is written to a flash page that was erased when the erase block of which it is a part was erased. The flash page containing the disk block formerly known as 42 is slated for eventual erasure, but it is part of an erase block that may contain flash pages that contain logical disk blocks that have not been overwritten. The SSD coalesces multiple logical disk blocks containing good data into a single flash page and updates its mapping in a process known as &lt;i&gt;garbage collection.&lt;/i&gt; This activity and the erasure of completely unused erase blocks is a more or less constant background activity on the part of the SSD.&lt;br /&gt;&lt;br /&gt;Because multiple disk blocks are stored per flash page, and multiple flash pages are stored per erase block, and because of the abstract mapping between disk blocks and flash pages, there are patterns of disk block writing behavior that appear to be uncorrelated from an application point of view, but that can result in the same erase block being erased and rewritten many times. This is called &lt;span style="font-style: italic;"&gt;write amplification&lt;/span&gt;. Because the mapping from disk blocks to flash pages is opaque to the application, this is hard to detect, and even harder to prevent.&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Flash cells can only be read so many times before the captured charge is depleted. To deal with this, the SSD controller reads flash pages containing good data and rewrites the data to a flash page in an erased block in a process called &lt;i&gt;static wear leveling&lt;/i&gt;. This is also a constant background activity on the part of the SSD.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Write latency may be further hidden by the inclusion of a RAM buffer inside the SSD. Logical disk blocks that are read may be cached in RAM, and logical disk blocks written may be buffered in RAM until an erased flash page becomes available and they can be written. The mappings used by the SSD to keep all of this straight may also be cached in RAM and written asynchronously as time permits.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;Garbage collection, static wear leveling, and cache write back are asynchronous processes inside the SSD over which you have no control, or even the ability to be aware that they are occurring, through the disk interface presented to your system by the device.&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The algorithms that implement the FTL are very complex, much more complex than the relatively simple state machine controllers implemented within the flash device itself. Indeed, inside every SSD is a powerful processor core on which the FTL runs. The SSD also implements the external electrical and command interface (e.g. IDE or SATA) that allows the SSD to connect to its host system as if it were a rotating disk drive. On at least some SSDs, the firmware that implements all of this is stored in the very same flash memory inside the SSD. The SSD controller may, in some sense, boot from itself.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;The integrity of not just your data, but of the mapping metadata, and of the SSD's own firmware, is of such critical importance to the stability of the SSD that vendors place capacitors on the SSD to power its operation in the event of a power failure, until the SSD can reach a stable recoverable state. Apparently this sometimes even works. But there is a lot of anecdotal evidence that it frequently does not. In his popular software development blog &lt;i&gt;&lt;a href="http://www.codinghorror.com/"&gt;Coding Horror&lt;/a&gt;&lt;/i&gt;, Jeff Atwood as written several articles on his own experiences with SSDs. He &lt;i&gt;loves&lt;/i&gt; them. For their &lt;i&gt;performance&lt;/i&gt;. But in the article "&lt;a href="http://www.codinghorror.com/blog/2011/05/the-hot-crazy-solid-state-drive-scale.html"&gt;The Hot/Crazy Solid State Drive Scale&lt;/a&gt;" he says:&lt;/div&gt;&lt;/div&gt;&lt;span&gt;&lt;span&gt;&lt;blockquote&gt;I feel ethically and morally obligated to let you in on a dirty little secret I've discovered in the last two years of full time SSD ownership. Solid state hard drives fail. A lot. And not just any fail. I'm talking about &lt;i&gt;catastrophic, oh-my-God-what-just-happened-to-all-my-data instant gigafail&lt;/i&gt;. It's not pretty.&lt;/blockquote&gt;&lt;/span&gt;&lt;/span&gt;&lt;div&gt;&lt;div&gt;The emphasis here is his. The comments for this article by his readership are similarly hair raising. There is a growing body of evidence that SSDs have to be treated with some care lest they be bricked, along with all your precious data. This is also in part why "Hard Power-Off Is Dead" will be a future article in my own blog.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;But their reliability isn't my primary concern for this article. How do you deal with data remanence when using SSDs? They can't be degaussed like rotating disk drives because they aren't based on magnetic media. They can't be erased like NOR and NAND flash because even though they use NAND flash as their storage medium, they don't expose the low level flash erase function through their emulated disk drive interface.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Michael Wei and his colleagues at the &lt;a href="http://cmrr.ucsd.edu/"&gt;Center for Magnetic Recording Research&lt;/a&gt; (CMRR) at &lt;a href="http://www.ucsd.edu/"&gt;U. C. San Diego&lt;/a&gt; very recently published a paper, "&lt;a href="http://www.usenix.org/events/fast11/tech/full_papers/Wei.pdf"&gt;Reliably Erasing Data from Flash-Based Solid State Drives&lt;/a&gt;", trying to answer this question. What they found was that alternative methods of declassifying a disk drive, like overwriting all of the data on the drive, where not effective. You can overwrite every logical disk block on the drive. But thanks to RAM buffering, over provisioning, and background erasure, you can power off the SSD immediately after the overwrite operation completes, crack the SSD open, remove the flash components, plug them into a flash programming tool, and recover a significant portion of the supposedly overwritten data sitting in erase blocks pending erasure. Worse, because of the complex mapping between logical disk blocks and flash pages, sequentially overwriting the entire drive may cause erase blocks to be erased more than once, eating into the erase budget of the drive and reducing its longevity.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;There is some hope. Many disk drive standards have some form of &lt;i&gt;secure erase&lt;/i&gt; command that accomplishes the same thing as overwriting a disk block or even the entire disk. Most SSDs do not implement this command. Or, as Wei et al. point out, some say they do but it doesn't actually work. But as the SSD industry shakes out, a correct implementation of secure erase may become more common. Also, some disk drive standards have defined a &lt;i&gt;trim&lt;/i&gt; command specifically in support of SSDs, where a logical disk block can be marked as no longer used without the necessity of writing over it. Few SSDs currently support this command, and as Wei et al. point out, even so this has no reliable effect on sanitizing an SSD. But again, as things shake out, an SSD controller might take all logical disk blocks being trimmed as a hint that all flash blocks used for logical disk block storage should be erased.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Until then, I find data remanence on solid state drives to be very problematic. SSDs are too new, alas, for the NSA to have an opinion, at least in the publicly available information to which I have access. I predict an industrial shredder will play a crucial role, making that expensive SSD even more expensive because it cannot be reused once it contains sensitive information. (I also question their use in mission critical applications because of questions concerning their reliability and stability, but that's a whole other soapbox.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;Flash-based file systems like JFFS2 and UBIFS used in Linux and other operating systems are FTLs implemented in software and that use raw flash devices. Although they have to deal with all the same issues as SSDs, data remanence isn't an problem because you have access to the low level erase functions on the flash device. You can simply unmount the file system and erase the flash using a standard utility program.&lt;br /&gt;&lt;br /&gt;JFFS2 (and maybe UBIFS too, although I haven't had to dig into its internals) is a log-structured file system. It writes blocks not to a hierarchical structure but instead to a kind of sequential transaction journal. The file system that the application sees is the result of the file system software reading the journal and reconstructing the hierarchical file system in memory at mount time. This kind of architecture maps pretty well to flash memory. But how this is done by the FTL inside of SSDs is vendor proprietary and specific.&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Given the growing popularity of SSDs, improving their performance, longevity, and reliability is an area of active research. At the &lt;i&gt;&lt;a href="http://storageconference.org/2011/Presentations.html"&gt;27th IEEE Symposium on Massive Storage Systems and Technologies&lt;/a&gt;&lt;/i&gt; (a.k.a. MSST 2011) conference I recently attended, there were many papers on the topic of improving FTLs or optimizing them for niche applications. Data remanence was only rarely mentioned, and then mostly by the cloud storage providers; never in the context of solid state drives.&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Sources&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;O. Al Homaidi, &lt;i&gt;&lt;a href="http://www.bth.se/fou/cuppsats.nsf/all/3bbeb4d3e1ae3ea3c12575d20053266c/$file/Master_Thesis_Complete_EX.pdf"&gt;Data Remanence: Secure Deletion of Data in SSDs&lt;/a&gt;&lt;/i&gt;, masters thesis, MCS-2009:3, Blekinge Institute of Technology, Sweden, 2009-02&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;J. Atwood, "&lt;a href="http://www.codinghorror.com/blog/2009/10/the-state-of-solid-state-hard-drives.html"&gt;The State of Solid State Hard Drives&lt;/a&gt;", &lt;i&gt;&lt;a href="http://www.codinghorror.com/"&gt;Coding Horror&lt;/a&gt;&lt;/i&gt;, 2009-10&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;J. Atwood, "&lt;a href="http://www.codinghorror.com/blog/2010/09/revisiting-solid-state-hard-drives.html"&gt;Revisiting Solid State Hard Drives&lt;/a&gt;", &lt;i&gt;&lt;a href="http://www.codinghorror.com/"&gt;Coding Horror&lt;/a&gt;&lt;/i&gt;, 2010-10&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;J. Atwood, "&lt;a href="http://www.codinghorror.com/blog/2011/05/the-hot-crazy-solid-state-drive-scale.html"&gt;The Hot/Crazy Solid State Drive Scale&lt;/a&gt;", &lt;i&gt;&lt;a href="http://www.codinghorror.com/"&gt;Coding Horror&lt;/a&gt;&lt;/i&gt;, 2011-05&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Department of Commerce NIST Computer Security Division, &lt;i&gt;&lt;a href="http://csrc.nist.gov/publications/nistpubs/800-88/NISTSP800-88_rev1.pdf"&gt;Guidelines for Media&lt;/a&gt; &lt;/i&gt;&lt;i&gt;&lt;a href="http://csrc.nist.gov/publications/nistpubs/800-88/NISTSP800-88_rev1.pdf"&gt;Sanitization&lt;/a&gt;&lt;/i&gt;, Recommendations of the National Institute of Standards and Technology, NIST Special Publication 800-88, 2006-09&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;Department of Defense, &lt;i&gt;&lt;a href="http://www.dss.mil/isp/odaa/documents/nispom2006-5220.pdf"&gt;National Industrial Security Program Operating Manual&lt;/a&gt;&lt;/i&gt; (NISPOM), DoD 5220.22-M, 2006-02-28&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Department of Energy Cyber Security Program, &lt;i&gt;&lt;a href="http://www.ornl.gov/doe/doe_oro_dmg/TMR/TMRs/DOE%20CIO%20Guidance%20CS-11.pdf"&gt;Media Clearing, Purging, and&lt;/a&gt; &lt;/i&gt;&lt;i&gt;&lt;a href="http://www.ornl.gov/doe/doe_oro_dmg/TMR/TMRs/DOE%20CIO%20Guidance%20CS-11.pdf"&gt;Destruction Guidance&lt;/a&gt;&lt;/i&gt;, DOE CIO Guidance CS-11, 2007-01&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;D. Feenberg, &lt;i&gt;&lt;a href="http://www.nber.org/sys-admin/overwritten-data-guttman.html"&gt;Can Intelligence Agencies Read Overwritten Data?&lt;/a&gt;&lt;/i&gt;, National Bureau of Economic Research, 2004-05-14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;P. Gutmann, "&lt;i&gt;&lt;a href="http://www.cs.auckland.ac.nz/%7Epgut001/pubs/secure_del.html"&gt;Secure Deletion of Data from Magnetic and Solid-State&lt;/a&gt; &lt;/i&gt;&lt;i&gt;&lt;a href="http://www.cs.auckland.ac.nz/%7Epgut001/pubs/secure_del.html"&gt;Memory&lt;/a&gt;&lt;/i&gt;", &lt;i&gt;USENIX Security Symposium Proceedings&lt;/i&gt;, 1996-07&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;P. Gutmann, &lt;i&gt;&lt;a href="http://www.usenix.org/events/sec01/full_papers/gutmann/gutmann.pdf"&gt;Data Remanence in Semiconductor Devices&lt;/a&gt;&lt;/i&gt;, IBM T.J. Watson Research Center&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;J. Handy, &lt;i&gt;&lt;a href="http://embeddedcomputingsystems.com/wp-content/uploads/2011/06/2011-05-16-Objective-Analysis-Avnet-Slides.pdf"&gt;SSDs in Enterprise, Embedded, and Client Applications&lt;/a&gt;&lt;/i&gt;, Objective Analysis, AvNet SSD Seminar, Westminster Colorado, 2011-05-17&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;G. Hughes, T. Coughlin, &lt;i&gt;&lt;a href="http://cmrr.ucsd.edu/people/Hughes/DataSanitizationTutorial.pdf"&gt;Tutorial on Disk Drive Data Sanitization&lt;/a&gt;&lt;/i&gt;, UCSD&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;M. Murugan, D. Du, "&lt;a href="http://storageconference.org/2011/Papers/Research/14.Murugan.pdf"&gt;Rejuvenator : A Static Wear Leveling  Algorithm for NAND Flash Memory with Minimized Overhead&lt;/a&gt;", &lt;i&gt;Proceedings of the 27th IEEE Symposium on Massive Storage Systems and Technologies&lt;/i&gt;, Denver Colorado, 2011-05&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;National Security Agency/Central Security Service, &lt;i&gt;&lt;a href="http://www.nsa.gov/ia/_files/government/MDG/NSA_CSS_Storage_Device_Declassification_Manual.pdf"&gt;Storage Device Declassification Manual&lt;/a&gt;&lt;/i&gt;, 9-12, (supercedes NSA/CSS Manual 130-2), 2000-11-10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;National Security Center, &lt;i&gt;&lt;a href="http://www.cerberussystems.com/INFOSEC/stds/ncsctg25.htm"&gt;A Guide to Understanding Data Remanence in Automated Information Systems&lt;/a&gt;&lt;/i&gt;, NCSC-TG-025, Library No. 5-236,082, Version-2&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;Royal Canadian Mounted Police Technical Security Branch, &lt;i&gt;&lt;a href="http://www.rcmp-grc.gc.ca/ts-st/pubs/it-ti-sec/b2-002-eng.pdf"&gt;IT Media Overwrite and Secure Erase Products&lt;/a&gt;&lt;/i&gt;, Lead Agency Publication B2-002, 2009-05&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;S. Skorobogatov, &lt;i&gt;&lt;a href="http://www.cl.cam.ac.uk/%7Esps32/DataRem_CHES2005.pdf"&gt;Data Remanence in Flash Memory Devices&lt;/a&gt;&lt;/i&gt;, University of Cambridge, Computer Laboratory, UK&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;E. Spanjer, &lt;i&gt;&lt;a href="http://www.adtron.com/pdf/Security%20Features%20WP%20-%20FINAL%20031408.pdf"&gt;Security Features for Solid State Drivers in Defense&lt;/a&gt; &lt;/i&gt;&lt;i&gt;&lt;a href="http://www.adtron.com/pdf/Security%20Features%20WP%20-%20FINAL%20031408.pdf"&gt;Applications&lt;/a&gt;&lt;/i&gt;, ADTRON, 2008-03&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;M. Wei et al., "&lt;a href="http://www.usenix.org/events/fast11/tech/full_papers/Wei.pdf"&gt;Reliably Erasing Data from Flash-Based Solid State&lt;/a&gt; &lt;a href="http://www.usenix.org/events/fast11/tech/full_papers/Wei.pdf"&gt;Drives&lt;/a&gt;", Center for Magnetic Recording and Research, U. C. San Diego, &lt;i&gt;9th USENIX Conference on File and Storage Technologies&lt;/i&gt;, 2011-02&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;Wikipedia, &lt;i&gt;&lt;a href="http://en.wikipedia.org/wiki/Data_remanence"&gt;Data remanence&lt;/a&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Wikipedia, &lt;i&gt;&lt;a href="http://en.wikipedia.org/wiki/Flash_memory"&gt;Flash memory&lt;/a&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;C. Wright, D. Kleiman, S. Sundhar R. S., &lt;i&gt;&lt;a href="http://www.vidarholen.net/%7Evidar/overwriting_hard_drive_data.pdf"&gt;Overwriting Hard Drive&lt;/a&gt; &lt;/i&gt;&lt;i&gt;&lt;a href="http://www.vidarholen.net/%7Evidar/overwriting_hard_drive_data.pdf"&gt;Data: The Great Wiping Controversy&lt;/a&gt;&lt;/i&gt;, Springer-Verlang, 2008&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28344720-2021018864270171474?l=coverclock.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://coverclock.blogspot.com/feeds/2021018864270171474/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28344720&amp;postID=2021018864270171474' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/2021018864270171474'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/2021018864270171474'/><link rel='alternate' type='text/html' href='http://coverclock.blogspot.com/2011/06/data-remanence-and-solid-state-disks.html' title='Data Remanence and Solid State Drives'/><author><name>Chip Overclock</name><uri>http://www.blogger.com/profile/11195242013008369733</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-1xNiFqWVjh8/TWQ1ru5Z6KI/AAAAAAAAABw/kMJyhvluNMI/s220/Chip%2BOverclock%2BAvatar%2B2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28344720.post-5137299507385030179</id><published>2011-06-13T15:18:00.008-06:00</published><updated>2011-06-13T17:49:25.135-06:00</updated><title type='text'>Android FroYo on the BeagleBoard xM Rev C</title><content type='html'>&lt;div&gt;There's a lot to like about the &lt;a href="http://beagleboard.org/hardware-xM"&gt;BeagleBoard xM&lt;/a&gt; compared to the BeagleBoard C4 I had been using for &lt;a href="http://www.diag.com/navigation/downloads/Contraption.html"&gt;Contraption&lt;/a&gt;, my project to broker peace between the Android and GNU peoples. The xM has twice as much RAM: half a gigabyte. It has a built-in USB hub and four USB ports, eliminating the need for a separate USB hub, simplifying the attachment of a USB keyboard and mouse. It has a built-in RJ45 Ethernet port, eliminating the need for a USB Ethernet adaptor or, as I used, an expansion board like the Zippy2. And best yet, the price of the tiny xM board has come down to be the same as what I originally paid for the C4 board. This makes the xM a great platform for Contraption and for the kinds of things for which I use it.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;At the time I chose to move off the C4, the currently shipping xM was the revision C board. The pre-built binaries available in the &lt;a href="http://code.google.com/p/rowboat/"&gt;Rowboat&lt;/a&gt; &lt;a href="http://software-dl.ti.com/dsps/dsps_public_sw/sdo_tii/TI_Android_DevKit/02_02_00/index_FDS.html"&gt;validation port&lt;/a&gt; of &lt;a href="http://developer.android.com/sdk/android-2.2.html"&gt;Android FroYo&lt;/a&gt; to the xM did not support the rev C. In fact, neither the X-Load stage one loader, nor the U-Boot boot loader, nor the 2.6.32 Linux kernel with Android modifications, recognized the rev C board. Because the xM differed significantly in many ways from prior BeagleBoards (most significantly, in how the USB components were configured and powered), this made using the pre-built binaries from the developer's kit a non-starter.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Fortunately, I poked around and found Robert C. Nelson's &lt;a href="https://github.com/RobertCNelson/linux-2.6/commit/ebe1e26476768b8edde0607433e564ffd4b0e903"&gt;patch&lt;/a&gt; to adapt the kernel's board support package (BSP) for the BeagleBoard to the rev C hardware. (&lt;i&gt;Thank You, Robert!&lt;/i&gt;) And while I didn't find similar patches for X-Load or U-Boot, it was a simple thing to make the required changes to those packages as well using Robert's changes as a model. The patch files I used are now all part of the latest tarball available on the &lt;a href="http://www.diag.com/navigation/downloads/Contraption.html"&gt;Contraption&lt;/a&gt; web page. As I've done in the past, I rebuilt all of the Android software and the root file system from scratch, because the graphics engine on the xM Rev C had to be built a little differently as well. This change has been incorporated into the make file.&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here's the BeagleBoard xM Rev C. Moving to the xM really cleaned up my workbench by eliminating a lot of cables and clutter. (You can click on any of the images below to open larger sizes.)&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/5830370756/" title="BeagleBoard xM Rev C by John Sloan, on Flickr"&gt;&lt;img src="http://farm6.static.flickr.com/5270/5830370756_20e35f3aa8.jpg" width="500" height="281" alt="BeagleBoard xM Rev C" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here you can see the BeagleBoard xM rev C running Android FroYo. My desktop on the left is displaying an SSH window to Android (black on white) and a console window to the serial port on the xM board (green on black). The LCD monitor on the right is hooked to the xM and is displaying the Android browser.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/5830371176/" title="Android on BeagleBoard xM Rev C by John Sloan, on Flickr"&gt;&lt;img src="http://farm3.static.flickr.com/2535/5830371176_5bfc20dd5f.jpg" width="500" height="281" alt="Android on BeagleBoard xM Rev C" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here's a photograph of the xM LCD display.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/5830371620/" title="Android Browser on BeagleBoard xM Rev C by John Sloan, on Flickr"&gt;&lt;img src="http://farm6.static.flickr.com/5304/5830371620_e7e5c422b3.jpg" width="500" height="281" alt="Android Browser on BeagleBoard xM Rev C" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here's a screen snapshot of the serial console. If you look closely you can see one of the things I did was change the root password using the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;/bin/busybox passwd&lt;/span&gt; applet. SSH doesn't seem happy with an empty root password.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/5830370030/" title="BeagleBoard xM Rev C Serial Console by John Sloan, on Flickr"&gt;&lt;img src="http://farm4.static.flickr.com/3192/5830370030_a84ac3a0f6.jpg" width="288" height="500" alt="BeagleBoard xM Rev C Serial Console" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;After I SSHed into Android from my desktop and got a &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;bash&lt;/span&gt; prompt, I ran the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;top&lt;/span&gt; command just to see who was doing what.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/5829821043/" title="SSHed into Android using Contraption by John Sloan, on Flickr"&gt;&lt;img src="http://farm4.static.flickr.com/3141/5829821043_6bcd8e097e.jpg" width="195" height="500" alt="SSHed into Android using Contraption" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I'd like to move to the port of &lt;a href="http://software-dl.ti.com/dsps/dsps_public_sw/sdo_tii/TI_Android_DevKit/TI_Android_GingerBread_2_3_DevKit_1_0/index_FDS.html"&gt;Android Gingerbread&lt;/a&gt;. But if I'm interpreting what I'm reading correctly (and please, someone, tell me I'm not), I have to run the 64-bit version of Java to build the Android software, and to do that I have to migrate to the 64-bit version of Linux on my build server. That's a pretty big leap. Might be a while.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28344720-5137299507385030179?l=coverclock.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://coverclock.blogspot.com/feeds/5137299507385030179/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28344720&amp;postID=5137299507385030179' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/5137299507385030179'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/5137299507385030179'/><link rel='alternate' type='text/html' href='http://coverclock.blogspot.com/2011/06/android-froyo-on-beagleboard-xm-rev-c.html' title='Android FroYo on the BeagleBoard xM Rev C'/><author><name>Chip Overclock</name><uri>http://www.blogger.com/profile/11195242013008369733</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-1xNiFqWVjh8/TWQ1ru5Z6KI/AAAAAAAAABw/kMJyhvluNMI/s220/Chip%2BOverclock%2BAvatar%2B2.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm6.static.flickr.com/5270/5830370756_20e35f3aa8_t.jpg' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28344720.post-1115888876605362565</id><published>2011-05-30T11:09:00.031-06:00</published><updated>2011-06-14T08:55:29.495-06:00</updated><title type='text'>MSST 2011</title><content type='html'>Last week I attended the &lt;a href="http://storageconference.org/"&gt;27th IEEE Symposium on Massive Storage Systems and Technologies&lt;/a&gt;, a.k.a. MSST 2011. A couple of decades ago, when large scale storage was my field, I attended this conference annually. This year I attended it because it was a twenty-minute drive from the Palatial Overclock Estate (what the media insists on calling the Heavily-Armed Overclock Compound) and because it was being held at the&lt;a href="http://www.brownpalace.com/"&gt; Brown Palace Hotel&lt;/a&gt;, a stunning Victorian-era historic fixture in downtown Denver Colorado. It was also a good excuse to catch up on the state of the art.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Back when I was a regular at this conference, large meant terabytes, which is kind of remarkable considering today you can trivially buy a terabyte disk drive at your local big box store. Nowadays, large means exabytes; a single tape cartridge can hold several terabytes, and a single robotic tape library can hold thousands of tape cartridges.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Applications of storage on the exabyte scale falls into a variety of categories, such as long term archiving of data from observations and experiments (e.g. weather observations going back decades, satellite imagery, results from experiments with particle colliders, DNA sequencing of individuals); short or long term storage of output of applications running on high performance computers; and cloud storage much of which is driven by the consumer space. All of these domains were represented at this international conference, with speakers and attendees from national laboratories and agencies, storage vendors, cloud users and providers including Yahoo!, and academic and corporate researchers doing original work in this area.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here are some of the notes I wrote down while attending this week-long conference. All original ideas are those of the speakers; all interpretations, and misinterpretations, are mine. And don't be surprised if some of these contradict one another. The notes are in chronological order. You can find a complete list of the papers, speakers, and panels from whence they came &lt;a href="http://storageconference.org/2011/Presentations.html"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Geoff Arnold/Yahoo!: Cloud storage: trends and questions&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;10x Effect:&lt;/i&gt; refers to the observation that scaling your application by a factor of ten requires that you to re-architect it.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Trend: deployment of components used in mass storage systems from enterprise-grade devices to consumer-grade devices. The consumer-grade devices may be less reliable, but you have to accommodate failures even in enterprise-grade devices anyway, and the consumer-grade devices offer better price performance.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;Fail-in-place: &lt;/i&gt;strategy where when something fails, you don't replace it, you just power it off, and let the system work around it. It will be replaced anyway by the next technology refresh, which happen so often that replacing a failed component with the same technology isn't worth the cost.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://en.wikipedia.org/wiki/RAID"&gt;RAID&lt;/a&gt; (Redundant Array of Inexpensive Disks) is dead. Instead: &lt;a href="http://en.wikipedia.org/wiki/JBOD#JBOD"&gt;JBOD&lt;/a&gt; (Just a Bunch Of Disks, or Just a Box Of Drives), with geographic replication for reliability. Part of the problem with RAID is that they don't scale: they appear to be one I/O device with one serialized command queue, where as commands to JBODs can be more parallelized.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://en.wikipedia.org/wiki/Storage_area_network"&gt;SAN&lt;/a&gt; (Storage Area Network, not to be confused with Network Attached Storage) is dead. Instead: converged networks using a single interconnect fabric. (But there were lots of folks proposing SAN architectures, too.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;Immutable objects&lt;/i&gt;: the concept where once an object is stored, it is never modified, except perhaps to be deleted. This vastly simplifies the storage system design. (This is very similar to the idea of &lt;i&gt;&lt;a href="http://en.wikipedia.org/wiki/Assignment_%28computer_science%29#Single_assignment"&gt;single-assignment&lt;/a&gt;&lt;/i&gt; in programming languages, where variables can never be changed once assigned. As bizarre as this sounds, it's quite workable. I implemented a single-assignment programming language as part of my master's thesis, and another graduate student implemented a Prolog interpreter in my language.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://en.wikipedia.org/wiki/POSIX"&gt;POSIX&lt;/a&gt; file semantics are dead, because they don't scale. The big problems are file locking and file modification. Instead: the future scalable storage interface will be &lt;a href="http://en.wikipedia.org/wiki/REST"&gt;REST&lt;/a&gt;ful, implementing HTTP-like operations limited to GET, PUT, POST, and DELETE and operate on objects instead of files and blocks.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Trend: movement from synchronous to asynchronous operations, because the former don't scale. One of the reasons POSIX file semantics are dead is we have to give up the API that has "an implicit guarantee of transactional consistency". Eventual consistency scales.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Trend: replacing MTBF (Mean Time Between Failures) with MTTR (Mean Time To Recover). The former doesn't scale. You have to design your system around the assumption that devices will fail, and optimize your ability to recover from those failures. (The routing architecture of the Internet Protocol was based on this concept, and the telecoms have been making this assumption for decades, for exactly the same reasons. I have also been attending an exascale computing conference, sponsored by the U.S. Department of Energy, for the past couple of years. To scale up to an exascale supercomputer with commodity memory chips, the MTBF calculation suggests that such a system will suffer a RAM chip failure every few minutes.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Trend: replacing a "predictable business model" with one of "chaotic innovation". (I wish the speaker had said more about that. But I like the premise. It fits in well with my own reading on &lt;a href="http://www.au.af.mil/au/awc/awcgate/milreview/skelton.pdf"&gt;asymmetric warfare&lt;/a&gt; and &lt;a href="http://www.chipoverclock.com/2009/12/product-development-as-warfighting.html"&gt;John Boyd&lt;/a&gt;'s OODA loops.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Trend: replacing human operators with automation and self-service. The former doesn't scale. Sun Microsystems was quoted as observing that "the largest source of failures in the data center was humans opening the door".&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Cloud computing requires &lt;i&gt;operational refactoring&lt;/i&gt;: outsourcing lower portions of the application stack, taking advantage of economies of scale, implementing service level agreements, and leverage specialization on the part of your provider.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Virtualization is a nightmare for security. Hypervisor vulnerabilities are the major concern. No matter how bullet proof your application stack is, once you run it in a virtual machine, all bets are off. VMs make the cloud providers very very nervous. (This was a recurring theme.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;People get nervous about cloud computing, yet there are centuries of precedence in outsourcing critical infrastructure. You put all your money in a bank, and that's your &lt;i&gt;money&lt;/i&gt;, for pete's sake. Not to mention hospitals, delivery services, lawyers, etc.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;Stovepiped:&lt;/i&gt; when your application stack is vertically integrated. This is a problem when moving to cloud architectures since doing so means migrating the lower portions of the stack into the cloud. To gain efficiencies of scale requires cloud vendors to provide basically the same generic services to everyone. (That was a new term for me.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The recent failure of Amazon.com's storage system was not in their S3 cloud computing service, which has RESTful semantics, but in their Elastic Block Storage (EBS), which has POSIX semantics. And even then, the failure fell within their Service Level Agreement. Cloud storage architects point to this as an example of why POSIX semantics don't scale.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;On moving part of your application stack into the cloud: "Until a new airliner crashes, you have have no idea what will happen when that airliner crashes".&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Trend: cloud providers have tended to optimize their stacks for "north-south" traffic (vertical within the stack) but are seeing a lot of growth in "east-west" traffic (horizontally between applications within the stack).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;We need to automate systems originally designed for human time scales. An example of this is the internet's Domain Name System (DNS), which was designed to be updated by a human using a command line interface, not by automated systems in clouds registering and deleting many domains per second.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Joshua McKenty/Piston Cloud Computing: Openstack: cloud's big tent&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Trend: moving computing closer to or even into the storage environment. This becomes more important as the datasets get larger. (This was reiterated time and again by many speakers.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;Tombstoned&lt;/i&gt;: destined or marked for deletion.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Patrick Quaid/Yahoo!: Lessons learned from a global DB&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Trend: the cloud stack becomes (from the top down): SaaS (Software as a Service), KaaS (Knowledge as a Service), PaaS (Platform as a Service), IaaS (Infrastructure as a Service).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Trend: in social networking, the movement from "me-view" to "we-view". (I interpreted this to mean applications leveraging crowd sourcing.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Cloud providers have found that implementing big-market infrastructures is wasted in developing markets. Once size does not fit all.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;You can't retrofit consistency into your architecture.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;Data remanence&lt;/i&gt;: how do you guarantee the data is deleted? In the domains like defense, finance, and medicine, there are legal requirements to ensure that deleted data cannot be recovered (particularly by the wrong parties). This is especially troublesome given the trend of geographic replication. You could encrypt the data and later delete the keys, but there is no guarantee that the keys themselves are not recoverable, and also no legal precedent that such a strategy is adequate. On the flip side, there are opposing legal requirements to ensure that some data flows can be wiretapped.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Scale: billions of records, ~600,000 users, one million reads per second, ~500,000 writes per second.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Sean Roberts/Yahoo!: Implementation problems and design principles&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;Black swan events&lt;/i&gt;: singularities like the death of Michael Jackson, the Royal Wedding.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;No-ops are the enemy.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Chris King/Linkedin: Storage infrastructure design and management at scale&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Google is moving from consumer-grade storage devices to enterprise-grade devices, because the latter are cheaper in the long run. Even if the enterprise-grade device lasts just a little longer before it fails, the savings in labor costs to have someone replace the device makes up for it.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://en.wikipedia.org/wiki/Conway%27s_Law"&gt;&lt;i&gt;Conway's Law&lt;/i&gt;&lt;/a&gt;: a system's architecture will recapitulate the bureaucracy that created it. This is a very old (circa 1968) assertion, but cloud providers have observed it in their domain.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Geoff Arnold/Yahoo!: Private clouds&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Forget about the &lt;i&gt;&lt;a href="http://en.wikipedia.org/wiki/Long_Tail"&gt;long tail&lt;/a&gt;;&lt;/i&gt; the problems are with the &lt;i&gt;big head&lt;/i&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In a slowly changing environment, it's easy to assume some things are constant, when they in fact aren't. Result: correlators don't correlate, invariants aren't invariant. Example: IP addresses. (I've been bit by this one too. I used to use MAC addresses as a unique system identifier, until I started seeing systems in which users routinely reprogrammed their MAC addresses.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;On demand&lt;/i&gt; assumes that each individual customer is small compared to the entire pool of customers, and that there is no correlation of behavior among customers. These assumptions are frequently wrong.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A sufficiently large data replication process looks like a distributed denial of service (DDoS) attack.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Joshua McKenty/Piston Cloud Computing: Security&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;a href="http://en.wikipedia.org/wiki/Blue_Pill_%28malware%29"&gt;Blue Pill Attack&lt;/a&gt;&lt;/i&gt;: when the virtual machine attacks the underlying real machine. This is the opposite of the usual concern. (From the movie &lt;i&gt;&lt;a href="http://www.imdb.com/title/tt0133093/"&gt;The Matrix&lt;/a&gt;, &lt;/i&gt;this is specifically when a real machine is compromised by it having been unwittingly virtualized, hence the attacker has wrested control of the real machine from the host operating system.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Michael Ernst/Brookhaven National Laboratory: Experience with 30PB of data from the LHC&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Storing petabytes of data is easy compared to moving petabytes of data to where it is needed. (This was a recurring theme, driving the rethinking of architecture.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Ron Oldfield/Sandia National Laboratory: Addressing scalable IO challenges for exascale&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Electrical power is the largest hurdle to exascale. At current efficiencies, an exascale system will require two gigawatts of power. Data movement is the largest user of power. (At the last exascale conference I attended someone mentioned that the Chinese have committed to building their supercomputer centers with a nuclear power plant. Everyone wonders how we'll compete with that.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Applications use the storage system as a communications channel.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Trend: it may be more economical to recompute rather than to store. (This is theme I see recurring at all scales, from massive storage systems to variables in a single application.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;More than eighty percent of all I/O is done for reasons of resilience.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Applications today are not designed to survive failures. The larger the application, the higher the probability of failure. This is the reason for &lt;i&gt;checkpoints&lt;/i&gt; (where the entire application state is periodically dumped to storage). As applications grow larger, and their data requirements bigger, checkpoints are increasingly expensive to generate and to store. (This is just another take on the theme that you have to expect failures and be able to recover from them.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Asynchronous I/O still buries the network, and jitter becomes a real issue. But, storing data persistently at each intermediate stage is actually very resilient. (This was said in the context of Big Science, such as the Large Hadron Collider.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Dave Fellinger/Data Direct Networks: Simplifying collaboration in the cloud&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;IDC predicts that by 2020 the world will have thirty-five zettabytes of digital storage.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;There is no bandwidth faster than a 747 filled with tapes. (This is a variation on the idea that Fedex operates the highest bandwidth network in the world by virtue of overnight delivery of tapes.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Alan Hall/NOAA: National Climate Data Center's plan for reprocessing large datasets&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;"80% of the world's data is on tape." (The speaker was quoting the CTO of a manufacturer of tape libraries.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Trend: archiving the software applications along with the data that it produced or processed. The software effectively becomes part of the metadata, because it is the only formal description of the data. The application, the operating system on which is runs, and the data would all be deployed to a VM from the mass storage system.&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Harry Hulen/IBM: Operational concepts and methods for using RAIT in high availability tape archives&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Rule of thumb: it takes about one full time equivalent (FTE) of staff to manage every five petabytes of tape archive.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Todd Abrahamson/Imation: Tape media reliability&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The black box flight recorder from the Columbia space shuttle disaster hit a tree in Texas at an estimated Mach 18. It took weeks to be found, during which time water got into the device. The data on its magnetic tape were still recoverable. (The speaker was the engineer that recovered and interpreted this data.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Rule of thumb: current magnetic tape technologies offers about a thirty year longevity when stored at seventy degrees Fahrenheit and thirty percent relative humidity.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Current hard disk drive controller boards are tuned to the specific spindle with which they are manufactured. This makes it difficult to recover a disk whose controller has been damaged. You can't just replace the controller with one from another disk of the same model.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Panel Discussion&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Trend: embed flash memory in tape cartridges so as to store metadata in the cartridge itself. (Cartridges today use an RFID chip to carry identity information.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Economics drive tape technology migration, not reliability or longevity.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Latency means uncertainty.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The National Institute of Standards and Technology (NIST, formerly the U.S. National Bureau of Standards) defines the required archive duration for medical records as "the life of the Republic plus one hundred years".&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Dimitry Ozerov/DESY: Data preservation in high energy physics&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Both theory and common sense evolve over time. This requires that we periodically revisit legacy data.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Ian Fisk/Fermi National Accelerator Laboratory: Evolving WLCG data access strategy and storage management strategies&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;There is a 10&lt;sup&gt;8&lt;/sup&gt; magnitude difference in data popularity between the most and least popular datasets. (This strikes me as another example of the &lt;i&gt;&lt;a href="http://en.wikipedia.org/wiki/Long_Tail"&gt;long tail&lt;/a&gt;&lt;/i&gt; phenomena.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Like events tend to aggregate (be clumped together) in a dataset due to buffering, resulting in jitter in the data. This is an issue with the data is reprocessed for analysis since it is not stored in strictly the order that it occurred in the experiment. (This was said in the context of Big Science, like the Large Hadron Collider, where the raw datasets generated in real-time from a single experiment are petabytes in size.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Panel Discussion&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Funding agencies are no longer willing to pay for peak capacity. Sharing resources is necessary.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Amazon.com's Amazon Web Service (AWS) established not only that infrastructure has value, but what that value was, and it demonstrated that customers would be willing to pay for infrastructure.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Peter Braam/Xyratex: Bridging the peta- to exa-scale I/O gap&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Rule of thumb for exascale storage requirements: memory capacity times thirty equals scratch space capacity, times three equals archive storage capacity per month. (I believe this was said in the context of Big Science.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Metrics for an exascale system: 10&lt;sup&gt;8&lt;/sup&gt; CPU cores, 10 gigaFLOPS per core, 1 gigabyte of RAM per core, 5x10&lt;sup&gt;3&lt;/sup&gt; cores per node, 5 terabytes RAM per node, 50 teraFLOPS per node, 15 gigabytes/second I/O per node, 20x10&lt;sup&gt;3&lt;/sup&gt; nodes per cluster, 100 petabytes RAM per cluster, 300 terabytes/second I/O per cluster, file system capacity greater than 1 exabyte.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Architectures of exascale systems will have to be heterogeneous.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Dan Duffy/Goddard Space Flight Center: Alternative architectures for mass storage&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;NCCS, the smaller of NASA's two data centers, has enough storage for an iPod playlist 34,000 &lt;i&gt;years&lt;/i&gt; long.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Mary Baker/HP Labs: Preserving bread crumbs&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;"All problems in computer science can be solved by another layer of indirection. Except for the problem of too many layers of indirection." -- David Wheeler (1927-2004) (Cited as the first person to be awarded a Ph.D. in Computer Science.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The Japanese have developed a unique strategy for preserving their monuments: they periodically rebuild them from scratch. An example of this is the &lt;a href="http://www.reseau-asie.com/edito-en/reseau-asie-s-editorial/preserve-restore-rebuild-renovate-the-archipelagos-of-mystical-thought-in-japan-and-europe-by-jean-s/"&gt;&lt;i&gt;Sanctuary of Ise&lt;/i&gt;&lt;/a&gt;, in which the temple is rebuilt every twenty years on an adjacent plot using the prior temple as a model. This is also the strategy for long term data preservation: continuous renewal by coping to new media using new technology and verifying against the prior copy. (I've heard this strategy referred to as &lt;i&gt;George Washington's Axe&lt;/i&gt;: "This is George Washington's axe. The handle rotted away so we replaced it. Then the head rusted away so we replaced that too.")&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;How do we communicate the value of data archives to future generations?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;MTDL&lt;/i&gt;: Mean Time to Data Loss.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Phil Carns/Argonne National Lab: Understanding and improving computational science storage access through continuous characterization&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;MiB&lt;/i&gt;: a Mebibyte is 2&lt;sup&gt;20&lt;/sup&gt; or 1,1048,576 bytes.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;MB&lt;/i&gt;: a Megabyte is 10&lt;sup&gt;5&lt;/sup&gt; or 1,000,000 bytes.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Raja Appusuwamy/Free University of Amsterdam: Flexible, modular file system virtualization in Loris&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Trend: designing a storage stack in a manner similar to a network stack. Layers: virtual file system, naming, cache, logical, physical, disk device driver, hardware.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Yangwook Kang/U. C. Santa Cruz: Object-based SCM: an efficient interface for storage class memories&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;SCM&lt;/i&gt;: storage-class memory e.g. flash memory and related memory-based persistent storage devices like solid state disk (SSD).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Yulai Xie/U. C. Santa Cruz: Design and evaluation of Oasis: an active storage framework based on T10 OSD standard&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Trend: moving computation to the data via mechanisms like running workload on the storage servers, instead of moving the data to the compute servers. At least one site is doing this using Java applications with JVMs running on the storage system, or by running complete packages of application plus operating system on a VM on the storage system.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Panel Discussion&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Blocks are dead. Instead: object stores. (This is another take on the death of POSIX file semantics, and was a common theme.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Humans are bad at remembering why they saved something. We have to automate the capture of the provenance of the data being saved.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Disks will be with us forever. Probably tape too. We can't build enough chip fabrication facilities to make enough solid state storage for all the world's data requirements.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Fewer and fewer students are studying the "systems" area. (This has been my experience as well, and is principally why my career has lasted as long as it has.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Academic research should be like science fiction: it should ask &lt;i&gt;what if&lt;/i&gt; questions, and expect a high rate of failure. Lots of useful collateral may be produced by even a failed line of research.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Academia should have been doing research on flash memories way earlier; by the time it did, flash was already everywhere. (This was said in response to a number of research papers given on alternative flash translation layers.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Storage systems are hard. Distributed systems are hard. Distributed storage systems are really hard.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In three to five years there will be no spinning media in any consumer device. (This was very controversial, but I'm not sure I disagree with it. Part of the reason is that cloud storage will eliminate much of the requirement for big storage in consumer devices.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Startups can't fund long horizon research and development. Only large companies can do that, thanks to their existing revenue stream. (As a former employee of Bell Labs, I don't think this bodes well for long horizon R&amp;amp;D.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;There are too many people designing new systems without understanding what existing systems do and how they work. (In fact, a couple of the speakers on cloud computing remarked that they had come to realize they were on trails previously broken by the telecommunications industry who are used to developing very large scalable geographically distributed networked systems that had to recover automatically from frequent failures.  Having spent time at Bell Labs working on such systems, this had occurred to me as well.)&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;BHAG&lt;/i&gt;: Big Hairy Audacious Goal. BHAGs are what the Defense Advanced Research Projects Agency (DARPA) and the National Science Foundation (NSF) should be funding. They are currently way too oriented towards near future applications and incremental improvements.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The reliability problem extends to people.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Specific workloads matter. I/Os per second (IOPS) are crap as a useful measure. (This same sentiment has been expressed by the high performance computing community regarding supercoputer vendors quoting GFLOPS of performance for their wares. HPC pundit Bill Buzbee was exactly right in saying "Any claims of performance by a vendor should be considered a guarantee that their product cannot exceed them.")&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Trend: &lt;span style="font-style: italic;"&gt;The Rise of the Stupid Storage Device&lt;/span&gt; (this is actually my term, not the speaker's), moving the storage management intelligence further up in the application stack. (This is a more general statement of the comment above about RAID, where you get better performance by moving disk management outside of the storage device. Compare with: &lt;a href="http://www.isen.com/stupid.html"&gt;&lt;i&gt;The Rise of the Stupid Network&lt;/i&gt;&lt;/a&gt;.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Negative results are still results. Disproving your hypothesis does not mean you failed. More is learned by failing gloriously in an ambitious endeavor than by succeeding in a modest incremental goal.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Wes Felter/IBM: Reliability-aware energy management for hybrid storage system&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;Energy-Proportional&lt;/i&gt;: Google's term for energy use that is proportional to a level of activity. Hard disk drives are &lt;i&gt;not&lt;/i&gt; energy-proportional. spinning the disk takes energy, whether I/O is being done or not. Spinning a disk up from idle takes a &lt;i&gt;lot&lt;/i&gt; of energy. You have to determine the break even point to know when or if to spin a disk down. Reliability is adversely affected by spinning a disk up. (I've also had some colleagues that had to deal with disk drives that &lt;i&gt;had&lt;/i&gt; to be periodically spun down; otherwise, cavitation would cause bubbles to form in the working fluid of the drive leading to a disk crash. I've always assumed my colleagues were talking about the fluid bearings in the drive, but I might be wrong.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Dean Hildebrand/IBM: ZoneFS: Stripe remodeling in cloud data centers&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The &lt;a href="http://en.wikipedia.org/wiki/MapReduce"&gt;&lt;i&gt;MapReduce&lt;/i&gt;&lt;/a&gt; design pattern is a form of moving the computation to the data, since at least the map portion of the computation can be applied to local data.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Muthukumar Murugan/U. Minnesota: Rejuvenator: a static wear leveling algorithm for NAND flash memory with minimzed overhead&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Rule of thumb: a read of a page of flash takes on the order of 10&lt;sup&gt;1&lt;/sup&gt; microseconds (from another source: this is a random read, whereas a sequential read takes on the order of 10&lt;sup&gt;-2&lt;/sup&gt; microseconds); a write of a page of flash 10&lt;sup&gt;2&lt;/sup&gt; microseconds; an erase of a block of flash 10&lt;sup&gt;3&lt;/sup&gt; microseconds. Pages are typically two or four kilobytes; blocks are typically 128 kilobytes. Single-level cell (SLC) flash can endure about 10&lt;sup&gt;5&lt;/sup&gt; erase cycles per block; multi-level cell (MLC) flash about 10&lt;sup&gt;4&lt;/sup&gt; erase cycles.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28344720-1115888876605362565?l=coverclock.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://coverclock.blogspot.com/feeds/1115888876605362565/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28344720&amp;postID=1115888876605362565' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/1115888876605362565'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/1115888876605362565'/><link rel='alternate' type='text/html' href='http://coverclock.blogspot.com/2011/05/notes-on-msst-2011.html' title='MSST 2011'/><author><name>Chip Overclock</name><uri>http://www.blogger.com/profile/11195242013008369733</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-1xNiFqWVjh8/TWQ1ru5Z6KI/AAAAAAAAABw/kMJyhvluNMI/s220/Chip%2BOverclock%2BAvatar%2B2.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28344720.post-8276125509026077632</id><published>2011-05-02T09:22:00.010-06:00</published><updated>2011-05-03T07:59:39.500-06:00</updated><title type='text'>Negative Space</title><content type='html'>MSNBC and many other news outlets &lt;a href="http://www.msnbc.msn.com/id/42853221/ns/world_news-death_of_bin_laden/"&gt;reported&lt;/a&gt; that one of the clues that led U.S. operatives to Osama Bin Laden's compound in a developed suburb of Abbottabad Pakistan just forty miles from the capital of that country was its &lt;i&gt;lack&lt;/i&gt; of technology.&lt;div&gt;&lt;blockquote&gt;And unusual for a compound valued at more than $1 million: It had no telephone or Internet service.&lt;/blockquote&gt;&lt;/div&gt;&lt;div&gt;Unless you have been living in a cave -- which, apparently, Bin Laden was not -- you are already aware of the concept of &lt;i&gt;&lt;a href="http://en.wikipedia.org/wiki/Negative_space"&gt;negative space&lt;/a&gt;&lt;/i&gt;. The Wikipedia article on this topic has an example of the image that introduced most of us to the idea.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/5680725145/" title="Negative Space by John Sloan, on Flickr"&gt;&lt;img src="http://farm6.static.flickr.com/5022/5680725145_83f12842d0.jpg" alt="Negative Space" width="313" height="480" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Is the black and white image a vase, or opposing profiles of two men? This is when many children come to understand that what &lt;i&gt;isn't&lt;/i&gt; there is just as important as what &lt;i&gt;is&lt;/i&gt; there.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This breaking news found me smack in the middle of reading &lt;i&gt;&lt;a href="http://www.amazon.com/Information-History-Theory-Flood/dp/0375423729"&gt;The Information: A History, A Theory, A Flood&lt;/a&gt;,&lt;/i&gt; a book on the history of &lt;a href="http://en.wikipedia.org/wiki/Information_theory"&gt;information theory&lt;/a&gt; by science writer&lt;a href="http://www.amazon.com/James-Gleick/e/B000AQ3M1I"&gt; James Gleick&lt;/a&gt;. For me, it is a slow but rewarding read. Slow mostly because it's the kind of book that causes me to stare off in to space minutes at a time waiting for my brain to catch up making connections with existing material tucked away in its dark recesses. Material which for the most part hasn't been accessed since graduate school or my tenure at Bell Labs. The book is full of anecdotes and details about the lives of scientists, mathematicians, and engineers whose work ultimately informed my entire professional career and that of most of my colleagues: Turing, Gödel, Von Neumann, Nyquist, Shannon, and others.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Gleick's description of coding techniques, particularly that of &lt;a href="http://en.wikipedia.org/wiki/Morse_code"&gt;Morse code&lt;/a&gt;, and of Shannon's and other's research into the redundancy of spoken and written natural languages, made me ponder how negative space, like the different durations of pauses between syllables, words, and sentences, was as or more  important than the symbols that constitute the positive space in messages. Negative space is frequently crucial for correctly parsing the message, while much of the positive space is redundant because the symbols can be accurately predicted.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Gleick's example is the classic&lt;/div&gt;&lt;div&gt;&lt;blockquote&gt;f u cn rd ths&lt;/blockquote&gt;&lt;/div&gt;&lt;div&gt;which nearly every English speaker can. But (and this is my example, not Gleick's) remove the negative space and&lt;/div&gt;&lt;div&gt;&lt;blockquote&gt;fucnrdths&lt;/blockquote&gt;&lt;/div&gt;&lt;div&gt;becomes much more cryptic. The negative space actually carries more information content than the redundant symbols in the positive space.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;But more to the point of Bin Laden, although nearly every English speaker can read that first sentence with the redundant symbols removed, everyone also recognizes it as malformed. It violates the principle of camouflage: it fails to blend in with its environment.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;What Bin Laden might have realized had he survived his encounter with U.S. operatives is that this principle now applies to technology as well, and most specifically to signals intelligence. If you want to go unnoticed, you have to blend in with your surrounding telecommunications environment. This means generating signals that have about the same level of traffic as your surround, about the same signal to noise ratio, and about the same information content. Otherwise, the negative space you have created in your ambient communications environment makes you stand out.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I suppose in the twenty-first century this would mean lots of outgoing Facebook updates and Twitter tweets whose topics are trivial and banal, and lots of incoming spam from Nigerian princes. I have no idea how to realistically fake those sorts of things, but I'm now convinced that keeping a low profile does not mean keeping no profile. You don't wear black to camouflage yourself in the woods; you wear something that looks like woods.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Just as &lt;a href="http://coverclock.blogspot.com/2008/11/negative-results-are-still-results.html"&gt;negative results are still results&lt;/a&gt;, negative space still imparts information. Some things become obvious by their omission.&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28344720-8276125509026077632?l=coverclock.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://coverclock.blogspot.com/feeds/8276125509026077632/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28344720&amp;postID=8276125509026077632' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/8276125509026077632'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/8276125509026077632'/><link rel='alternate' type='text/html' href='http://coverclock.blogspot.com/2011/05/negative-space.html' title='Negative Space'/><author><name>Chip Overclock</name><uri>http://www.blogger.com/profile/11195242013008369733</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-1xNiFqWVjh8/TWQ1ru5Z6KI/AAAAAAAAABw/kMJyhvluNMI/s220/Chip%2BOverclock%2BAvatar%2B2.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm6.static.flickr.com/5022/5680725145_83f12842d0_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28344720.post-3744188949174120974</id><published>2011-04-24T12:42:00.011-06:00</published><updated>2011-04-25T08:21:02.525-06:00</updated><title type='text'>Sturgeon's Law and Context Sensitivity</title><content type='html'>Hi. My name is Chip, and I've been a manager. More than once. It's not something I'm proud of, nor did I find those experiences personally fulfilling, and only rarely enjoyable. Some misguided folks seemed to think I was good at it. It was an opinion I myself didn't share.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;But I tried to be the best manager I could be, and part of that effort was spent reading books that made the bestseller lists in the various business magazines. Over the years I came to the conclusion that, like pretty much everything else, business books obey &lt;i&gt;Sturgeon's Law&lt;/i&gt;:"Ninety percent of everything is crap"&lt;i&gt; &lt;/i&gt;[1].&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;An article by Matthew Stewart, "&lt;a href="http://www.theatlantic.com/magazine/archive/2006/06/the-management-myth/4883"&gt;The Management Myth&lt;/a&gt;", published in 2006 in the magazine &lt;i&gt;&lt;a href="http://www.theatlantic.com/"&gt;The Atlantic&lt;/a&gt;&lt;span class="Apple-style-span" style="font-style: normal;"&gt; (and also as a &lt;a href="http://www.amazon.com/Management-Myth-Debunking-Business-Philosophy/dp/0393338525"&gt;book&lt;/a&gt; reviewed in the &lt;i&gt;&lt;a href="http://online.wsj.com/article/SB10001424052970204313604574329183846704634.html"&gt;Wall Street Journal&lt;/a&gt;&lt;/i&gt;)&lt;/span&gt;,&lt;/i&gt; speaks to this. In it, Stewart relates how he spent seven years as a management consultant, ultimately co-founding a management consulting firm that employed six hundred people. Stewart did not have an M.B.A. He didn't have a business degree at all. He had a Ph.D. in nineteenth-century German philosophy. So, was he a natural born genius in business management? Not so much. To hear him tell the tale, he pretty much faked it. He doesn't make it sound that hard. He also runs to ground many of the classic epic tales in management, many of which I'd read or been told about during my own management training, revealing many to have actually been epic fails.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Frederick Winslow Taylor is credited with creating management as a profession by writing the book &lt;i&gt;The Principles of Scientific Management&lt;/i&gt; based on his experience with figuring out in 1899 how to get laborers to load train cars faster: he bribed them. His book however described a much more complicated theory of management, which some called "Taylorism", which could only be accomplished by someone with an advanced education, an expensive suit, and for sure a higher salary. Unfortunately, it was a theory whose application could not be replicated by others. Bethlehem Steel Company eventually wised up, fired him, and scrapped his new fangled management techniques.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Another anecdote, and one that I had also heard about before, involved Homer Hibarger, who in the early twentieth century was doing research into how to increase productivity of workers by increasing workplace illumination. Since this research was being funded by a manufacturer of electric light bulbs, you may assume the results were a forgone conclusion, for otherwise they would have never, ah, seen the light of day. Indeed, productivity among a group of woman on a assembly line at a Western Electric plant increased when the illumination of the work area was increased. It also improved when illumination was decreased. In fact, productivity increased when almost any change was made in the work environment. What change resulted in the greatest improvement? Apparently, that occurred when some of the women on the line were replaced with others who were easier to get along with. And the fact that the women earned extra compensation for participating in the experiment.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Stewart isn't shy about relating his own experiences as a management consultant, watching his fellow consultants massage raw data to fit the curve that they needed, altering conclusions to match those required by their client, or reiterating the latest fad from a recent business bestseller whether it was applicable to the situation or not. Eventually his disillusionment led him to leave his consulting firm, only to watch it self-destruct in the receding distance under the squabbles of the remaining partners.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I had a similar period of disillusionment as a manager. I was a fan the 1982 bestseller &lt;i&gt;In Search of Excellence&lt;/i&gt; by Tom Peters and Robert Waterman. It had what appeared to be hard data on how companies succeeded in their industries through both innovation and good management. That list of excellent companies included 3M, Walt Disney, and Intel. And also Amdahl, Data General, and Wang Laboratories. As I read other books by Tom Peters, I began to see less and less hard data from Peters backing up whatever management fad he was pushing. And about those excellent companies: many of them later fell on hard times, and some of them ceased to exist all together. Some, like NCR and Xerox, didn't even produce great financial results at the time the book was published. Peters was later &lt;a href="http://www.fastcompany.com/magazine/53/peters.html?page=0%2C2"&gt;accused of fudging the data&lt;/a&gt; for the book, a charge &lt;a href="http://www.businessweek.com/magazine/content/01_49/b3760040.htm"&gt;he denies&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;But I'm reluctant to be too hard on Peters, or for that matter on Hibarger or even Taylor. Because although I'm a lousy manager, I have a pretty good track record as a software developer. And one thing I've learned over the past three-plus decades from studying, applying, and being painfully subjected to the latest software development process fad: the application of all processes and techniques, regardless of the problem domain, is very sensitive to context.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Extreme Programming was widely publicized before it had ever had its first big success. It was first applied to a project at Chrysler which never came to fruition; the &lt;a href="http://en.wikipedia.org/wiki/Extreme_programming"&gt;project was cancelled&lt;/a&gt; when Chrysler was acquired by Daimler-Benz. Large development organizations (like the kind I have found myself in much of my career) have found the principles of Agile Development &lt;a href="http://en.wikipedia.org/wiki/Agile_programming"&gt;difficult to apply&lt;/a&gt; to non-co-located staff or to mission critical applications (ditto). The U.S. government (as well as many large development organizations) have found the classic Waterfall Process to be way too heavy-weight and inefficient to work at the rapidly changing pace of software development, although it works for things like building nuclear submarines.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;That doesn't mean that Peter's eight themes of excellent companies, Boehm's tenets of Extreme Programming, the principles of the Agile Manifesto, or even the hoary old Waterfall Process, are fundamentally wrong. On the contrary, all of those have nuggets of great truths in them. It just means any particular technique or process can't be all things to all people all the time. Expecting any of them to work in all circumstances is just plain naive. And that includes whatever article on the latest thing in business management or software development that you are reading today. You might even apply Sturgeon's Law to mean that any of these ideas will be applicable at most 10% of the time.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Besides, it is in dealing with the exceptions where managers, and developers, earn their pay. The exceptions are what require innovation, insight, experience, and improvisation. As much as upper management would like to have a recipe for guaranteed success, sometimes you just have to make it up as you go long. And to come back to Stewart's article in &lt;i&gt;The Atlantic&lt;/i&gt;, it's almost always more about the people you have than the process you use.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If it were easy, anybody could do it.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;(Many thanks to my old friend and occasional colleague &lt;a href="http://jacquemarshall.net/"&gt;Jacque Marshall&lt;/a&gt; for passing the Stewart article along.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;[1] I was fortunate many years ago to hear the late Theodore Sturgeon relate this anecdote in person: at a dinner party a woman asked what he did for a living. "I'm a science fiction writer," he replied. "Oh dear," she said, "isn't ninety percent of it crap?" "Yes", he explained, "but ninety percent of everything is crap."&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28344720-3744188949174120974?l=coverclock.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://coverclock.blogspot.com/feeds/3744188949174120974/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28344720&amp;postID=3744188949174120974' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/3744188949174120974'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/3744188949174120974'/><link rel='alternate' type='text/html' href='http://coverclock.blogspot.com/2011/04/sturgeons-law-and-context-sensitivity.html' title='Sturgeon&apos;s Law and Context Sensitivity'/><author><name>Chip Overclock</name><uri>http://www.blogger.com/profile/11195242013008369733</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-1xNiFqWVjh8/TWQ1ru5Z6KI/AAAAAAAAABw/kMJyhvluNMI/s220/Chip%2BOverclock%2BAvatar%2B2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28344720.post-1115183797563903755</id><published>2011-04-19T16:03:00.007-06:00</published><updated>2011-04-20T13:27:44.002-06:00</updated><title type='text'>Elisabeth Sladen, a.k.a. Sarah Jane Smith, Dead of Cancer at 63</title><content type='html'>This is being reported by the BBC.&lt;span style="text-decoration: underline;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;a href="http://www.bbc.co.uk/news/entertainment-arts-13137674"&gt;&lt;/a&gt;&lt;blockquote&gt;&lt;a href="http://www.bbc.co.uk/news/entertainment-arts-13137674"&gt;http://www.bbc.co.uk/news/entertainment-arts-13137674&lt;/a&gt;&lt;/blockquote&gt;The SF media blog io9 has a warm and sentimental obituary.&lt;br /&gt;&lt;a href="http://io9.com/#%215793664/rip-elisabeth-sladen-doctor-whos-apprentice"&gt;&lt;/a&gt;&lt;blockquote&gt;&lt;a href="http://io9.com/#%215793664/rip-elisabeth-sladen-doctor-whos-apprentice"&gt;http://io9.com/#!5793664/rip-elisabeth-sladen-doctor-whos-apprentice&lt;/a&gt;&lt;/blockquote&gt;Thanks to forsinain42 for this.&lt;br /&gt;&lt;span class="ctedit"&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span class="ctedit"&gt;"Pain and loss define us as much as happiness or  love. Whether it’s a world or a relationship… Everything has its time  and everything ends."&lt;br /&gt;&lt;br /&gt;Sarah Jane Smith&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Doctor Who:  Series 2 -  School Reunion&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/blockquote&gt;I am crying at my desk.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28344720-1115183797563903755?l=coverclock.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://coverclock.blogspot.com/feeds/1115183797563903755/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28344720&amp;postID=1115183797563903755' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/1115183797563903755'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/1115183797563903755'/><link rel='alternate' type='text/html' href='http://coverclock.blogspot.com/2011/04/elisabeth-sladen-aka-sarah-jane-smith.html' title='Elisabeth Sladen, a.k.a. Sarah Jane Smith, Dead of Cancer at 63'/><author><name>Chip Overclock</name><uri>http://www.blogger.com/profile/11195242013008369733</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-1xNiFqWVjh8/TWQ1ru5Z6KI/AAAAAAAAABw/kMJyhvluNMI/s220/Chip%2BOverclock%2BAvatar%2B2.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28344720.post-8692353153695126277</id><published>2011-04-15T10:08:00.008-06:00</published><updated>2011-04-16T06:53:30.143-06:00</updated><title type='text'>Deconstructing the AR.drone: Part 6</title><content type='html'>&lt;blockquote&gt;&lt;/blockquote&gt;&lt;div&gt;The other day the Free Flight app on my iPad told me that there was a new firmware release available for my AR.drone. I figured there was no better time to try loading new firmware using the diagnostic port on the bottom of the device.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/5479450002/" title="AR.drone Bottom Close-Up by John Sloan, on Flickr"&gt;&lt;img src="http://farm6.static.flickr.com/5051/5479450002_f4e154ff41.jpg" width="500" height="281" alt="AR.drone Bottom Close-Up" /&gt;&lt;/a&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here is the bottom of my drone with the rubber plug with the USB symbol on it removed. You can see the port just to the lower left of center, and you can see the missing indexing pin of the eight-pin header in the upper left of the port.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here's what I needed:&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;a cable I built that has a USB Type A connector on one end and an eight-pin Molex connector on the other, wired up as &lt;a href="https://projects.ardrone.org/attachments/167/ARDrone-USB-Cable.png"&gt;described&lt;/a&gt; on the &lt;a href="https://projects.ardrone.org/"&gt;AR.drone reference platform&lt;/a&gt; web site;&lt;/li&gt;&lt;li&gt;the &lt;a href="http://code.google.com/p/ardrone-tool/downloads/list"&gt;AR.drone tools&lt;/a&gt; developed by user &lt;a href="http://embedded-software.blogspot.com/"&gt;skorpion2k&lt;/a&gt;, which include the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;a href="http://ardrone-tool.googlecode.com/files/libplf-0.1.0-win32.zip"&gt;libplf&lt;/a&gt;&lt;/span&gt; library, the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;a href="http://ardrone-tool.googlecode.com/files/plf_inst_extract-0.1.0-win32-fixed.zip"&gt;plf_inst_extract&lt;/a&gt; &lt;/span&gt;tool, and the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;a href="http://ardrone-tool.googlecode.com/files/usb_flash-0.1.0-win32.zip"&gt;usb_flash&lt;/a&gt;&lt;/span&gt; tool, the latter which includes the USB driver needed by the process;&lt;/li&gt;&lt;li&gt;a copy of the USB boot loader &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;a href="http://www.rcgroups.com/forums/showatt.php?attachmentid=3817738&amp;amp;d=1298301595"&gt;ardrone_usb_bootloader.zip&lt;/a&gt;&lt;/span&gt; kindly provided by user MAPGPS on the &lt;a href="http://www.rcgroups.com/forums/showthread.php?t=1335257&amp;amp;page=31"&gt;RC Groups&lt;/a&gt; web site;&lt;/li&gt;&lt;li&gt;a copy of the latest AR.drone firmware update file &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;a href="http://download.parrot.com/drone_soft_update/ardrone_update.plf"&gt;ardrone_update.plf&lt;/a&gt;&lt;/span&gt; from &lt;a href="http://www.parrot.com/catalog/downloads/ar-drone/"&gt;Parrot&lt;/a&gt;;&lt;/li&gt;&lt;li&gt;a Windows system with the usual accoutrements.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/5609720829/" title="Molex Eight-Pin to USB by John Sloan, on Flickr"&gt;&lt;img src="http://farm6.static.flickr.com/5310/5609720829_63c51ab3ac.jpg" width="500" height="281" alt="Molex Eight-Pin to USB" /&gt;&lt;/a&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here's the cable I fabricated, with the eight-pin Molex connector on the left and the Type A USB connector on the right. You can see the blocked socket that will match the missing indexing pin on the port when the cable is inserted in the correct orientation.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/5589926794/" title="ARDrone-USB-Cable.png by John Sloan, on Flickr"&gt;&lt;img src="http://farm6.static.flickr.com/5176/5589926794_5ec7d7b44d.jpg" width="500" height="265" alt="ARDrone-USB-Cable.png" /&gt;&lt;/a&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here's the diagram of the cable that was provided by Parrot.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I unloaded all of the AR.drone tool zip files into separate directories on my Windows laptop so that the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;README&lt;/span&gt; files wouldn't overwrite one another, but consolidated all of the sub-directories, dynamic link libraries, and executables, plus the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ardrone_usb_bootloader.zip&lt;/span&gt; file, into a single directory. There was a &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;drivers&lt;/span&gt; sub-directory with the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;P6_USB_Stage1&lt;/span&gt; device driver.&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I used the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;plf_inst_extract&lt;/span&gt; tool to extract the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ardrone_installer.plf&lt;/span&gt; file from the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ardrone_update.plf&lt;/span&gt; file. The &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;README&lt;/span&gt; file that comes with the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;usb_flash&lt;/span&gt; tool says to use a command like this&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style=" ;font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style=" ;font-family:'courier new';"&gt;plf_inst_extract -i ardrone_update.plf -o ardrone_installer.plf&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style=" ;font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;but as usual I am incapable of following simple instructions. Here's a screen shot.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/5588796275/" title="Running plf_inst_extract Against ardrone_update.plf by John Sloan, on Flickr"&gt;&lt;img src="http://farm6.static.flickr.com/5064/5588796275_34439fec05.jpg" width="500" height="359" alt="Running plf_inst_extract Against ardrone_update.plf" /&gt;&lt;/a&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I omitted the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;-o ardrone_installer.plf&lt;/span&gt; option. The &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;plf_inst_extract&lt;/span&gt; tool uses the name &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;extract_installer.plf&lt;/span&gt; by default, but the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;usb_flash&lt;/span&gt; tool expects it to be named &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;ardrone_installer.plf.&lt;/span&gt; So I renamed it. Here's what was in the directory after doing that.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/5589389192/" title="After Running plf_inst_extract against ardrone_update.plf by John Sloan, on Flickr"&gt;&lt;img src="http://farm6.static.flickr.com/5309/5589389192_414bf58cd6.jpg" width="500" height="293" alt="After Running plf_inst_extract against ardrone_update.plf" /&gt;&lt;/a&gt;&lt;div&gt;The order of these next steps is important. I connected my laptop to the &lt;i&gt;unpowered&lt;/i&gt; drone using the cable that I had made. The diagnostic LED on the bottom of the drone lit up as a portion of the digital logic in the drone was powered from the USB cable itself. &lt;i&gt;Then&lt;/i&gt; I connected the drone to its battery. The USB interface in the drone enumerated on my laptop. I went through the Windows device driver installation dialog to point it to the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;drivers&lt;/span&gt; subdirectory of the AR.drone tools. Windows installed the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;P6_USB_Stage1&lt;/span&gt; driver. Here's a screen snapshot of the Windows Device Manager following that process.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/5588796393/" title="Device Manager After Powering Up USB-attached AR.drone by John Sloan, on Flickr"&gt;&lt;img src="http://farm6.static.flickr.com/5106/5588796393_d0dc047e2e.jpg" width="500" height="384" alt="Device Manager After Powering Up USB-attached AR.drone" /&gt;&lt;/a&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I ran the &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;usb_flash&lt;/span&gt; tool without any arguments at all. The first time it failed to establish contact with the drone, probably because I botched the order of something, but it worked fine the second time. Here's the successful run split into two screen snapshots.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/5589388982/" title="Running usb_flash Part 1 of 2 by John Sloan, on Flickr"&gt;&lt;img src="http://farm6.static.flickr.com/5110/5589388982_307fcea00b.jpg" width="500" height="359" alt="Running usb_flash Part 1 of 2" /&gt;&lt;/a&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/5589389086/" title="Running usb_flash Part 2 of 2 by John Sloan, on Flickr"&gt;&lt;img src="http://farm6.static.flickr.com/5146/5589389086_a012d16256.jpg" width="500" height="279" alt="Running usb_flash Part 2 of 2" /&gt;&lt;/a&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I disconnected everything, cycled power on the AR.drone, connected my iPad to it, and the Free Flight app reported that the drone was running the new version of firmware.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This is a great example of how this kind of hacking depends upon the kindness of strangers. From the wiring diagram provided by the AR.drone's manufacturer Parrot, to the software tools developed and provided by skorpion2k, to the boot loader binary provided by MAPGPS, it is a combined effort of an avid community of AR.drone enthusiasts.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28344720-8692353153695126277?l=coverclock.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://coverclock.blogspot.com/feeds/8692353153695126277/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28344720&amp;postID=8692353153695126277' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/8692353153695126277'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/8692353153695126277'/><link rel='alternate' type='text/html' href='http://coverclock.blogspot.com/2011/04/deconstructing-ardrone-part-6.html' title='Deconstructing the AR.drone: Part 6'/><author><name>Chip Overclock</name><uri>http://www.blogger.com/profile/11195242013008369733</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-1xNiFqWVjh8/TWQ1ru5Z6KI/AAAAAAAAABw/kMJyhvluNMI/s220/Chip%2BOverclock%2BAvatar%2B2.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm6.static.flickr.com/5051/5479450002_f4e154ff41_t.jpg' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28344720.post-8195486778014605235</id><published>2011-04-11T09:47:00.019-06:00</published><updated>2011-05-20T14:38:15.951-06:00</updated><title type='text'>Deconstructing the AR.drone: Part 5</title><content type='html'>In this article I will describe some of the tools I've been using in my quest to understand the AR.drone. Some of them I had to build myself; that's part of the fun.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/5610303838/" title="Radio Shack 12V Power Source by John Sloan, on Flickr"&gt;&lt;img src="http://farm6.static.flickr.com/5062/5610303838_8c43fdd9e0.jpg" alt="Radio Shack 12V Power Source" width="500" height="281" /&gt;&lt;/a&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;When it's engines aren't rotating, the 11.1 volt AR.drone battery lasts considerably longer than the nine to twelve minutes of flight time you typically get. But I wanted to spend as much time as necessary poking around in the drone's software without having to worry about losing power. Unable to find the battery connector locally, I bought the cheapest used battery I could find off EBay, snipped the connector off of it, and attached it to a 12V power supply I got from Radio Shack.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;Important safety tip&lt;/i&gt;: I probably voided the warranty on my drone as soon as I hooked it up. But it seemed to work fine and it permitted me to work at a much more leisurely pace. If I'd had an expensive lab bench-quality power supply, I probably would have used that instead.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/5589314983/" title="Saleae Logic Analyzer and AR.drone Detail by John Sloan, on Flickr"&gt;&lt;img src="http://farm6.static.flickr.com/5019/5589314983_b185a0eaa0.jpg" alt="Saleae Logic Analyzer and AR.drone Detail" width="500" height="281" /&gt;&lt;/a&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The AR.drone has an eight-pin (one pin missing) diagnostic connector accessible from its underside, covered with a rubber plug with a USB symbol on it. This shows my drone lying upside down with the plug removed and a logic analyzer hooked up to three of the pins.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;Important safety tip&lt;/i&gt;: the AR.drone really doesn't like sitting at much of an angle and its software will complain bitterly and eventually refuse to do useful things. But placing it upside down was relevant to my interests.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/5589926794/" title="ARDrone-USB-Cable.png by John Sloan, on Flickr"&gt;&lt;img src="http://farm6.static.flickr.com/5176/5589926794_5ec7d7b44d.jpg" alt="ARDrone-USB-Cable.png" width="500" height="265" /&gt;&lt;/a&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This is Parrot's diagram describing the USB cable you can build that allows you to flash new software onto your drone without relying on the wireless network connection. What this diagram doesn't tell you is that pins 4 and 6, shown unconnected here, are receive data (a.k.a. RX, RD, RXD) and transmit data (a.k.a. TX, TD, TXD) respectively for a TTL-level serial port right off the drone's microprocessor. Pin 7 is ground just as with the USB cable. This serial port is configured to be a console terminal for the system.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;Important safety tip&lt;/i&gt;: the serial port pins are transistor-transistor-logic (TTL) level, which on the drone's ARM-based Parrot P6 processor means something like zero to 3.3 volts. &lt;a href="http://en.wikipedia.org/wiki/RS-232"&gt;RS-232&lt;/a&gt; peak signal levels vary widely, but logic values can range from -15 to 15 volts, and the standard requires that hardware tolerate voltages as high as 25 volts. Standard compliant RS-232 ports will not recognize the input signal levels of the drone's serial port, and peak RS-232 output voltages may damage the microprocessor in the drone. More on this below.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/5609720829/" title="Molex Eight-Pin to USB by John Sloan, on Flickr"&gt;&lt;img src="http://farm6.static.flickr.com/5310/5609720829_63c51ab3ac.jpg" alt="Molex" pin="" to="" width="500" height="281" /&gt;&lt;/a&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This is the USB flash cable I fabricated using the Parrot cable diagram above. I just bought a USB cable at Radio Shack, hunted down another cable that had the right eight-pin Molex connector on it, snipped the ends off both cables and did a bit of soldering. I've successfully used this cable, and some software tools developed by others, to flash my drone with the latest drone software from Parrot. I'll describe that process in a later article.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/5610301296/" title="Molex Eight-Pin to DB9 Serial by John Sloan, on Flickr"&gt;&lt;img src="http://farm6.static.flickr.com/5270/5610301296_4d233ac235.jpg" alt="Molex Eight-Pin to DB9 Serial" width="500" height="281" /&gt;&lt;/a&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This is a DB9 null-modem serial cable that I fabricated using the same approach as the USB cable, using the transmit and receive pins and the same ground pin as the USB cable. After using these cables for a bit it occurred to me that an even better approach would have been to build a single Y-cable with a the eight-pin Molex connector on one end and both a DB9 and a USB cable on the other end. That would have given me console access while reflashing my drone.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/5610302528/" title="FTDI USB Serial to DB9 TTL Converter by John Sloan, on Flickr"&gt;&lt;img src="http://farm6.static.flickr.com/5101/5610302528_18699f8cc9.jpg" alt="FTDI USB Serial to DB9 TTL Converter" width="500" height="281" /&gt;&lt;/a&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This is a commercially available &lt;a href="http://www.amazon.com/USB-3-3v-TTL-DB9-Adapter/dp/B004LC5RMO"&gt;USB to 3.3 volt TTL DB9 adaptor&lt;/a&gt; that uses an IC from &lt;a href="http://www.ftdichip.com/"&gt;Future Technology Devices International, Limited&lt;/a&gt; (FTDI). It automatically does the conversion from the TTL signal level to USB serial. Otherwise it works just like any other USB serial adaptor.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This is not my first experience with FTDI products, and it won't be the last; I'm an FTDI fanboy. This cable uses one of their ICs embedded in the DB9 hood. This same or similar FTDI chip can be surface mounted in a embedded application. This is a &lt;i&gt;huge&lt;/i&gt; win. First, you can use one of the mini or micro USB B connectors, which have a tiny footprint compared to other serial connector alternatives, as a console port for your application. Second, USB cables with the right connectors are easier to come by these days than serial cables, and it is impossible to hook them up wrong. Third and most importantly, the FTDI chip is powered &lt;i&gt;not&lt;/i&gt; from your embedded application, but over the USB cable from your laptop or desktop; this means it doesn't draw power when it's not being used, and it's active and running long before your microprocessor comes out of reset and the boot loader configures and starts using the serial port.  (A big &lt;i&gt;Thank You&lt;/i&gt; to my hardware colleagues for introducing me to this.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;i&gt;Important safety tip&lt;/i&gt;: this is the &lt;i&gt;third&lt;/i&gt; such device I've tried on the AR.drone, and is the only one that has worked, which it did &lt;i&gt;flawlessly&lt;/i&gt;. The others, made by companies I'd never heard of, were crap. (This is in fact the reason for the long pause between articles on this project.)&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/5609728085/" title="Saelae Logic with HP 110 Mini Netbook by John Sloan, on Flickr"&gt;&lt;img src="http://farm5.static.flickr.com/4113/5609728085_8dc3040d59.jpg" alt="Saelae Logic with HP 110 Mini Netbook" width="281" height="500" /&gt;&lt;/a&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It may sound like overkill, but I used a logic analyzer to make sure I had the pins right on the serial console port. But at around US$150 for an eight channel logic analyzer, that you can fit in your laptop bag, with a 24MHz sampling rate and serial decoders, doing so was kind of a no-brainer. I used a &lt;a href="http://www.saleae.com/home/"&gt;Saleae&lt;/a&gt; &lt;a href="http://www.saleae.com/logic/"&gt;Logic&lt;/a&gt;, one of many USB-connected logic analyzer pods and software packages used in conjunction with a laptop. This is the Logic pod hooked up to my little HP 110 Mini netbook running the Logic software.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/5610304710/" title="Saleae Logic Case by John Sloan, on Flickr"&gt;&lt;img src="http://farm6.static.flickr.com/5067/5610304710_3579294fef.jpg" alt="Saleae Logic Case" width="500" height="281" /&gt;&lt;/a&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/5610306042/" title="Saleae Logic Contents by John Sloan, on Flickr"&gt;&lt;img src="http://farm6.static.flickr.com/5021/5610306042_30912cfee7.jpg" alt="Saleae Logic Contents" width="500" height="281" /&gt;&lt;/a&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here is the nice zippered case (complete with cat hair, I now notice) that the Logic comes in, and its contents, along with my little key ring pocket knife just for scale. The Logic pod is about one inch or so square and is shown here with a company property sticker on it that almost covers the entire unit.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/5589867212/" title="Saleae Logic Analyzer and AR.drone Serial Decode by John Sloan, on Flickr"&gt;&lt;img src="http://farm6.static.flickr.com/5190/5589867212_21a0c5eacd.jpg" alt="Saleae Logic Analyzer and AR.drone Serial Decode" width="500" height="211" /&gt;&lt;/a&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This is a screen snapshot of the actual hexadecimal serial decode when the Logic was hooked up to the AR.drone while the drone was booting. It captured part of a "BMI Write Memory" message.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/5610311250/" title="Radio Shack Digital Multimeter by John Sloan, on Flickr"&gt;&lt;img src="http://farm6.static.flickr.com/5302/5610311250_1d6483a5a2.jpg" alt="Radio Shack Digital Multimeter" width="281" height="500" /&gt;&lt;/a&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;When you're building cables it pays to check voltages and continuity before committing yourself to your soldering. I use a Radio Shack digital multimeter. It's probably the slowest reading digital multimeter I've ever used. But it's also a fraction of the price of the nice lab bench-quality units I've used in the past, and otherwise seems to work fine.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/5609733367/" title="Weller WESD51 Soldering Iron by John Sloan, on Flickr"&gt;&lt;img src="http://farm6.static.flickr.com/5262/5609733367_541efa9851.jpg" alt="WESD51 Soldering Iron" width="500" height="281" /&gt;&lt;/a&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If you're going to solder, particularly if you're going to solder digital components (as I did when adding an expansion connector to my Beagle Board), a quality soldering iron is an absolute must. And it'll make cables too. This is a &lt;a href="http://www.amazon.com/Weller-WESD51-Digital-Soldering-Station/dp/B000ARU9PO"&gt;Webber WESD51 Digital Soldering Station&lt;/a&gt; with digital temperature control. I really like the fact that I can just dial in the recommended soldering temperature right from the manufacturer's data sheet, and the unit heats up in seconds.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/5610311748/" title="Weller 6966C Electric Heat Gun by John Sloan, on Flickr"&gt;&lt;img src="http://farm6.static.flickr.com/5186/5610311748_64aa4a69c7.jpg" alt="Weller 6966C Electric Heat Gun" width="281" height="500" /&gt;&lt;/a&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This is a &lt;a href="http://www.amazon.com/Weller-6966C-Watts-Electric-Industrial/dp/B000ICGMN4"&gt;Webber 6966C 250 Watt Industrial Heat Gun&lt;/a&gt;. It's overkill for use on shrink wrap when making cables. But it's ESD safe and gets hot enough to melt solder, so it is not one of Alton Brown's dreaded uni-taskers. Alton would also use it to brown the top of &lt;a href="http://www.foodnetwork.com/recipes/alton-brown/creme-brulee-recipe/index.html"&gt;Creme Brulee&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;There are also some tools in my AR.drone arsenal that I haven't quite needed yet, or which are more in the experimental stages.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/5609733891/" title="Parrot AR.drone Tool Kit by John Sloan, on Flickr"&gt;&lt;img src="http://farm5.static.flickr.com/4105/5609733891_b4db3c8c34.jpg" alt="Parrot AR.drone Tool Kit" width="500" height="281" /&gt;&lt;/a&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Parrot sells a small &lt;a href="http://www.amazon.com/Parrot-PF070012AA-AR-Drone-Repairing-Tools/dp/B0041G5YB4"&gt;tool kit&lt;/a&gt; with the specialized parts necessary to take the AR.drone apart and to replace parts like the propellers likely to be damaged during normal use. I'll be using these when I follow in other's footsteps and open the drone up to take a closer look at its digital components.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/5609734429/" title="Field Service ESD Matt by John Sloan, on Flickr"&gt;&lt;img src="http://farm6.static.flickr.com/5307/5609734429_1c40574365.jpg" alt="Field Service ESD Mat" width="500" height="281" /&gt;&lt;/a&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;For sure when I open the AR.drone up I'll be using a grounded Electro-Static Discharge (ESD) or anti-static mat and wrist strap. I have a permanent one wired up on the computer desk where I do most of my poking around (you can see it in some of my other articles). But I like to keep this fold-up field service model in my big tool kit.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;a href="http://www.flickr.com/photos/johnlsloan/5609730947/" title="Vinyl Chess Board, IR LED, IR Viewer by John Sloan, on Flickr"&gt;&lt;img src="http://farm6.static.flickr.com/5268/5609730947_d0fff508e0.jpg" alt="Vinyl Chess Board, IR LED, IR Viewer" width="500" height="281" /&gt;&lt;/a&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In one of my more speculative side-projects, I'm experimenting with how the AR.drone uses its ventral camera to stabilize itself during hovering. Consensus opinion on the web is that it is using edge detection, so I am using a vinyl checker board as a high contrast take off pad. Others have suggested that sometimes the drone has problems seeing the take off pad in dim light, so I'm trying to illuminate it with a tiny button cell-powered flashlight whose LED emits in the infrared (IR). Finally, I'm using an &lt;a href="http://www.amazon.com/EyeClops-Vision-Infared-Stealth-Binoculars/dp/B0026G8SCI"&gt;IR night vision viewer&lt;/a&gt; to see the LED myself; remarkably, this viewer can be found in your local toy store. You may also be surprised to find, as I did, how many LEDs in objects around the house emit in the IR portion of the spectrum.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Next up: I describe how I flashed new software into my AR.drone over its diagnostic port via the USB cable by depending upon the kindness of strangers.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28344720-8195486778014605235?l=coverclock.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://coverclock.blogspot.com/feeds/8195486778014605235/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28344720&amp;postID=8195486778014605235' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/8195486778014605235'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28344720/posts/default/8195486778014605235'/><link rel='alternate' type='text/html' href='http://coverclock.blogspot.com/2011/04/deconstructing-ardrone-part-5.html' title='Deconstructing the AR.drone: Part 5'/><author><name>Chip Overclock</name><uri>http://www.blogger.com/profile/11195242013008369733</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/-1xNiFqWVjh8/TWQ1ru5Z6KI/AAAAAAAAABw/kMJyhvluNMI/s220/Chip%2BOverclock%2BAvatar%2B2.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm6.static.flickr.com/5062/5610303838_8c43fdd9e0_t.jpg' height='72' width='72'/><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28344720.post-942466745470824930</id><published>2011-04-09T09:48:00.013-06:00</published><updated>2011-04-10T15:00:37.996-06:00</updated><title type='text'>The House of Cards</title><content type='html'>&lt;div&gt;I cannot say that I am especially a fan of the horror fiction genre. But I am a total fanboy of the non-fiction work of Eric Eide and John Regehr and their team at the University of Utah School of Computing. In 2008 they published a paper&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;Eric Eide and John Regehr, "&lt;a href="http://www.cs.utah.edu/~regehr/papers/emsoft08-preprint.pdf"&gt;Volatiles are miscompiled and what to do about it&lt;/a&gt;", &lt;i&gt;Proceedings of the 8th ACM International Conference on Embedded Software&lt;/i&gt;, 2008-10&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;which scared the crap out of me.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;They developed a tool called &lt;i&gt;randprog&lt;/i&gt; to see how a broad set of open source and commercial C compilers handled the &lt;span
