David's picture

How to talk to Tin Can

Tue, 05/19/2009 - 13:16

You've downloaded Tin Can and got it running on your iPhone (or iPod touch 2G). Works great. But maybe you've had the sneaking thought (or perhaps more like a bright idea) that Tin Can might be able to talk to more than just another iPhone. But how would one go about this?

Tin Can uses a fairly simple modulation and coding scheme with a few different modes. If you've been following this blog, you'll know that Tin Can uses frequency-shift keying (FSK) to modulate an audio signal. This means that it uses a sine wave that alternates between two frequencies to represent a binary signal, one frequency representing a '0' (LOW) and the other representing a '1' (HIGH).



(Image courtesy of Wikipedia, distributed under the GNU Free Documentation License.)

On top of the FSK-modulated signal, Tin Can uses a standard serial protocol, with a start bit, a series of data bits and finally a stop bit. One LOW bit indicates the start of a byte, then follow eight bits of data, an optional parity bit and then a HIGH bit to indicate the end of the byte. It uses a HIGH carrier signal in between bytes to indicate that no transmission is taking place.

In addition, the standard data transmission protocol uses an initial byte 0xFF to initiate a transfer. That is, to transmit the sequence "Hello", you would send 0xFF, then 'H' (0x48), 'e' (0x65), 'l' (0x6C), etc.

There are two basic speed modes that Tin Can uses: high speed and low speed. The specs for each are:

Low speed
LOW frequency: 800Hz
HIGH frequency: 1600Hz
Data transfer rate: 100 baud
Brief carrier tone before each transmission (HIGH)
1 start bit (LOW)
8 data bits, LSB first
1 even parity bit
1 stop bit (HIGH)

High speed
LOW frequency: 2666Hz
HIGH frequency: 4000Hz
Data transfer rate: 600 baud
Brief carrier tone before each transmission (HIGH)
1 start bit (LOW)
8 data bits, LSB first
1 even parity bit
1 stop bit (HIGH)

So how would one use all this data?

Receiving data

To receive data transmitted from Tin Can (for example, with a computer or another type of device), you will need to begin by demodulating the signal. There are a number of ways to do this, from as quick and dirty as simply counting zero-crossings to as refined as a full signal analysis. However, the best method -- if you have the processing power -- is probably to use a DFT (discrete Fourier transform), most efficiently implemented on a computer as an FFT (fast Fourier transform). These techniques can be found in any basic text on signal processing. Signals and Systems by Oppenheim, Willsky and Nawab is a good starter text. A full FFT gives you a full spectral analysis of the signal, which is overkill since you are only interested in two frequencies (the HIGH and LOW frequencies). (A custom DFT optimized to measure the strength of the two frequencies only could be designed for this application, saving processing power.) The basic technique is to establish which frequency is coming in without picking up noise, so the reading at a particular frequency must be sufficiently strong that it is certainly a signal and not just background noise or a fluke. There are a few methods of determining whether you have an actual signal:

  • Compare the reading at one frequency to the level of background noise, and if the fluctuations in the background noise (use the standard deviation) are too great compared to the strength of the selected frequency (say, 1/10), your readings are probably noise.
  • Measure fluctuations in the strength of the selected frequency. If the square root of the fluctuations is greater than the square root of the average strength of the frequency, your readings are probably noise.
  • Compare the strengths of the two target frequencies. Only one should be on. If they both appear on, your readings are noise.

Once you have your frequency analysis working you can move on to reading bits. The idea here is to sample the signal with a period equal to the data rate (for example, if you are reading a signal transmitted at 100 baud you would sample a bit every 1/100 of a second). You should measure enough data each period to be able to perform the analysis listed above and thus be certain of the frequency you are receiving.

When reading the serial data you will need to watch the signal and look for the carrier tone, which will be a longish period in the HIGH state. When you receive a start bit (LOW for one period), you then read eight data bits, one parity bit and, finally, a stop bit (HIGH for one period) to indicate the end of the byte and confirm that you are synced with the signal. (If you are not synced you will need to discard the byte and start again, as something has gone wrong -- possibly a noisy signal.)

The parity bit exists to evaluate if there has been data corruption. Even parity means that the number of '1' (HIGH) bits in the data (including the parity bit) is even. If you count the '1' bits and it comes out odd, you have a data error. If you have a data error you should drop the byte (and if your custom protocol is sophisticated enough, ask that it be resent).

Since the protocol used by Tin Can always sends 0xFF as the first byte in a transmission, you must wait for this byte to come across before beginning receipt of the transmission data.

Sending data

Sending data is somewhat simpler than receiving data. The same principles apply, but you don't need to deal with the complexities of signal analysis and establishing whether you are reading a real signal -- or just noise.

The first thing you will need to send data is a sine wave generator. These are fairly simple to design if you are a proficient programmer or engineer, and there are numerous standard libraries that will do it for you.

To send bits, you simply set up two sine wave generators, one at each frequency, and alternate them on the signal output. You should make sure, by adjusting the phase of the generated sine waves, that the boundaries are smooth where you switch from one frequency to the other. Otherwise you will end up with glitches in your signal that add noise and can result in data corruption.

Once you've got bits transmitting properly, simply follow the protocol specification given above and you're home free. Precede each byte with a longish carrier tone (HIGH) for synchronization, then pulse LOW for one bit period to initiate the byte, send the eight data bits followed by the parity bit, then pulse the signal HIGH to end the byte.

To calculate the parity bit, count up the number of '1' (HIGH) bits in the byte you are sending. If it is odd, set the parity bit to '1'. If it is even, set the parity bit to '0'. The idea is to make the total number of HIGH bits, including the parity bit, even.

And be sure to precede each transmission (a block of data bytes) with the byte 0xFF.


This concise summary should give you enough information to talk to Tin Can. I hope you come up with some great uses for it!

David's picture

Tin Can - new iPhone app

Sun, 04/19/2009 - 02:54

We just released our latest iPhone app - Tin Can! Tin Can allows you to send notes from one iPhone to another using sound. Here's how it works:

1. You write a note in Tin Can on one iPhone.
2. You start up Tin Can on the other iPhone.
3. You tap Send on the iPhone where you typed the note.
4. Tin Can emits sounds and voila! The note appears on the other iPhone.

For those of you who are technically inclined, Tin Can uses frequency shift keying (FSK) to send data from one iPhone to the other. This is the same technique used by early modems to transmit data.

FSK uses alternating frequencies to represent binary data. For instance, to transmit a '1' using FSK you might use a 4 kHz signal, whereas to transmit a '0' you might use a 3 kHz signal. You would then alternate the two frequencies to send sequences of ones and zeroes.

What we have done, in essence, is turn the iPhone into a simple modem using its speaker and microphone. Pretty cool.

You can find out more about Tin Can at http://www.perceptdev.com/tincan.