Click here to Skip to main content
Email Password   helpLost your password?

Total Remote closeup, and inserted into the audio port

Introduction

One of the most exciting aspects of a mobile device is its ability to let you to interact with your surroundings. This article takes a look at a method of controlling consumer appliances (stereo, DVD player, VCR, television, hobby robots, etc...) using their built-in infrared (IR) receivers. There are several good applications available that allow you to send/receive IR signals from your Pocket PC, but they all suffer from the same problem: the IRDA port on most models is too weak to produce a consumer IR signal that can go further than 8 feet. The clever developers at Griffin Technology came up with a nifty device that plugs into your mobile PC's audio port and can send much stronger signals. My hat is off to their developers for coming up with this idea, as it is truly inventive. This article will explore how they can accomplish the feat of sending of consumer IR signals using, well, ... sound, and how you can use it in your own applications.

Note: This is NOT a paid advertisement, and I have absolutely no relationship with the Griffin Technology people. Rather, when this device first came, I contacted Griffin about getting access to an SDK so that I could incorporate the sending of IR codes in my own applications. I was very disappointed with the one-line response I received and the attitude towards consumers in their postings on other web forums. So I decided to work work this puzzle out for myself. Hey, how hard could it be? Famous last words.

Background - IR Signals in a nutshell (or a very very small box)

First things first: What is an IR code?

There are articles on the web that can explain IR signals in much greater detail than I can here. For example, Barry Gordon has a great write-up about how infrared signaling works over at RemoteCentral.com. That site also has loads of IR codes in their IR database that you can use to control your own devices. But anyway, I will take crack at explaining simple consumer IR signaling in a nutshell:

When you use your remote control to (say) turn on your television, you are really sending a command to the TV on a beam of infrared (IR) light. Unlike a flashlight, the IR light is not visible to the naked eye so you won't actually see the beam. But the sensitive IR receiver on your television can "see" it, and uses the information it contains to perform a given command. What command should it perform? Well, the beam of IR light that your remote control sends is really comprised of many little ON and OFF pulses of light. The combination of ON and OFF pulses determines the exact command that your television should perform. One set of ON and OFF pulses means TURN ON, and another means CHANNEL UP. A diagram of what is happening can be seen below:

Sample IR wave with pulses ON and OFF

Now, behind the scenes, your television remote is doing a little extra work than is outlined above. Yes, it sends a series of ON and OFF pulses and their sequence determines the specific command it is trying to send (power on, power off, change channel, etc...). But these ON and OFF pulses are really made up of a wave of IR light at a given carrier frequency. All this means is that the long pulse of ON is comprised of many little ON/OFF flickering of IR light. The IR light goes on-off-on-off-on-off... for a duration of the total ON time. Each little on-off duration is at the carrier frequency.

This carrier frequency serves several purposes including power savings and the better handling of "noise". (Note: even though IR signals are at a higher wavelength than visible light, they are still subject to the introduction of noise produced by visible light and other radiating sources). The carrier frequency varies from remote-to-remote and brand-to-brand. Normally, consumer IR remotes operate in the 36KHz (that's 36,000 cycles per second) to 40Khz range. Remember this range, as it is very important later on. An example of a wave using a carrier frequency can be seen below:

Wave with IR Carrier

Background - Code breaking

The last section was a very brief description of how a remote control sends its code using an Infrared (IR) wave. In this section, we will take a quick (and I mean quick) look at what the remote control sends. This is known as the IR code. Remember, in order for a remote control to send different commands, it needs to send a specific IR code for each command. This way, the receiving unit (say the television) can distinguish between a channel up command or a power off command.

A popular example of an IR code format is the Pronto CCF format. The Pronto is a consumer device made by Philips that learns your remote control codes and allows you to setup your own user-interface to play them back. When the Pronto learns your remote codes, it is basically analyzing the IR wave your remote control produces when you press a given button. This is the same wave we discussed above. It is the unique series of ON/OFF values from this wave that gets stored as the IR code for that button. An example of a typical IR code (in Pronto format) is below:

0000 0067 000D 000D 0060 0019 0018 0018 0018 0018 0018 0018 0030 0018 0030 0018 0018 0018 0018 0018 0030 0018 0030 0018 0018 0018 0030 0018 0018 03FB 0060 0018 0018 0018 0018 0018 0018 0018 0030 0018 0030 0018 0018 0018 0018 0018 0030 0018 0030 0018 0018 0018 0030 0018 0018 03E5

There is nothing like a big long string of Hex codes to make you reach for another dose of aspirin and a cup of coffee. But in this case, hold off. The code above is really quite simple and shouldn't cause you overdue stress. The first 4 values are just a descriptive header. The rest of the code is comprised of 1 or 2 signals (depending on the header).

Header: 0000 0067 000D 000D

The header is made up of 4 words. The first word (0x0000 in this case) specifies the code format. For our purposes, this will always be 0000 denoting a "Raw" format. There are other values for this indicating different types of encoding. Feel free to read up on those other format types, but we won't be covering them here. The second word (0x0067 = 103 decimal) is the frequency divider of the carrier signal, which is relative to the Pronto's internal clock that operates at 4,145,146Hz. So the carrier frequency for this IR code is really 4,145,146Hz /103 = 40,244Hz. The next words in the header describe what signals are contained within the code.

The third word (0x000D = 13 decimal) is known as the "once count" and indicates that this IR code has 13 on/off pairs of data known as signal bursts. The "once" signal is the signal that is sent if you press and let-go of a key on your remote control. Note that this value indicates the number of signal pairs, which means there will really be 2*Value of data for this signal. In this case, 13 pairs means we will be reading 26 values. The values are the alternating ON/OFF duration of the code. So you can see (using the color coding) that the green "once" signal starts with an ON value of 0x0060 followed by an OFF value of 0x0019 followed by an ON value of 0x0018 followed by... well, you get the picture. If the value of this word is 0x0000, it means that there is no "once" code, and that you should always send the "repeat" code no matter if you are pressing the key once, or repeating.

The fourth word (0x000D = 13 decimal) is the "repeat count" and indicates that there are also 13 signal bursts in the "repeat" signal. The "repeat" signal is the signal that is sent if you hold a key down (say, the volume key) on your remote control. If you hold a key, the "once" signal is sent followed by as many repetitions of the "repeat" signal as possible (while you are holding the remote control key down). When you let go off the key, the remote stops sending. So again using the color coding, you can see that the purple signal is the repeat signal. If the value of this word is 0x0000, it means there is no "repeat" code and the key doesn't repeat.

That's it! An extremely brief overview of a summarized version of a condensed beginner's guide to the workings of consumer IR codes. Now go grab yourself that coffee and let's get on with the meat of the article.

Mystery Unfolds - How do they do it?

Now that we know a little about IR codes and how they are built, the real question is: How can we send IR waves through the audio port of our PDA? The Total Remote comes with software to accomplish this, but I really would like to have the ability to do this from my own mobile application. So I broke out my trusty/dusty USB oscilloscope, a pad and paper, an old Sony VCR, and a pack of Mentos candy and started to investigate this conundrum myself. Four hours and 2 cavities later, I came up with how to send the proper signals through the audio port to tell my VCR to start/stop/play/etc...

To work on this problem, I wrote down a list of questions I thought needed answering in order to come to the solution. My overriding goal here was to figure out the how without actually breaking open the hardware. You see, I am cheap and clumsy. So prying open this little piece of hardware with the tools of choice (hammer and vice grips) would mostly likely lead to me right into buying a replacement. This scenario did not fall within my zero-budget. So I had to do the cheapest thing I could and actually exercise the mental muscle. Here is a list of what came to mind:

1. How can an audio signal turn into a 40Khz carrier signal?

By examining the Total Remote hardware itself, the answer to this question became apparent. The hardware has 2 IR emitting LEDs on the top, and a stereo mini-jack plug which connects it to the PDA. I was very puzzled by the 2 separate LEDs. At first, I thought they used 2 in order to give a wider transmission angle. In other words, 2 LEDs spaced slightly apart might beam a signal cone wider than just a single LED. But further examination and reflection proved this was not necessarily the case.

Next, I was wondering how I could send any 40Khz signal through the audio port. You see, audio ports are manufactured to really only pass signals within the range of human hearing which tops out around 20Khz. Anything over 20Khz would be squashed by either noise filtering or simply the performance of the port itself. So how could I possibly get a 40Khz signal from a 20KHz port? What I really needed was a port that could pass twice the bandwidth. Twice. Two. Hrm... where have I heard that number before....two ... I just ate two Mentos, no.... there were those twins I knew in college, no ....waittaminnut! Could it be a coincidence that there are two LEDs and that I need twice the bandwidth. Yeah, probably just coincidence.

No, wait! Something I was forgetting is that, sure, the audio port is limited to around 20KHz, but the audio port is in stereo. This means there are two channels (left and right), each capable of sending a 20KHz audio signal. Heyyy, maybe each of those LEDs is wired to a separate channel and would account for the stereo mini-jack plug they used. But even so, how can I get 40Khz from a 20KHz channel? The answer is to send a 20KHz signal through each channel and to send one signal out-of-phase with the other. This will double the effective frequency of the emitted signal, thus giving us the 40Khz we need to send carrier signals.

Out-of-phase signals produce desired result

2. How can we get enough power from the audio port to drive the IR signal further than a few feet?

OK, so we figured out how it was theoretically possible to send a 40Khz signal through the IR port, but that would be useless unless we can send it a reasonable distance. After all, what good is a remote control that you have to get yourself out of your chair to use! I did some web searches and I found that audio ports on PDAs are not really known for being very powerful. So I wondered how much power the Total Remote software was generating from the audio port. There was only one way to conclusively find out: bring out the oscilloscope!

I plugged in my handy dandy USB oscilloscope, ran the Total Remote software, pressed a key to send a signal, and recorded the output. What I saw baffled me at first. Here is a screenshot of the beginning of the signal:

Oscilloscope view of actual preamble waveform

Yes, I pretty much had the same reaction as you, looking at the beginning of the signal. What the heck is that? With a little more observation, I calculated that when I pressed a remote control key (in the software), the signal that was generated started with this "preamble" of a 500Hz wave on both channels that was out-of-phase. After this preamble, I could see what I expected: periods of on/off signal bursts that represented the IR code. This looked like:

Oscilloscope view of actual ON/OFF signal burst pairs

So, I was curious. What is the purpose of the preamble? The answer appears to be that in order to boost the power from the audio port to send the IR signal a reasonable distance, we need to "charge up" the total remote. My guess (because I never really pulled out the hammer and opened the hardware) is that inside there is a little capacitor tuned to this preamble signal. The preamble charges up the capacitor and this power is subsequently released when the rest of the IR signal is sent. This power boost enables the IR signal to travel further. Again, this is just a guess. Whether I am right or wrong is immaterial as long as I can reproduce the same preamble.

3. How can I send a signal through software?

Ok, so at this point, I had an idea of what needed to be accomplished in order to send an IR signal using the Total Remote. I needed to create an out-of-phase stereo audio signal that included a "preamble" of 500Hz to charge up the total remote, followed by on/off signal bursts of the given carrier frequency. If I could create this signal in some sort of audio format, I could simply play the sound file to send the IR command. And what is the first thing that comes to mind when you think of raw audio files?

Doing the WAV

So my mission is clear. I need to create raw audio files that represent the IR code I want to send, and each audio file should have a "preamble" to charge up the Total Remote. I believe the WAV file format is perfectly suited for this task. It is well documented, and has the flexibility to handle my needs. I won't go full-bore into the structure of the WAV file format but you can easily Google the information from the web. Stanford.edu has a good short description of the WAV format, and there is a different one over at SonicSpot.

When you download my source code, you will see only three classes that I created to support generating and sending the audio files. The PCMWaveGen object encapsulates the writing of the actual WAV file. The IRWav class is derived from PCMWaveGen. It takes an IR Code and generates the proper wav file, and optionally sends it to the Total Remote (audio port). Finally, we have the ProntoCCF object which encapsulates the file format used to input IR codes.

PCMWaveGen

This class encapsulates the writing of a WAV file. If you look at the source code, you will see it basically consists of a list of properties and several Write methods. All of the properties map to properties in the the WAV file format. The basic WAV file consists of headers followed by sample data. The sample data is really data at-a-point-in-time, or a "sampling" of the output stream. The headers just describe what kind of sample data to expect. An overview of the file format layout looks something like:

Section 1: RIFF Header Chunk
Section 2: FMT sub-chunk
Section 3: Data sub-chunk

This PCMWaveGen object is really not that interesting by itself, but the two methods to note are the WriteHeader and WriteFormat methods. At the very beginning of a WAV file, there is a "RIFF" header. As you can see, it is very simple.

public bool WriteHeader(BinaryWriter writer)
{
    WriteString(writer,"RIFF");
    writer.Write(this.ChunkSize);
    WriteString(writer,"WAVE");
}

The real meat-and-potatoes of the information is in the Format section. As you can see, it consists of the audio format, number of channels, bit rate, etc...

public void WriteFormat(BinaryWriter writer)
{
    WriteString(writer,"fmt ");
    writer.Write(this.FormatChunkSize);
    writer.Write(this.AudioFormat);
    writer.Write(this.NumChannels);
    writer.Write(this.SampleRate);
    writer.Write(this.ByteRate);
    writer.Write(this.BlockAlign);
    writer.Write(this.BitsPerSample);
}

ProntoCCF

This simple class takes the string representation of a Pronto CCF formatted IR code and translates it into signal arrays. The signal arrays are burst pairs just like we discussed at the top of this article. Instead of creating yet another arbitrary format, I figured it would be easier in the long run to write a simple class that parses out the Pronto codes. To use this class, you only need to pass the raw IR code string to its FromString() method. All of the processing is done for you.

If you are looking for IR codes to use with your own devices, I would suggest RemoteCentral.com. They have a great database of different brands of remote control codes that you can use. One thing to note: although a lot of times it is easy to grab an IR code from the web and have it work, they can sometimes be very temperamental. If you have a method of learning your own IR codes, this is much more reliable than using someone's code that might not work for you (for whatever reason). I only mention this because in the past, I have lost hours of work thinking there was an error in my code, when in reality, a simple change of the IR code was the answer.

IRWav

This is the real workhorse class, as it encapsulates the generation of a WAV file from an IR code. To begin using this class, you only need to do the following:

using DForge.IR.Formats;
using DForge.IR.TotalRemote;

ProntoCCF irCommand = new 
    ProntoCCF("0000 006D 001A 0000 ...rest of ir code here...");
IRWav totalRemote = new IRWav();
if(!totalRemote.SendSignal(irCommand,true))
    MessageBox.Show("Failed to send the signal");

When designing this class, I wanted to make it as efficient as possible. You see, creating WAV files on the fly is no easy task for a little 'ole PDA. Sure, it can handle it, but you really don't want the user waiting for 5 seconds every time you send an IR signal. To eliminate this waiting, I decided to cache the IR signals so that they only get generated once. They are cached by using a unique ID (GUID) that is associated with every IR command. So when you see methods that take a Guid idCommand parameter, this is the reason. When you send a command and it doesn't find the ID in the cache, it will generate the signal and cache it for later use. The next time you send the signal, it looks up the ID form the cache and sends the pre-generated signal. If you want to just send a temporary signal (like in the above example), either leave off the ID or send Guid.Empty in its place. If you do this, the code will generate the IR WAV file every time (and you won't gain the benefits of caching).

One thing to note: if you change the actual IR code, you must clear the cache before sending the new code. Otherwise, it will look in the cache and pull up the old pre-generated version and send that instead. As you can see, I provide two methods of clearing the cache. The first clears the entire cache, and the second clears the pre-generated signal for a given command.

/// <summary>

/// Clears the cached signal directory

/// </summary>


public void ClearCache()
{
    if(Directory.Exists(this.CacheDirectory))
        Directory.Delete(this.CacheDirectory,true);
    Directory.CreateDirectory(this.CacheDirectory);
}

/// <summary>

/// Clears the cached signal for the given command

/// </summary>

public void ClearCache(Guid idCommand)
{
    string strFilename = CacheDirectory + idCommand.ToString();
    if(File.Exists(strFilename))
        File.Delete(strFilename);
}

When you send a signal using IRWave, you will see several things going on. First, you will notice that we turn up the volume on the audio port to its maximum level. This is the equivalent of us saying we want to send the IR signal with maximum power. Remember in the earlier sections, how we discovered that preamble signal and how it is used to boost the power? Well, if we don't push the audio port's volume to maximum power before we send the signals, the preamble would be for nothing. So we save the current audio volume level and put it up to 100% power for maximum range. Next, we check the cache to see if the signal has already been created. If it is in the cache, we use it. Otherwise, we take the hit and generate the WAV file from the IR command. Finally, we put the volume back to its original level. I figured this was a nice touch, so that when you later plug your headphones in and queue up your Celine Dione MP3 collection, you won't get popped eardrums. Well, no more than normally at least.

/// Sends the given IR signal via IR

public bool SendSignal(Guid idCommand, double irCarrier, 
                              short[] signal, bool usePreamble)
{
    bool success = true;

    try
    {
        // For total remote we need to send maximum power to the audio port

        // so that we get the greatest range.

        Sound.PushVolumePercent(100);

        string strFilename = this.TempWavFilename;
        if(idCommand!=Guid.Empty)
        {   // We should cache commands with ids.

            // Only generate a signal file if it doesn't already exist

            strFilename = CacheDirectory + idCommand.ToString();
            if(!File.Exists(strFilename))
              this.WriteIRWAVFile(strFilename,irCarrier,signal,usePreamble);
        }
        else
        {   // For commands without Ids (temporary ones) then we just

            // write out the audio version of the IR signal to a temp file

            this.WriteIRWAVFile(strFilename,irCarrier,signal,usePreamble);
        }

        // Play the audio signal through the total remote,

        // generating an IR signal

        success = Sound.Play(strFilename);

        // Make sure we reset the volume to its previous value.

        Sound.PopVolume();
    }
    catch(Exception except)
    {
        MessageBox.Show(except.Message);
        success = false;
    }

    return success;
}

The next step in processing is to examine the WriteIRWAVFile method. This method draws upon the base class (PCMWavGen) to write the necessary information to create a valid WAV file. WriteHeader and WriteFormat generated sections #1 and #2 of the WAV file format. The 3rd section is generated by calling the WriteWAVSignal method which (finally) gets to the issue of generating the proper audio WAV data.

public bool WriteIRWAV(BinaryWriter destWriter, 
       double carrierFreq, short[] signal, bool usePreamble)
{
    bool success = true;

    try
    {
        WriteHeader(destWriter);
        WriteFormat(destWriter);
        WriteWAVSignal(destWriter,carrierFreq,signal,usePreamble);
    }
    catch(Exception e)
    {
        MessageBox.Show(e.Message);
        success = false;
    }

    return success;
}

The WriteWAVSignal method creates audio data for the given IR code. If you can remember from previous sections, the IR code consists of a series of ON/OFF burst pairs. The ON time is comprised of many on-off transitions of the signal, the frequency of which is determined by the carrier frequency of the IR code. The OFF time is, well, simply time where we want to be absolutely quiet and send no signal at all.

/// Creates a WAV audio signal that represents

/// the given consumer IR remote control code.

/// </SUMMARY>

/// <PARAM name="writer">Destination of the WAV data</PARAM>

/// <PARAM name="carrierFreq">Carrier of the IR code in hz (ie. 38000)</PARAM>


/// <PARAM name="irSignalPairs">Array of alternating short values 

///      representing ON and OFF times of the carrier signal for the IR code. 

///      Times are given in multiples of the carrier signal.</PARAM>

/// <PARAM name="usePreamble">If true, the WAV signal will be prefixed 

///      by a 1Khz preamble (necessary for the Total Remote hardware)</PARAM>

/// <returns></returns>

public bool WriteWAVSignal(BinaryWriter writer, double irCarrier, 
                             short[] irSignalPairs, bool usePreamble)
{
    bool success = true;

    try
    {
        // Indicate a DATA chunk is to follow in the WAV

        WriteString(writer,"data");

        // Mark the data size location for later

        long dataSizePos = writer.BaseStream.Position;
        // Write a dummy size for now

        int dataSize = 0;
        writer.Write(dataSize);

        // Mark beginning of data to determine size later

        long dataStartPos = writer.BaseStream.Position;

        // If including the preamble for the Total Remote, then write it

        if(usePreamble)
            CreatePreamble(writer);

        bool high = true;
        double time = 0;
        double halfCarrier = irCarrier/2;

        // For each value in the IR code, generate its waveform.

        // The array consists of pairs of short values indicating

        // ON and OFF values of the carrier.

        // An example would be { 0x5E, 0x19, 0x17, 0x19 }

        // would produce an ON signal of

        // duration 0x5E*Carrier followed by a "silence"

        // of 0x19*Carrier followed by an 

        // ON signal of 0x17*Carrier followed by a "silence"

        // of 0x19*Carrier ....

        for(int i = 0; i < irSignalPairs.Length; i++)
        {
            // If last is a long "low" then ignore for now

            if(i == irSignalPairs.Length-1 && !high)
                break;

            this.SampleHigh = high?255:128;
            this.SampleLow = high?0:128;

            time = (double)irSignalPairs[i] / irCarrier;
            CreateStereoCarrier(writer,halfCarrier,irSignalPairs[i] ,true);

            // toggle ON and OFF values

            high = !high;
        }

        // Determine the overall Data size and write it to the WAV

        dataSize = (int)(writer.BaseStream.Position-dataStartPos);
        writer.BaseStream.Position = dataSizePos;
        writer.Write(dataSize);

        // Go ahead to end

        writer.BaseStream.Position = writer.BaseStream.Length;

    }
    catch(Exception e)
    {
        MessageBox.Show(e.Message);
        success = false;
    }
    return success;
}

The last method of note creates the data for a stereo carrier wave. Originally, I created a method that calculated a carrier wave with a given phase-shift and called it twice to get a stereo wave. Due to speed issues, I rewrote this to calculate both channels at once. (The original method, although unused, is included in IRWav). Also, I took one more caching step and cached the carrier wave that was generated. The IR codes that come from a single remote generally use the exact same carrier frequency. So I managed to eek out more speed improvement by caching the last carrier frequency. Then I simply copy enough of these carrier cycles into the destination signal that will fit in the given duration.

public void CreateStereoCarrier(BinaryWriter writer, 
  double carrierFreq, short cycles, bool phaseShift) 
{ 
   if(carrierFreq != _lastCarrierFreq || _lastCarrierWave == null 
        || _lastCarrierWave.Length == 0 || _lastCarrierPhase != phaseShift) 
   { 
        if(_lastCarrierWave!=null)
            _lastCarrierWave.Close();
        _lastCarrierWave= new MemoryStream(); 
        _lastCarrierFreq= carrierFreq; 
        _lastCarrierPhase= phaseShift; 

        BinaryWriter bw = new BinaryWriter(_lastCarrierWave); double

        samplesPerWave = this.SampleRate/carrierFreq; double 
        quant = 2*Math.PI/samplesPerWave; double
        sampleValue = 0; byte
        bytValue = 0; int
        i = 0; double
        delta = Math.Abs(this.SampleHigh-this.SampleLow); double

        cycleDuration = 1 / carrierFreq; 
        double step = 1/ ((double)this.SampleRate); 

        //For each sample, determine the value that would create a signal 

        //of the given carrier frequency for the duration specified 

        for(double time = 0; time < cycleDuration; time += step) 
        {
            sampleValue = delta/2 * (1 + Math.Cos(quant*i)); 
            bytValue = (byte)(this.SampleLow+sampleValue); 
            //First channel 

            bw.Write(bytValue);
            //Are we phase shifting the second channel? 

            if(phaseShift)
                bytValue = (byte)(this.SampleLow + delta - sampleValue); 
            //Second Channel 

            bw.Write(bytValue);
            i++;
        }
        //create a "silent" wave as well. 

        _lastNullCarrierWave = new byte[_lastCarrierWave.Length]; 
        for(int j= 0;j<_lastNullCarrierWave.Length;j++)
            _lastNullCarrierWave[j] = (byte)(this.SampleLow+delta/2);
    }

    if(writer != null)
    {
        // Now make an exact copy of the carrier

        // cycle for each of the remaining cycles

        if(this.SampleHigh - this.SampleLow == 0)
        {
            for(short nI=0; nI < cycles/2; nI++)
                writer.Write(_lastNullCarrierWave,0,
                    (int)_lastNullCarrierWave.Length);
        }
        else
        {
            for(short nI=0; nI < cycles/2; nI++)
                writer.Write(_lastCarrierWave.GetBuffer(),
                    0,(int)_lastCarrierWave.Length);
        }
    }
}

Sample Application

Screenshot of pocketpc application

The sample application is very simple and is meant to be nothing more than an illustration of how to use the underlying IR code. To really take advantage of the sample application, you need 2 things.

The actual sending of the IR data couldn't be simpler, as illustrated by the following snippet:

/// <summary>

/// Private member that allows us to send signals to the TotalRemote

/// </summary>

IRWav _totalRemote = new IRWav();

/// <summary>

/// Sends an IR command

/// </summary>

/// <PARAM name="idCommand">Unique ID of the command (or Guid.Empty)</PARAM>


/// <PARAM name="irCommand">IR Command to send</PARAM>

void SendIRCommand(Guid idCommand, DForge.IR.Formats.ProntoCCF irCommand)
{
    if(!_totalRemote.SendSignal(idCommand,irCommand,true))
        MessageBox.Show("Failed to send the signal");
}

The sample application reads the config.xml file and dynamically generates buttons for the user interface. (Please note that the config.xml file must reside in the same directory as the executable.) When you press a button, its associated IR code is then sent through the total remote. Each entry in the config.xml file consists of an ID (used to uniquely identify the button), a Name (displayed on the button), and the Code (actual Pronto CCF data representing the IR code you want to send). An example of the config.xml file is as follows:

<?xml version="1.0" encoding="utf-8" ?> 

<Buttons>
    <Button ID="Button1" type=button>
        <Id>6A25C487-F171-49a2-A6D8-2C5F28FF546F</Id>
        <Name>Sony VCR Play</Name>
        <Code>0000 006D 0020 0000 005E  0019 0017 0019 0017 
           0019 0017 0019 0030 0019 002E 0019 0017 0019 0017 
           0019 0017 0019 0030 0019 0017 0019 0030 0019 002F 
           0019 0030 0019 0017 0019 0030 00AF 0060 0019 0017 
           0019 0017 0019 0017 0019 0030 0019 0030 0019 0017 
           0019 0017 0019 0017 0019 0030 0019 0017 0019 0030 
           0019 0030 0019 0030 0019 0017 0019 0030 3F03</Code>

    </Button>
    <Button ID="Button2" type=button>
        <Id>F96CA367-E471-4bff-AC39-7D3594E135F8</Id>
        <Name>Sony VCR Stop</Name>
        <Code>0000 0067 001A 0000 0060 0019 0018 0018 0018 
           0018 0018 0018 0030 0018 0030 0018 0018 0018 0018 
           0018 0030 0018 0030 0018 0018 0018 0030 0018 0018 
           03FB 0060 0018 0018 0018 0018 0018 0018 0018 0030 
           0018 0030 0018 0018 0018 0018 0018 0030 0018 0030 
           0018 0018 0018 0030 0018 0018 03E5</Code>

    </Button>
    <Button ID="Button3" type=button>
        <Id>7A4F502A-2593-4d00-A4F3-3672B7B390B2</Id>
        <Name>Zenith Television Power ON/OFF</Name>
        <Code>0000 006D 0022 0000 0018 0011 0018 00A5 0018 
           00CF 0018 0011 0018 00A5 0018 0010 0018 00A5 0019 
           00CD 0018 0010 0018 00A5 0018 00CE 0018 0011 0018 
           00A5 0018 00CE 0016 00CF 0018 0011 0018 13B6 0018 
           0011 0018 00A5 0018 00CF 0018 0011 0018 00A5 0018 
           0010 0018 00A5 0019 00CD 0018 0010 0018 00A5 0018 
           00CE 0018 0011 0018 00A5 0018 00CE 0016 00CF 0018 
           0011 0018 13B6</Code>

    </Button>
</Buttons>

Wrapping it up

So, there we have it from start to finish. I really must commend Griffin for devising a very clever solution to sending IR signals through the audio port. The method is ingenious and quite simple. I even toyed with creating a homemade version of the dongle, but just haven't had the time. I think the recipe is as follows:

1 part stereo mini-jack +
1 part capacitor +
1 part resistor +
2 parts LEDs +
1 part Elfin Magic
= Homemade Total Remote

The problem is that I am a bit short on the Elfin magic. Maybe someone will take this article as the basis and come up with the home version. But either way, once you know a bit about how IR signals are created, the process of determining how to convert audio to IR is pretty straightforward.

I do have a couple closing notes:

I cannot stress enough that when using this application to send IR codes to your own devices that the IR code is very important! Not only do you need to find the proper IR code for your make/model of device, but it has to be a good code. Generally, the codes I found were usable. But a lot of codes were missing the full code. Hint: If you get an IR code that doesn't seem to work, try sending it twice in rapid succession. If this still doesn't work, then it is probably a bad code. Also, please do not send me requests for IR codes!!! I don't have a big-book-of-IR-codes. Search the web (or look at the sites I references) and you will find them.

This method of using the audio port may not work on all PDAs.  If the hardware manufacturer skimped on the audio port, it might not be capable of sending a signal (or at least a strong one).  For example, I believe the Dell Axim (at least older models) have  a problem with using the audio port in this manner.  See the Griffin Technology site for a complete list of supported models.

References

Boy howdy, I certainly referenced a lot when developing this project. Here are the links of the relevant sources:

More Reading

Here are some related IR links:

History

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
QuestionAnyone tried it?
Adrian Ber
3:37 13 Sep '09  
I have built my own dongle with two IR leds connected to audio right and left.
Then I connect the dongle to the speakers and I run the application on the PC.
It seems that it does not work. Can someone please tell me what do I do wrong?
The dongle seems to work, as when I play a sound, the leds emit light.
I'm using for testing a Canon camera and RC-5 remote control code: 0000 007e 0002 0000 0010 00b1 0010 00b1.
Questionport
Adrian Ber
10:02 12 Sep '09  
I'm trying to port this program. Can someone send me a WAV file and the associated IR code for testing?
Thanks.
GeneralIpaq 210
JohnK888
7:07 5 Jan '09  
Hi Michael:
One question - from reading your article.
My ipaq 210 doesn't have ir capability.
Will I have this capability using this device?

Thanks
JohnK
General(Applause)
Predrag Tomasevic
8:34 4 Oct '08  
Your description of theory behind IrDA is great. Thanks for great article!
GeneralPorting to Linux and MacOSX
jumpjack
7:40 2 Jul '08  
Not yet done, but it's a good starting point:
http://code.google.com/p/ledrem/source/browse

Here you find RapidQ BASIC sources to create a WAV file by sampling a remote control using your Windows PC.

RapidQ is quite compatible with Linux, so maybe you can easily port the SW.
If you cannot, try looking at file sky_SKY(on).zip file: it contains:
sky-SKY(on).wav - remote control sample
Provalirc.conf - resulting LIRC file
sky-SKY(on).bat - DOS batch files which creates the final WAV file using SOX program (which is available for Linux)
sky-SKY(on)_.wav - the final WAV file (to turn on Italian SKY Satellite receiver)
GeneralPlatform
erasmur
4:46 23 Jun '08  
In what platform is this cods written in? Will it work on windows mobile 6?
I don’t know much about programming but would like to give this a try.
GeneralI found the Griffin patent descriprion freely available online! (free registration required)
jumpjack
22:47 14 May '08  
http://www.freepatentsonline.com/6931231.html[^]
GeneralAudio to the PDA possible?
mangotj
17:54 1 Nov '07  
From this article I'm wondering if I can transmit stereo audio from another source via IR to the PDA. I would of course utilize the mic input on the PDA.
Do you see any issues with this...my bandwidth would be about 10kz and the only concern I have is the phase of the audio. They should be pretty close.

tks,
ERSmile
QuestionWhere to get a dongle?
t_barbz
7:12 30 Oct '06  
Does anyone know where i can get a dongle that this will work with? Thanks. Tom
GeneralUsing the built in IrDA port
t_barbz
6:45 27 Oct '06  
Does anyone know how this could be modified to work with the built in IrDA port of a pocket pc rather than using the IR audio jack?

Any help would be greatly appreciated

Tom
Questioni have a silly idea
NuVanDibe
23:28 13 Aug '06  
i'm rather new to this, but what about this method:

stuff needed:
1) remote control
2) old headphones or another chord with a mono audio jack on one end
3) soldering iron

1. open the remote control and remove the infrared LED.
2. Clip the chord with the audio jack on it and then solder the piece of chord with the audio jack onto the remote control in place of the infrared LED.
3. open up a sound recording utility and hit record, then tap a button on the remote control.
4. desolder the wire from the remote control and solder it directly to the LED.
5. connect the audio jack to your line out and play the sound back.

i've tried it, but i can't get it to work.
NewsBuilt my own dongle...
RF_GUY
6:47 20 Jul '06  
Hey Guys, very-very nice article. And since the dongle has been discontinued (you still can buy Total Remote software though) I managed to build my own, it works fine. I didn't get good IR LEDs in time so i used generic once from Radio Shack (low power, but still got about 10 meters range). I must admit, without this article it wouldn't be possible to build it. Their idea to divide 40 KHz spectrum in two was just genius in its simplicity. So basically you have to connect two IR LEDs in opposite polarity between Left and Right Audio Out. Then one of them will transmit during positive audio cycle and another during negative, that's how you get 40 KHz on 20 KHz port and that's why you need two LEDs.
Specs to look for:

1) IR LEDs, wavelength 940 nm, Radiation intensity at least 40 mW/sr (there are very good LEDs
from Avago Tech, they emit 50 mW/sr, HSDL-4271. Another choice would be HSDL-4220, their
peak is at 875 nm, but they are powerful enough to provide you range of up to 50 feet.
They are typically available from Digi-Key and they are cheap).
Typical bias current for IR LEDs is about 100 mA. Viewing Angle at least 30 deg.
If you can't find 940 nm diodes, try to use 875 nm, they still should work fine.
IR receivers have wide range of reception.
Anyways your PDA uses 875 nm diodes (940 nm usually used for remote controls and 875 nm for
IR communication).
Pay attention that your LED should be able to withstand max Reversed Voltage between Left and
Right Outputs of Audio Port on your PDA (for my iPAQ 3850 it was 5 V).
2) Calculate bias resistor based on Forward Voltage of LED and Bias Current.
R=(Vcc-Vf)/I
3) I used 3.5 mm stereo audio to regular plugs adaptor from Radio Shack to assemble my dongle.
Looks good, but of course not as pretty as the original one.

That's it, you are good to go. For some reason can't copy pictures in my answer.

RF_Guy

RF_Guy
GeneralRe: Built my own dongle...
slkhu
18:18 10 Aug '06  
1. How do I find the Reversed Voltage? my is a IPAQ H4150.
2. What is the resistor for ?
So is it
Left--R1--LED--Right?
Right--R2--LED--Left?
and ignore the ground?
I have a old remote can I take the LED from that remote, but i have no idea of the part number.
GeneralRe: Built my own dongle...
slkhu
22:01 17 Aug '06  
Finally I got mine to work, very simple.

Audio Left - IR LED - Right Audio
Audio Right - IR LED - Left Audio


GeneralRe: Built my own dongle...
slkhu
23:28 26 Sep '06  
Apparently someone email to ask me the wiring...
very simple,
goto a hardware shop, buy 2 IR transmitters LEDs or get it from an old remote control, u need two however. Buy or like me cut out from an old headset the jack. Then solder the LEDs directly to the jack.
The jack should have 3 parts. 1 ground, Left and right
Solder the LEDs to the Left and right make sure they of opposite direction. The LEDs should have 1 long and 1 short lead.
SO..
LED1_Long--LED2_Short--Left Audio
LED1_Short--LED2_Long--Right audio
Ignore the ground

Use handphone camera to check, if it work u should see the LEDs flashing when u press a button.

BTW I have no luck with the codes.. so I bought the Griffin Software instead.
GeneralRe: Built my own dongle...
oliseski
10:38 30 Mar '07  
Here you have a simple circuit to do it:
http://www.lirc.org/ir-audio.html[^]
GeneralRe: Built my own dongle...
jumpjack
11:56 14 May '08  
I sampled my remote at 38000 Hz.
I connected two IR led as explained.
I play the file.
Nothing happens. Frown

what did I miss?!?

If I use standard LEDs, I can barely see a bit of light: shouldn't I require a little amplifier?
Confused
GeneralRe: Built my own dongle...
jumpjack
22:42 14 May '08  
Any schematic available?

Can actually a PDA send enough current to the LEDs? I tried playing a wavefile through an IR led using PC audio card, but emitted light is barely visible (using a webcam), compared to really bright light emitted by a remote!
GeneralRe: Built my own dongle...
slkhu
23:00 25 Dec '08  
Still having problem?
If you want I can send you the WAV file that I did for Philips TV on/off. Can some one point me to where I can permanent post this file for people to download?
GeneralPC Remote
Acuum
4:32 6 Jul '06  
Finaly, this looks like what i have been after...
A Way to whilst working at my computer change TV channel, stereo volume, all that kind of stuff, which out having to hunt under books paper work for the remote, that i left the other side of my bedroom!!!!

My plan is. create wav files for each button.
save as wav file. Find a media player for windows, that allows you to select which sound card to output the sound from. install CHEEP second sound card in machine, with IR sending attached to it perminatnly.

Make pretty gui from static webpage. with Wav files linked. Click link wav file loads and plays in selected media player. and channel should change :P

this should also work well with my planned video streaming. i should be able to change channel on my digi box whilst im watching it streaming to my work pc :P Only kidding, about watching from work. but you ge the idea.

Acuum
GeneralCould it be simpler
Acuum
4:20 6 Jul '06  
Sorry i have very limited knoledge, (dont stomp on me to hard if this is a stupid sugestion...

but could it not be as simple as.

IR LED
+ -----------------------|<---------
| |
| |
--------->|-------------
IR LED |
|
gnd ----------------------------------


by my understanding on the raiding edge of the wave file we would get a pulse, and then also on the falling edge of the wave we would get a pulse from the second LED.

would this not have the effect of doubling the effective frequency we get, without trying to get both stereo signals in sync...?????????????????????

just thought, dont shoot me down too hard :P

Acuum
GeneralRe: Could it be simpler
Acuum
4:23 6 Jul '06  
My diagram didn't work at all... oooops

let me try again,

                           IR LED
+ -----------------------|<---------
| |
| |
--------->|-------------
IR LED |
|
gnd ------------------------------

GeneralRe: Could it be simpler
RF_GUY
8:01 3 Aug '06  
Try to connect both IR LEDs between Audio Left and Audio Right, do not connect them to GND. You got right opposite poliarity idea though.

RF_Guy

RF_Guy

Generallooks more like AM modulation to me
calixo
1:10 19 Feb '06  
I had a look at the griffin software on my PDA and made some recordings of the audio output with my soundcard. There is no out-of-phase signal as a matter of fact, both signals have the same phase. If you simply add those two signals, you'll get another signal with the same frequency, only increased in amplitude for 0 deg. phase or decreased/canceled for 180 deg. phase(inverted signal on one channel)

I guess the solution used by griffin is to AM-modulate both signals, i.e. multiply them using a amplitude modulator, which could be as simple as a transistor.

Check it out with cool edit - i.e. generate 400 Hz stereo tone, copy left channel, Edit->mix paste to the right channel and choose "modulate", and you'll get a nice 800 Hz signal as a result.
QuestionPort Software to s60?
uzzors2k
11:01 12 Nov '05  
Could someone port this to a s60 app? I don't have any programming skills, but I do like hacks. If no one is willing to do it for me, could someone show me how? I've got the symbian SDK and source code for the pocket beamer.
Help appreciated


Last Updated 11 Jun 2004 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010