MicIO.js

The Problem:

Sending data from a microcontroller to any smartphone/computer

While you can use the usb interface on non-mobile devices, very few smartphones allow you to use this easily. For example using the iOS lightning port requires purchasing a 100k+ license.

Then there's bluetooth with its multitude of native code libraries to hook into: OS X, Windows, Linux, iOS, Motorola, HTC, Samsung, LG,....ew.

Solution:

Use HTML5's web audio API to create a hardware bus somewhat similar to how Square's Credit Card readers works.

I've successfully tested this with my Macbook Air with Firefox v28 and Chrome v33. IE will not work under any circumstances as it currently does not support the HTML5 Web Audio API.

Protocol Overview

Sending a data payload

Javascript is asynchronous, and setIntervals can vary by +/- a few ms. The way around this is to create a master slave bus. Our JavaScript master dictates to the microcontroller slave when it wants data through a square wave clock signal. When the square wave goes from High (1) to low (0) (falling edge), the microcontroller sends the next data payload. Here's a screenshot of this in action:
falling edge data payload

Each data payload is a sinusoid. As of right now the library generates 16 distinct frequencies, where each frequency represents a number from 0 to 15.

MicIO in its current form has an error rate of ~5%, and transfer rate of 16bits/sec. This can easily be sped up by using a faster microcontroller, as well as modulating sinusoids in the payload. For example 0xFF would be represented by: sin(2π*1000) + sin(2π*1500) +sin(2π*2000).

Parsing a data payload

HTML5's Web Audio API allows us to perform a mathematical operation called a Fast Fourier Transform (FFT). FFT's basically allow us to parse out the frequencies in our audio stream. Below is a table converting hex/decimal values to it's corresponding sinusoid frequency.

Hex Decimal Sinusoid Frequency (Hz)
0x0 0 818
0x1 1 1076
0x2 2 1335
0x3 3 1335
0x4 4 1894
0x5 5 2153
0x6 6 2411
0x7 7 2670
0x8 8 2971
0x9 9 3229
0xA 10 3488
0xB 11 3746
0xC 12 4048
0xD 13 4306
0xE 14 4565
0xF 15 4823
NULL NULL < 500 or >5500

Wiring

4 pole mini jack

4 pole mini jack

  1. Left Music = Clock In/Out
  2. Right Music = Master Data not yet implemented
  3. Ground
  4. Microphone In = Slave Data

Currently, MicIO does not support sending data to the microcontroller, but it'd be trivial to add in a future version.

Here is the actual wiring schematic with the mbed NXP LPC1768: sparkfun. Due to my cad software not having a 4 pole mini jack, it's wired up to two 3 pole mini jacks. The left mini-jack should go to the mic prong, where-as the right mini-jack goes to left Music.
wiring schematic

Here's what mine looks all wired up. FYI the green wires on the right of the mbed go to an 16x2 LCD Character display used for debugging.
example wiring

Software

Slave - MBED

The Code repository can be found on the mbed webpage here.
I've also published an example micIO application here.

Basically it takes in a string array (or number). Then micIO sends the data in half byte payloads each time the master requests more data. If there is no more data, it simply does not generate any sinusoids, aka frequency of 0.

Master

This code can be found on github here.

The HTML5 MicIO library when instantiated, will try to bind to the microphone. Upon successful binding, it'll begin to request for data.
There's two javascript files you must include:

  • js/clock.js - Generates a square wave clock for MicIO w/some helpers
  • js/index.js - The MicIO library

make sure that the volume on your computer/mobile device is all the way up.

To create a new MicIO master instance you'd simply run:

<script src="HTML5.MicIOjs/clock.js"></script>  
<script src="HTML5.MicIOjs/js/index.js"></script>  
<script>  
    var micIO = new MicIO(function onDataRecieved(halfByteArr) {
        /*
            do stuff with the data 
            E.g: convert it to a byte array
        */
        var byteArr = [];
        for(var i = 0; i < halfByteArr.length; ++i) {
            var byteIndex = Math.floor(i/2);
            if(i%2 === 0) {           //first half of the byte
                byteArr[byteIndex] = (halfByteArr[i] << 4) & 0xF0;
            } else {            //second half of the byte
                byteArr[byteIndex] += halfByteArr[i] & 0x0F;
            }
        }
        alert(JSON.stringify(byteArr));

        //Convert it to a string
        var str = "";
        for(var i = 0; i < byteArr.length; ++i) {
            str += String.fromCharCode(byteArr[i]);
        }
        alert(str);
      });
</script>  

Your specific implementation may vary. The above code is for illustrative purposes. I'd also like to thank my ECE 4180 Prof James Hamblen for his help with this project.