It was an interface that launched a thousand hacks. Near trivial to program, enough I/O lines for useful work, and sufficiently fast for a multitude of applications: homebrew logic analyzers, chip programmers, LCD interfaces and LED light shows, to name a few.
Today the parallel printer port is on the brink of extinction (and good riddance, some would say). Largely rendered obsolete by USB, few (if any) new peripherals even include a parallel connector, and today’s shrinking computers — nettops, netbooks, media center PCs — wouldn’t have space for it anyway. That’s great for tidy desks, but not so good if you enjoyed the dirt-cheap hacks that the legacy parallel port made possible.
Fear not, for there’s a viable USB alternative that can resurrect many of these classic hacks! And if you’ve done much work with Arduino, there’s a good chance it’s already lurking in your parts drawer.
A recurring element among many recent hacks is the use of an Arduino or other USB-connected microcontroller as an intermediary between a PC and an external circuit. Code running on the microcontroller will poll some sensor to detect a change (for example, an empty coffee pot), then send a message over USB to a host PC where another program then acts on it (updating a web page to tell the world there’s no coffee). This is a reasonable approach, the parts are affordable and simple to program, but for many projects we can get by with just half the code, complexity and expense…and some folks will be thrilled to hear, no Arduino!
When the microcontroller on an Arduino board talks to a host PC over USB, all of the heavy lifting of USB communication is done by a separate chip: the FTDI FT232R USB to serial UART interface. This allows code on both the host and microcontroller to use much simpler asynchronous serial communication. As a size- and cost-cutting measure, some Arduino variants place this chip on a separate board to be attached only when programming the microcontroller, allowing it to be re-used for the next project.
This default USB-to-serial mode of the FT232R is what usually draws all the attention and gets all the girls. An alternate mode, less talked about but no less useful, is bitbang mode. This gives us independent software control of up to eight I/O lines, similar to the classic parallel port or the digital I/O lines of a microcontroller.
Acquiring the Hardware
If one isn’t already in your stash, FT232R breakout boards are easy to come by. Any shop that carries the Arduino Pro or LilyPad, or some of the bargain-priced Arduino derivatives (e.g. Boarduino), will also offer a programming cable that breaks out four of the FT232R I/O lines:
Four data lines may seem constraining, but for many tasks this is sufficient; projects using SPI communication, shift registers and port expanders will be well served. If you need the full complement of I/O lines, more sophisticated breakout boards are available:
Setting Up for Development
Another encouraging aspect of the FTDI interface is cross-platform software support; the same hacks can be created whether you’re using Windows, Linux or Mac OS X. Two software components are required to begin development: a device driver, which operates behind the scenes to handle all the low-level USB communication, and an API library, which is linked with your own code and forwards requests to the driver. Complicating matters slightly, there are two different APIs to choose from, and the setup process is a little different for each OS.
FTDI’s own API is called D2XX. This library is proprietary and closed source, but they do not charge for its use, even in commercial situations. An alternate API, libftdi, is community-developed and fully open source. This library has similar capabilities, but different function names and syntaxes. Conversion between the two APIs is very straightforward, and we’ll provide an example for each.
Windows users: if you’ve used Arduino before, the necessary driver is already installed. Otherwise, download and extract the latest Windows driver from the FTDI web site. When first connecting an FTDI cable or breakout board, use the Found New Hardware Wizard to locate and install the driver. If you want to use the D2XX library, the header and object files are included in the driver folder. This is the easier option. If you’d prefer the open source libftdi, you’ll need to download and install the both the libusb-win32 device driver and source code, then download and build libftdi.
Linux users: most current Linux distributions already have the necessary driver present as a kernel module. The D2XX library for Linux can be downloaded from the FTDI driver page, but libftdi is easier to install: simply locate libftdi-dev in your favorite package manager and have it take care of the dependencies when installing. In either case, FTDI programs for Linux need to be run as root, e.g.
sudo ./hello-ftdi
Mac OS X users: download the D2XX library from the FTDI download page. The included ReadMe file will explain how to install this library. If you’d prefer to use libftdi, download the source for libusb (legacy 0.1.12 version) and libftdi from their respective sites, then use the following commands in a Terminal window to build and install each of the two libraries:
./configure make sudo make install
If you’ve used Arduino in the past or have the FTDI Virtual Com Port (VCP) driver installed for any other reason, this needs to be disabled before bitbang mode will work on the Mac; the two cannot coexist. In a Terminal window, type:
sudo kextunload /System/Library/Extensions/FTDIUSBSerialDriver.kext
To restore the driver and resume using Arduino or other FTDI serial devices:
sudo kextload /System/Library/Extensions/FTDIUSBSerialDriver.kext
Other operating systems: drivers for several other platforms are available. Please see the FTDI drivers page for details and links.
Most of the FTDI sample code is written in C, and that’s what we’ll use here. Bindings for other languages are available on the FTDI web site.
Hello World: Flash an LED
The standard introductory program for nearly every microcontroller is the LED flasher, so let’s give that a try. You’ll need an FTDI cable or any of the breakout boards, one LED and a 220 Ohm resistor.
Connect the resistor to either leg of the LED, but keep note of which leg is the positive (anode) side. Then insert the LED/resistor pair into the socket on the end of the FTDI cable as shown below, with the negative leg connected to the GND line (the black wire on the FTDI cable) and the positive leg to the CTS line (brown wire).
Here’s the C source code, using the libftdi API. If you plan on using D2XX, have a look at the second listing a bit later; the relationship between functions should be fairly obvious.
/* hello-ftdi.c: flash LED connected between CTS and GND. This example uses the libftdi API. Minimal error checking; written for brevity, not durability. */ #include <stdio.h> #include <ftdi.h> #define LED 0x08 /* CTS (brown wire on FTDI cable) */ int main() { unsigned char c = 0; struct ftdi_context ftdic; /* Initialize context for subsequent function calls */ ftdi_init(&ftdic); /* Open FTDI device based on FT232R vendor & product IDs */ if(ftdi_usb_open(&ftdic, 0x0403, 0x6001) < 0) { puts("Can't open device"); return 1; } /* Enable bitbang mode with a single output line */ ftdi_enable_bitbang(&ftdic, LED); /* Endless loop: invert LED state, write output, pause 1 second */ for(;;) { c ^= LED; ftdi_write_data(&ftdic, &c, 1); sleep(1); } }
If the program successfully compiles (all of the required headers and libraries in the appropriate locations, and properly linked with our own code), the LED should flash slowly.
The code is largely self-explanatory, but there are a couple of points worth highlighting:
- Note the second parameter to ftdi_enable_bitbang(). This is an 8-bit mask indicating which lines should be outputs (bit set) vs. inputs (bit clear). As we’re only using a single output line (CTS in this case), we set just the one bit corresponding to that line (0x08). For additional outputs, we can OR the bit values together. The bitbang I/O pin mappings aren’t defined in either API’s header, so you might find it helpful to keep around a header such as this:
#define PIN_TX 0x01 /* Orange wire on FTDI cable */ #define PIX_RX 0x02 /* Yellow */ #define PIN_RTS 0x04 /* Green */ #define PIN_CTS 0x08 /* Brown */ #define PIN_DTR 0x10 #define PIN_DSR 0x20 #define PIN_DCD 0x40 #define PIN_RI 0x80
- Notice that the second parameter to ftdi_write_data() is a pointer to an 8-bit variable. The function normally expects an array (and the second example will demonstrate this), but for this simple case only one value is required. When issuing a single byte like this, remember to always pass by reference (a pointer), not a numeric constant. The last parameter to the function is the number of bytes.
The value(s) passed to ftdi_write_data() indicate the desired state of the output lines: a set bit indicates a logic high state (3.3 or 5 volts, depending on the FTDI adapter used), and a clear bit indicates logic low (0 volts). The mapping of bits to I/O pins is exactly the same as for ftdi_enable_bitbang(), so the prior #defines may be helpful in that regard.
More Bells and Whistles
There are many project ideas that only occasionally need to toggle an I/O line: ring a bell when a web counter increments, flash a light when email arrives, send a Tweet when the cat uses the litter box. The code for such tasks will often be just as simple as the example above. But when communicating with more complex devices and protocols, this byte-at-a-time approach becomes very inefficient. Every call to ftdi_write_data(), even a single byte, issues a USB transaction that will be padded to a multiple of 64 bytes, and there can be latencies of a full millisecond or more before this request is actually sent down the wire. To efficiently send complex data streams, it’s necessary to pass an entire array to the ftdi_write_data() function.
Bitbang mode operates very differently than the chip’s default serial UART mode. In the serial configuration, one simply calls fwrite() to issue a block of data to the serial port, and the chip manages all the details of the transmission protocol: word length, start, stop and parity bits, and toggling the logic state of the TX line at the required baud rate. In Bitbang mode there is no implied protocol; this is raw access to the data lines, and we must take care to construct a meaningful signal ourselves, essentially creating an image map of the data lines over time:
Suppose we want to communicate with a device that uses the SPI protocol (Serial Peripheral Interface, also sometimes called Microwire, synchronous serial or three- or four-wire serial, depending on the implementation). The required output would resemble the waveform in the illustration above: one output line provides a clock signal, another represents the data bits (in sync with the clock), and a third issues an end-of-data latch signal. If sending 8 bits of data, our output array would need to be twice that size (to represent the high and low state of each clock tick), plus two additional bytes for the latch high/low at the end. 8 * 2 + 2 = 18 bytes in the output array (possibly a few extra bytes, if a specific device requires a short delay before the latch signal).
SPI might be too esoteric for an introductory article; not everyone will have the right components around. Instead, let’s make something visually gratifying: we’ll drive a group of LEDs using pulse width modulation. This is of dubious utility but it’s flashy and hints at the speed and fine control that’s possible using this port.
The hardware setup is similar to the first example, but repeated four times: four LEDs, four 220 Omh resistors (we’re limiting it to four in order to work with the FTDI cable or SparkFun Basic Breakout, but it’s easily expandable to eight with the other boards). The negative legs are all connected in common to the GND line (black wire on the FTDI cable), while the positive legs are connected to CTS, TX, RX and RTS (brown, orange, yellow and green wires, respectively). The SparkFun Basic Breakout has DTR in place of RTS for the last pin, but the example code will work the same with either one…we’ll explain how shortly.
Here’s how the components look on a breadboard. Notice that the +5V line (red wire on FTDI cable) is skipped:
And here’s the source code, using the D2XX API. Adapting this to libftdi is straightforward; see the first example for the different syntaxes.
/* pwmchase.c: 8-bit PWM on 4 LEDs using FTDI cable or breakout. This example uses the D2XX API. Minimal error checking; written for brevity, not durability. */ #include <stdio.h> #include <string.h> #include <math.h> #include <ftd2xx.h> #define LED1 0x08 /* CTS (brown wire on FTDI cable) */ #define LED2 0x01 /* TX (orange) */ #define LED3 0x02 /* RX (yellow) */ #define LED4 0x14 /* RTS (green on FTDI) + DTR (on SparkFun breakout) */ int main() { int i,n; unsigned char data[255 * 256]; FT_HANDLE handle; DWORD bytes; /* Generate data for a single PWM 'throb' cycle */ memset(data, 0, sizeof(data)); for(i=1; i<128; i++) { /* Apply gamma correction to PWM brightness */ n = (int)(pow((double)i / 127.0, 2.5) * 255.0); memset(&data[i * 255], LED1, n); /* Ramp up */ memset(&data[(256 - i) * 255], LED1, n); /* Ramp down */ } /* Copy data from first LED to others, offset as appropriate */ n = sizeof(data) / 4; for(i=0; i<sizeof(data); i++) { if(data[i] & LED1) { data[(i + n ) % sizeof(data)] |= LED2; data[(i + n * 2) % sizeof(data)] |= LED3; data[(i + n * 3) % sizeof(data)] |= LED4; } } /* Initialize, open device, set bitbang mode w/5 outputs */ if(FT_Open(0, &handle) != FT_OK) { puts("Can't open device"); return 1; } FT_SetBitMode(handle, LED1 | LED2 | LED3 | LED4, 1); FT_SetBaudRate(handle, 9600); /* Actually 9600 * 16 */ /* Endless loop: dump precomputed PWM data to the device */ for(;;) FT_Write(handle, &data, (DWORD)sizeof(data), &bytes); }
When successfully compiled and run, the LEDs should slowly pulsate in a repeating “chaser” cycle. There are some notable differences from the first example:
- LED4 is defined by two bits, a logical OR of both RTS and DTR, and the two bits are always toggled in unison. This isn’t a mandatory requirement, it simply makes the program compatible with different hardware: the FTDI cable and the SparkFun Basic Breakout use a different signal on the last pin, and toggling both bits makes it work the same regardless.
- The baud rate is explicitly set to 9600 bps (bitbang mode will actually run at 16 times the baud rate). This is so the PWM speed will be the same whether using libftdi or D2XX. The former library normally initializes the port to 9600 baud by default, while the latter API (used here) opens the port at maximum speed and we need to slow it down to match. In practice, at maximum speed we’re able to get about 650,000 8-bit samples per second out this port.
- In Mac OS X 10.6, you may find it necessary to pass the -m32 flag to gcc in order to compile and link with the D2XX library. And Windows programmers using Cygwin may need some additional header files:
#include <stdarg.h> #include <windef.h> #include <winnt.h> #include <winbase.h>
Pulse width modulation makes for a nice visual demonstration of speed but unfortunately can’t really be put to serious use. In addition to the previously-mentioned I/O latency, other devices may be sharing the USB bus, and the sum total is that we can’t count on this technique to behave deterministically nor in realtime. PWM with an LED looks just fine to the eye…the timing is close enough…but trying to PWM-drive a servo is out of the question. For a synchronous serial protocol such as SPI, where a clock signal accompanies each data bit, this method works perfectly, and hopefully that can be demonstrated in a follow-up article.
Not a Panacea
FTDI bitbang mode comes in handy for many projects, but it’s not a solution to every problem. There are many situations where a microcontroller is still preferable:
- For extended standalone use, it’s a no-brainer: a microcontroller board costs less than a fancy meal and runs for days on a 9-volt battery. Only when a project is going to involve a full-on PC anyway should bitbang mode be considered.
- If a task involves basic analog-to-digital conversion, you’re almost certainly better off using a USB-connected microcontroller with built-in ADC. It’s just less hassle than the alternative.
- For tasks that require continual high-speed polling of a sensor, bitbang mode will needlessly gobble USB bandwidth and CPU cycles. Most microcontrollers have an interrupt-on-change feature that avoids polling entirely, using resources only when a change actually occurs.
We hope this introduction has planted the seeds of new hacks in your mind, or will breathe new life into forgotten classic parallel port hacks. To dig deeper, the FTDI web site is the best resource. Here you’ll find data sheets, articles, and most useful of all are the application notes. There’s also information for working with other languages: Java, Perl, Python and Visual Basic, among others.
sweet and no arduino(although hints to “microcontroler” we know what hackaday ment :) )
This is an awesome and detailed article, and USB/Parallel interfaces have a place, but remember you can also buy straight Parallel port cards, too, that have broader functionality.
The parallel port was originally designed for direct real-time machine control, at which it excels, not data transfer. When devices got ‘smart’, it was eventually hacked for use doing data transfer, and it sucked at that job.
It is still heavily used today for its originally designed purpose in automation and CNC as there is no other alternative. It is the only thing that runs real-time, and it still excels at that function where timing is critical. If you had to redesign it today, it would do exactly the same thing.
You can’t do that with USB or a USB/Parallel adapter, so the parallel port does still has some life left in it.
Great post Phil!
Although USB might be the hardware nail in the parallel port’s coffin, the software nail was Window’s protection of i/o ports making direct and easy access to the ports more difficult. For high speed and deterministic timing (like driving CNC stepper motors), DOS and parallel ports still have a nitch.
Nice one Phil, thanks!
If you have a Bus Pirate, there was an earlier HackADay on using it with a PCF8574 I2C bus expander that would provide an alternate way to get to some parallel in/out bits to experiment with. http://hackaday.com/2008/12/27/parts-8bit-io-expander-pcf8574/
Office Space :-)
Wow, great article Phil- you really covered all the bases. Very detailed, Thanks!
Awesome post. I’m working on a project right now using parallel ports and maybe I can use this to.
Thanks
Nice article, was curious about FTDI bit-bang mode and this is a great introduction.
This is why I keep coming back to Hack-a-day, because when they finally get bored with Arduinos they take a break and write an article like this ;)
LOL @ Office Space. You should have put up some hardcore rap to go with the picture. :D
*embedded (instead of “put up”)
Great article! Thanks!
Excellent work! This is exactly the type of article that keeps me coming back to Hack a Day. I have nothing against Arduino articles, but the lego ‘hacks’ almost drove me away for good.
thanks phil, you da man!
NOT A HACK!!!!!1
I used the bit-bang mode of FTDIs UM245R development board to get an LCD displaying system information. It literally took 5 minutes to find my jumper wires and wire the thing together. These little devices are amazing, and make simple USB projects actually simple.
Hai Thomas i want to control 4 steppermotors through usb port the circuit is below
http://archive.electronicdesign.com/files/29/16125/figure_01.gif
http://electronicdesign.com/article/components/control-multiple-stepper-motors-through-a-pc-s-usb.aspx
is it possible to replace DLP-USB245M WITH UM245R IF YES HOW PLEASE GIVE CIRCUIT TO ME
bijo
Great article! Thank you
I use FTDI bitbang mode to program my ATMEGA168 on my arduinos!
Phil, thank you.
glad i subscribed to the rss
this is one of the best articles i’ve seen here for quite some time. job well done phil! It’s nice to see a hardware programming article that doesn’t focus on the ‘duino for a change. Also, thanks for presenting alternative approaches using the different libraries. It’s always nice to see options for doing things differently.
Well, i’ve allways thought of (and heard of) windows as not-so-realtime OS, but is DOS better in this regard?
A Linux-distro would in my head make mutch more sense in my head for real-time cnc control :)
Much so. Protected-mode DOS programs almost entirely control the CPU, RAM, and I/O ports. The exception is interrupts/DMA for stuff like DRAM/video refresh or ATA(IDE) hard drive access. You can safely disable those if your hardware has no need for software refresh and you’re not needing the hard drive to run at full speed. Ralf Brown’s big honking book of PC info lists the most common uses for IRQs, by the way.
In fact, DOS is so bare-metal, that you’re better off reading the PC BIOS info if you’re wanting to use DOS for realtime programs. You can pretty much run a DOS program the same as if you burned an EPROM and replaced the BIOS, if that’s what you desire. Few did this because the BIOS has a good reason for existing – BIOS calls work no matter the underlying hardware >99% of the time! Windows and Linux do this because they have implemented protected-mode drivers that run much better. Running your program as an ‘option ROM’ is possible if you compile it correctly. ’55 AA’ signature and all… This leaves the BIOS interrupt implementation intact, but still makes your program not use DRAM. You can use 128KB or so of SRAM to get a bare-bones version of DOS running. Since you’re likely using a FPGA and Flash ROM, that is awfully convenient! ;)
Some more info:
Ralf Brown’s Interrupt List in HTML format is at http://www.ctyme.com/rbrown.htm
http://en.wikipedia.org/wiki/List_of_real-time_operating_systems
http://en.wikipedia.org/wiki/DOS
http://en.wikipedia.org/wiki/Option_ROM
Some memory maps and related information is at http://www.os2site.com/sw/info/memory/memory.txt
http://www.andrewmallett.net/tech/hardware/bios_one.htm
http://en.wikipedia.org/wiki/BIOS#BIOS_boot_specification
If you MUST have lower latency than USB supports or want a cheap way to get beyond 1MB/second, you’re going to need a PCMCIA (PC Card) Parallel port adapter. And if you’re doing that, it’s really tempting to just make a native PC Card/Cardbus adapter that has the advantage of interrupts and such. I can see the ‘Express’ slots on newer laptops putting the dirt onto the coffin of parallel ports after USB 2.0 put the nails in.
Some smarter people needing real-time timing to get the most speed out of protocols like JTAG is to implement the low-level stuff using a microcontroller and then sending commands in a batch to it on the USB side using a program running on the PC. For stuff like programming a router’s firmware, this is a LOT faster!
dangit – meant for bottom, not in a reply (Moderator please move this reply to bottom? Thanks if possible!)
@martinmonk: There are a number of real-time linux kernels, here’s one of them
http://www.rtlinuxfree.com/
I believe there is some RT Linux action in the audio recording area for linux, so some of those distros may be suited for such projects as well.
BTW, great article Phill. Very detailed, keep em coming!
thank you phil! this was very informative article and it remebered me why i love this site! where else can you find such blogpost on a regular basis?
now focus more on this style and you will see no more negatives comments! this is what we all waited for, a good structured, long and detailed article!
excellent work
Great job,that was an informative article.
would love to see more in the way of old school parallel bus hacks. I used to have an old XT IBM box i used for that kinda stuff, brings back the DOS nostalgia.
Hey Jones:
GROW A PAIR!
Thank you, Phil. There was a post a few days ago about putting two voltage regulators on a power supply which was pretty lame. To make it worse, the same webpage discussed bitbanging SPI and that was considered unworthy of mention.
Keep it up!
XP can be forced to allow real-time, but it REALLY doesn’t like it and you usually have to break some stuff first. I assume Vista won’t allow it at all.
DOS and many Linux kernels can both do real-time very well.
DOS may be old and limited as computer OS’s go, but for controllers its simple, stable, and has all the needed functions for Real Time control and more importantly no issues with more complex functions to interfere.
Older DOS actually makes a decent platform for machine control, and easy to develop on. I’ve heard of people using DR-DOS, FreeDOS, and even MS-DOS 2.0 (yes, the one from 1983).
Everything you need, nothing you don’t.
Oddly, the Wikipedia list for real-time OSes doesn’t mention any flavor of traditional (PC/DR/MS/…) DOS anywhere in it.
Another way to do something similar, though probably slower, is to put V-USB firmware on an AVR. I’d like to see a V-USB tutorial on here at some point; it’s a great AVR library.
Finally ! Useful Info, thank you
Thanks for the info. I always see cool projects on here and just recent got a microcontroller kit to learn from but my creativity doesn’t usually expand beyond basic I/O so this is great!
Doesn’t exactly *resurrect* all those legacy hacks though, it just makes it more possible to recreate them. I got all excited about being able to throw away the old Win98 box I use for talking to some legacy LPT kit…(no, really!)
If only I knew this a few months ago, I made a Parallel port outlet controller using the Parallel port on my home server and thought it would be great to use USB if I could, though wasn’t able to find anything cheap.
There is one thing with this method, I cannot really program, though I have recently been taking interest in Python… I just can’t find any sample code for this device.
@BenJ
Regarding python example code this will help:
https://github.com/walac/pyusb
I know it’s too late, but hopefully someone will be happy.
>If you had to redesign it today, it would do exactly the same thing.
Probably not. As a dedicated G.CODE parser and machine controller, a DOS PC isn’t bad… but neither is a small embedded ARM/MIPS/etc. machine running a much more modern RTOS. Smaller, less power hungry, easier to integrate with the CAD workstation, easier access to more GPIO, cheaper and simpler, yadda-yadda.
this is one of the best hackaday posts in a long time. thank you!
Great article, keep up the good work !
Well I dug out my ftdi cable and decided to try to play with this. I can’t get libftdi to make under cygwin. I would prefer not to used the closed source driver and would like to use gcc for compiling. I don’t currently have a linux box to use that would be practical. What is your setup? What compilier are you using?
@ron: gcc version 3.4.4. That and libusb-win32 were installed using the cygwin ‘Setup’ menu-based installer. Then download and build libftdi 0.16 with ‘configure’, ‘make’ and ‘make install’.
Good article.
Vista etc lets you bitbang hardware ports easily with a driver like WinRing0.
Great article! Thanks Phil….
Fantastic article, Phil. Seems maked with grat care
i guess I’m saying this a bit late.. but you don’t need to be root to run programs linked with libftdi.
libftdi uses libusb which in turn is a userspace library.
needless to say, i never run my ftdi programs as root. nether should anyone else.
still, its one of the best posts on hackaday.
thanks.
You not going to believe this but I have spent all day scrounging for some info about this. Thanks for this, it was a great read and has helped me out to no end. Thanks again,X10 Home Automation
Hi. Very helpful article.
In order to prevent the requirement that the libusb (and in turn libftdi) be run as root simply add the following line to your /etc/init.d/rc file:
chmod o+w -R /dev/bus/usb
This was taken from user nickbarnes:
http://ubuntuforums.org/showthread.php?t=880550&page=2
Best regards
Priyend
You safe my day! Great posting!
Great posting – the FTDI tech guy I spoke to on Friday should read it as he said that what you describe above could not be done!
Two questions if I may: What is the maximum speed possible and what is the programming environment used i.e. where would I copy the code examples to on a mac?
Thanks Simon
@Simon: the FT232R chip in the FTDI cable and most breakout boards tops out at about 650,000 bytes/sec (though with some caveats as mentioned in the article).
In Mac OS X, the code samples can be compiled using gcc from the Terminal command line.
Yes the older DOS actually made a decent platform for machine control, and was easy to develop on. I’ve heard of people using DR-DOS, FreeDOS, and even MS-DOS 2.0 Could work??
Tony Granims
Loving the Mario theme for the music-roll analogy!