Support Code Examples

Finding a USB RedRat Device (RedRat3 or RedRat-X)

A LocationInfo object provides information about an actual RedRat device without having to instantiate an actual RedRat object. This is useful for example, if the device is in use by another application.

So the general process is to obtain the LocationInfo of available devices, and use this to create an instance of the RedRat object to be used.

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, but could instead find by device name etc.
    var rrLi = locationInfoList[0];

    // Get an actual RR3 or RRX object to work with.
    if (LocationInfo.IsRedRat3(rrLi.RRType))
    {
        // This is the usual way of getting a RedRat instance from the LocationInfo.
        redRat = (IRedRat3)rrLi.GetRedRat();
    }
    else if (LocationInfo.IsRedRatX(rrLi.RRType))
    {
        // OK, slightly awkward for the USB RedRatX. Use static method on RedRatX as the LocationInfo returns
        // an intermediate object used for USB comms rather than the full RedRatX object.
        redRat = RedRatX.GetInstance(rrLi);
    }

    // Need to explicitly connect to a RRX. Not needed for the RR3, but makes the code work with both.
    redRat.Connect();
}

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

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

    // Find all known RR3s & RRXs.
    var locationInfoList = RRUtil.FindRedRats(LocationInfo.RedRatType.USB);

    // Lookup by name (case insensitive)
    var locationInfo = locationInfoList.FirstOrDefault( r => r.Name.Equals( redRatName, StringComparison.CurrentCultureIgnoreCase ) );

    // Get the actual device instance
    if (locationInfo != null)
    {
        return LocationInfo.IsRedRatX(li.RRType) ? RedRatX.GetInstance(li) : li.GetRedRat() as IRedRat3;
    }

    throw new Exception($"No USB RedRat device found with name '{redRatName}'.");
}

Discovering Information about the RedRat

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

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

    // Physical position, name etc is returned in LocationInfo object
    Console.WriteLine($"Location: {redRat.LocationInformation}");

    // Physical USB hardware information
    var devInfo = (USBDeviceInfo)redRat.DeviceInformation;
    Console.WriteLine($"Hardware Version: {devInfo.ProductName}.{devInfo.ProductDescriptor.Version}");
    Console.WriteLine($"Serial Number: {devInfo.SerialNumber}");

    // Firmware version information read directly from RedRat
    Console.WriteLine("Firmware Version: {redRat.FirmwareVersion}");
}

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 void SignalDataIn(object sender, SignalEventArgs sea)
{
    switch ( sea.Action )
    {
        case SignalEventAction.EXCEPTION:
            Console.Error.Writeline(sea.Exception.Message);
            break;

        case SignalEventAction.MODULATED_SIGNAL:
            // Just print out signal data
            Console.Writeline(sea.ModuleatedSignal);                {
            break;
    }
}

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.

public void LearnSignal( IRedRat3 rr3 )
{
    Console.WriteLine( "\n==> IR signal input from wide-band receiver" );
    Console.WriteLine( "Point remote at RedRat and press a button (timeout = 10s)..." );

    var mutex = new ManualResetEvent( false );

    // Create event handler (could be a separate method).
    EventHandler learningSignalInHandler = ( s, siea ) =>
    {
        if ( siea == null ) return;
        if ( siea.Action == SignalEventAction.MODULATED_SIGNAL )
        {
            Console.WriteLine( $"Have IR signal from wide-band detector:\n{siea.ModulatedSignal}" );
        }
        else if ( siea.Action == SignalEventAction.INPUT_CANCELLED )
        {
            Console.WriteLine( "Timeout when waiting for IR signal." );
        }

        // Allow main thread to continue
        mutex.Set();
   };

   // Hook up the incoming event handler just for this operation. An alternative is to hook it
   // up for the duration of the application.
   rr.LearningSignalIn += learningSignalInHandler;

   // Set the RedRat up for IR signal input and allow 10s for the RCU button press.
   rr.GetModulatedSignal( 10000 );

   // Wait for input...
   mutex.WaitOne();

   // Unhook event handler
   rr.LearningSignalIn -= learningSignalInHandler;
}

Transmitting an IR 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");
}

Transmitting a Signal from a Database File

Generally IR signals are stored in a Signal DB file in XML format, which is loaded by an application for IR data transmission.

// Load the signal DB file
var signalDB = Serializer.AVDeviceDBFromXmlFile( filename );

// Get the required signal
var signal = (ModulatedSignal)signalDB.GetIRPacket(deviceName, signalName);
if ( signal == null )
{
    throw new Exception( $"No signal of name '{signalName}' found for device '{deviceName}' in the signal database." );
}

rr.OutputModulatedSignal( signal );
Console.WriteLine( $"\nSignal {deviceName}->{signalName} output via {rr.LocationInformation.Name}." );

Using the Database to Decode Signals

To capture and then decode RCU button presses the RedRat's narrow-band detector should be used. This has a long range and is basically the same as detectors in TVs, STBs etc.

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, SignalEventArgs siea)
{
    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);
                    Console.Writeline($"Have signal {sigKey}");
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message + "\n" + ex.StackTrace + "\n");
                }
            }
            break;
    }
}

The SignalDecoding sample gives a more complete example.

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();
        }
    }
}