Support Code Examples

The majority of the code shown below is taken from the Sample .Net code delivered as part of the RedRat SDK. It demonstrates, in a simple fashion, the use of the RedRat API and a lot of the RedRat3’s and RedRat-X's functionality.

Finding a RedRat3 or RedRat-X

The code snippet below provides an example of how to find RedRat3 and RedRat-X devices attached to a computer via USB. The method RRUtil.FindRedRats returns a list of all RedRat3s and RedRat-Xs found and the first device in the list is selected.

protected IRedRat3 redRat;

protected void FindRedRat()
{
    // Find all known RR3s & RRXs.
    var locationInfoList = RRUtil.FindRedRats(LocationInfo.RedRatType.RedRat3 | LocationInfo.RedRatType.RedRatX_USB);
    if (locationInfoList.Length == 0)
    {
        Console.WriteLine("No RedRat3 or RedRat-X devices found.");
        return;
    }

    // Take the first device found.
    var rrLi = locationInfoList[0];

    // Get an actual RR3 or RRX object to work with.
    if (LocationInfo.IsRedRat3(rrLi.RRType))
    {
        redRat = (IRedRat3)rrLi.GetRedRat();

        if (redRat == null)
        {
            Console.WriteLine("LocationInfo object was not for a RedRat3.");
        }
    }
    else if (LocationInfo.IsRedRatX(rrLi.RRType))
    {
        redRat = RedRatX.GetInstance(rrLi);

        if (redRat == null)
        {
            Console.WriteLine("LocationInfo object was not for a RedRat-X.");
            return;
        }

        // Need to explicitly connect to a RRX.
        redRat.Connect();
    }
}

A specific RedRat can be found via information associated with the LocationInfo object, such as the device name or serial number, using the following code:

public IRedRat3 LookupRedRat(string redRatName)
{
    if (redRatName == null) return null;

    // Find all known RR3s & RRXs.
    var locationInfoList = RRUtil.FindRedRats(LocationInfo.RedRatType.RedRat3 | LocationInfo.RedRatType.RedRatX_USB);
    foreach (var li in locationInfoList)
    {
        IRedRat3 rr = null;
        if (LocationInfo.IsRedRat3(li.RRType))
        {
            rr = (IRedRat3)li.GetRedRat();    
        }
        else if (LocationInfo.IsRedRatX(li.RRType))
        {
            rr = RedRatX.GetInstance(li);
        }

        if (rr != null && rr.LocationInformation.Name.Equals(redRatName)) return rr;
    }

    throw new Exception("No RedRat3 or RedRat-X found with name: " + redRatName);
}

Discovering Information about the RedRat

The code snippet below shows how to obtain and print information about the RedRat.

public void PrintRedRatInfo()
{
    if (redRat == null)
    {
        Console.WriteLine("No RedRat3 or RedRat-X connected.");
        return;
    }

    var sb = new StringBuilder();
    sb.Append("RedRat Info:");

    // Physical position is returned in LocationInfo object
    sb.Append("\nLocation: " + redRat.LocationInformation);

    // Physical USB hardware information
    var devInfo = (USBDeviceInfo)redRat.DeviceInformation;
    sb.Append("\nHardware Version: " + devInfo.ProductName + "." + devInfo.ProductDescriptor.Version);
    sb.Append("\nSerial Number: " + devInfo.SerialNumber);

    // Firmware version information read directly from RedRat
    sb.Append("\nFirmware Version: " + redRat.FirmwareVersion);

    Console.WriteLine(sb);
}

IR Signal Learning

To capture and then store IR signals the RedRat's wide-band detector should be used. To be able to learn IR signals using this detector, a learning-signal event delegate first needs to be created.

protected SignalEventArgs SignalInEvent { get; set; }

protected void SignalDataIn(object sender, EventArgs e)
{
    var args = e as SignalEventArgs;
    if (args == null) return;
    SignalInEvent = args;
}

The SignalEventArgs object indicates several things: whether the signal has been captured properly, the signal capture has been cancelled by the user or an error has occurred via exception handling. The following code snippet shows how to add the learning-signal event delegate to the RedRat instance and then perform the above checks.

protected IRPacket LearnSignal()
{
    Console.WriteLine("\n==> IR signal input from wide-band receiver");
    var learningSig = true;
    IRPacket irPacket = null;

    try
    {
        // Tell the RedRat we want to input a demodulated signal
        redRat.GetModulatedSignal(0);

        // Handle the input signal event from the RedRat.
        redRat.LearningSignalIn += SignalDataIn;

        while (learningSig)
        {
            if (SignalInEvent != null)
            {
                learningSig = false;

                // Once signal is learnt, use the event object
                switch (SignalInEvent.Action)
                {
                    // There is input data of some kind...
                    case SignalEventAction.MODULATED_SIGNAL:
                        Console.WriteLine($"Have IR signal from wide-band detector:\n{SignalInEvent.ModulatedSignal}");
                        irPacket = SignalInEvent.IRPacket;
                        break;

                    // There is an error from the comms with the device, so read exception and throw it.
                    case SignalEventAction.EXCEPTION:
                        throw SignalInEvent.Exception;

                    // The user has cancelled learning input signal
                    case SignalEventAction.INPUT_CANCELLED:
                        Console.WriteLine("IR signal learning has been cancelled.");
                        break;
                }
            }
        }
    }
    finally
    {
        // Remove event listener and object.
        redRat.LearningSignalIn -= SignalDataIn;
        SignalInEvent = null;
    }

    return irPacket;
}

The finally section ensures the learning-signal event delegate is removed.

Outputting an IR Signal

The following code snippet provides a simple example of how to output a captured signal.

protected void DoIrSignalOutput(IRPacket irPacket)
{
    var sig = irPacket as ModulatedSignal;
    if (sig == null) return;

    // Output an IR signal via the RR3 or RRX blaster
    redRat.OutputModulatedSignal(sig);
    Console.WriteLine("IR output via blaster");

    if (!LocationInfo.IsRedRatX(redRat.LocationInformation.RRType)) return;

    // Output an IR signal via RRX port 2 at 40% power
    var rrx = (RedRatX)redRat;
    rrx.EnableIROutput(2, 40);
    rrx.OutputModulatedSignal(sig);
    rrx.DisableIROutput(2);
    Console.WriteLine("IR output via port 2 on RedRat-X");
}

Loading a Signal Database

The code snippet below shows how to load a database of IR signals from several audio-visual devices. The database is loaded from an XML file to create an object of type AVDeviceDB. This object contains multiple AVDevice objects which each represent a particular piece of AV equipment or remote.

protected AVDeviceDB avDeviceDB;

protected void LoadDB()
{
    // Read signal database from XML file.
    var openFileDialog = new OpenFileDialog
    {
        Filter = "XML files (*.xml)|*.xml|All files (*.*)|*.*",
        RestoreDirectory = true
    };

    if (openFileDialog.ShowDialog() != DialogResult.OK) return;

    var fName = openFileDialog.FileName;
    var ser = new XmlSerializer(typeof(AVDeviceDB));
    FileStream fs = null;
    try
    {
        fs = new FileStream((new FileInfo(fName)).FullName, FileMode.Open);
        avDeviceDB = (AVDeviceDB)ser.Deserialize(fs); ;
        Text = "";
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
    }
    finally
    {
        if (fs != null) fs.Close();
    }
}

Using the Database to Decode Signals

To capture and then decode RCU button presses the RedRat's narrow-band detector should be used. To be able to capture IR signals using this detector, a handler for the RCDetectorSignalIn event first needs to be added.

Console.WriteLine("\n==> IR signal input from narrow-band receiver");

// Hook up the incoming event handler for this operation.
redRat.RCDetectorSignalIn += RCSignalDataIn;

// Start the RR listening.
redRat.RCDetectorEnabled = true;

// Application code here…

// Tidy up on program termination.
redRat.RCDetectorEnabled = false;
redRat.RCDetectorSignalIn -= RCSignalDataIn;
Console.WriteLine("RC signal input terminated.\n");

if (LocationInfo.IsRedRatX(redRat.LocationInformation.RRType))
{
    // Need to disconnect the RRX once finished.
    redRat.Disconnect();
}

Once a valid signal has been received, it can then be decoded in the RCDetectorSignalIn event handler using the loaded database as shown below.

public void RCSignalDataIn(object sender, EventArgs e)
{
    var siea = e as SignalEventArgs;
    if (siea == null) return;

    switch (siea.Action)
    {
        case SignalEventAction.EXCEPTION:
            MessageBox.Show( siea.Exception.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation );
            break;

        case SignalEventAction.MODULATED_SIGNAL:
            Console.WriteLine($"Have IR signal from RC detector:\n{siea.ModulatedSignal}");

            // Decode signal if there is a database.
            if (avDeviceDB != null)
            {
                try
                {
                    var sigKey = avDeviceDB.DecodeSignal(siea.ModulatedSignal);
                    MoveWindow(sigKey);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message + "\n" + ex.StackTrace + "\n");
                }
            }
            break;
    }
}

The DecodeSignal method that belongs to the AVDeviceDB object returns a SignalKey object which contains information identifying the signal. The code snippet above gives an example of how this can then be used. The SignalKey object is passed to a method called MoveWindow whose purpose is to change the location of a simple WinForms application window on the screen. The MoveWindow method is defined below.

protected void MoveWindow(SignalKey sigKey)
{
    // Read current location
    var curLoc = Location;

    // Should not get a null return, but check in case.
    if (sigKey == null || sigKey.AVDevice == null)
    {
        lastMove = Direction.NONE;
        stepSize = 1;
        return;
    }

    // Respond to buttons on a particular remote, e.g. button "Down" on remote "CD".
    if (!sigKey.AVDevice.Name.Equals("CD")) return;

    if (sigKey.Signal.Name.Equals("Down", StringComparison.InvariantCultureIgnoreCase))
    {
        // Move down
        AdjustStepSize(Direction.DOWN);
        curLoc.Y += (int) stepSize;
        
        // If window moves off screen, move back onto other side
        if (curLoc.Y > workingScreenSize.Height)
        {
            curLoc.Y = 0;
        }
    }
    else
    {
        lastMove = Direction.NONE;
        stepSize = 1;
    }

    SetLocation(curLoc);
}

The new location of the window is set as follows:

protected void SetLocation( Point newLocation )
{
    // Likely to be a cross-thread GUI op.
    if ( InvokeRequired )
    {
        Invoke( new Action( () => Location = newLocation ) );
    }
    else
    {
        Location = newLocation;
    }
}

Remote Control Signal Queue

When reading incoming signals from a RedRat3 or RedRat-X, the action that each signal initiates on the computer could take a non-negligible period of time. So that the RedRat does not miss part or all of the next signal, reading signal data is decoupled from the signal event dispatch using a FIFO queue. The following code, when used in the handler for the RCDetectorSignalIn event, prints out the size of the signal queue.

case SignalEventAction.MODULATED_SIGNAL:
    Console.WriteLine("Have signal. Queue size is: " + siea.QueueSize);
    break;

In some situations, one may not want to process the signal backlog that can occur. A good example is when “Skip Forward A Track” is pressed on a remote that is used to control a media player on a PC. A typical button press will result in several signals being sent, however acting on all these signals will cause the media player to jump several tracks. In this case, the queue should be cleared once it has moved on one track as shown below:

// Only want to respond to buttons on remote "CD"
if (sigKey.AVDevice.Name.Equals("CD"))
{
    if (sigKey.Signal.Name.Equals("Skip+"))
    {
        mediaPlayer.NextTrack();
        Thread.Sleep(500);
        if (sender is IRedRat3)
        {
            // Clearing the queue.
            ((IRedRat3)sender).ClearRCSignalInQueue();
        }
    }
}

Database Signal Lookup for Output

The code snippet below shows how to obtain a particular signal from the signal database for output.

var sig = (ModulatedSignal)avDeviceDB.GetIRPacket("CD", "Pause");
redRat.OutputModulatedSignal(sig);

Instead of a device and signal name, a UID can also be used to lookup a signal:

var sig = (ModulatedSignal)avDeviceDB.GetIRPacket(uid);