Soup to Nuts: Cisco Codec – Part 3

In this part, we’ll extend our Device class and create a subclass specialized for talking to Cisco devices. Then we’ll work on properly wrapping our SIMPL+ module into a SIMPL User Macro.

Let’s add a new Codec class to our project:

Start off with a simple definition for Codec:

using System;
using Crestron.SimplSharp;

namespace CiscoRoomKit
{
   public class Codec : Device
   {
      public event EventHandler<DataEventArgs> OnResponse;

      public Codec()
      {
         OnConnect += RegisterEvents;
         OnDataReceived += HandleDataReceived;
         OnResponse += HandleResponse;
      }

      private void RegisterEvents(object sender,
         EventArgs args)
      {

      }

      private void HandleDataReceived(object sender,
         DataEventArgs args)
      {

      }

      private void HandleResponse(object sender,
         DataEventArgs args)
      {

      }
   }
}

All we’ve done so far is chain onto the OnConnect and OnDataReceived events, but we’re adding a new event named OnResponse that we’ll also register to. Let’s fill in RegisterEvents first since this happens when we connect to the Cisco codec:

private void RegisterEvents(object sender,
   EventArgs args)
{
   SendCommand("");
   SendCommand("echo off");
   SendCommand("xfeedback deregisterall");
   SendCommand("xpreferences outputmode terminal");
}

This sets up our terminal session environment: we don’t want commands echoed back to us, we’re going to setup new feedback registrations so clear out the old ones, and we want the output to be terminal-like (meaning every response ends in a newline).

Since we know the responses will be coming to us one line at a time, we can implement HandleDataReceived to clean it up and pass it to OnResponse:

private void HandleDataReceived(object sender,
   DataEventArgs args)
{
   foreach (var text in args.Message.Split('\r'))
   {
      var clean_text = text.Trim();

      if (clean_text.Length > 0)
      {
         if (OnResponse != null)
         {
            OnResponse(this, new DataEventArgs {
               Message = clean_text });
         }
      }
   }
}

We can split the incoming text on line-endings ('\r') and loop over each one. Calling Trim on each line removes any white space from the beginning or end of the string. As long as we have a line of text whose Length is greater than zero, we can pass this to OnResponse to handle the details.

For now we can leave HandleResponse blank.

SIMPL+

Copy the CiscoRoomKit.clz library to your SIMPL project folder. Let’s update Cisco Codec Wrapper.usp to take advantage of our new class. Very few changes here:

// --- Compiler Directives ---

#DEFAULT_VOLATILE
#ENABLE_STACK_CHECKING
#ENABLE_TRACE

#DEFINE_CONSTANT MAX_NAME_LEN 50
#DEFINE_CONSTANT MAX_TEXT_LEN 255

#USER_SIMPLSHARP_LIBRARY "CiscoRoomKit"

// --- Inputs ---

DIGITAL_INPUT Connect;
DIGITAL_INPUT Debug;
STRING_INPUT  To_Device[MAX_TEXT_LEN];

// --- Outputs ---

DIGITAL_OUTPUT Connect_Fb;
DIGITAL_OUTPUT Error_Fb;
STRING_OUTPUT  Error_Message;
STRING_OUTPUT  From_Device;

// --- Parameters ---

STRING_PARAMETER Host[MAX_NAME_LEN];
STRING_PARAMETER User[MAX_NAME_LEN];
STRING_PARAMETER Password[MAX_NAME_LEN];

// --- Global Variables ---

Codec RoomKit;

// --- Events ---

PUSH Connect
{
   Try
   {
      RoomKit.Connect();

      Error_Fb = 0;
      Error_Message = "";
   }
   Catch
   {
      Error_Fb = 1;
      Error_Message = GetExceptionMessage();
   }
}

RELEASE Connect
{
   RoomKit.Disconnect();
}

CHANGE To_Device
{
   Try
   {
      RoomKit.SendCommand(To_Device);
   }
   Catch
   {
      Error_Fb = 1;
      Error_Message = GetExceptionMessage();
   }
}

EVENTHANDLER Codec_OnConnect (Codec sender, EventArgs args)
{
   Connect_Fb = 1;
}

EVENTHANDLER Codec_OnDisconnect (Codec sender, EventArgs args)
{
   Connect_Fb = 0;
}

EVENTHANDLER Codec_OnResponse (Codec sender, DataEventArgs args)
{
   If (Debug)
   {
      From_Device = args.Message;
   }
}

// --- Main ---

Function Main()
{
   RoomKit.Host = Host;
   RoomKit.User = User;
   RoomKit.Password = Password;

   RegisterEvent(RoomKit, OnConnect, Codec_OnConnect);
   RegisterEvent(RoomKit, OnDisconnect, Codec_OnDisconnect);
   RegisterEvent(RoomKit, OnResponse, Codec_OnResponse);

   WaitForInitializationComplete();
}

Most of these changes are the result of renaming our global variable from Codec to RoomKit (since Codec is also the name of our new class). Notice that even though our Codec class uses the OnConnect and OnResponse events internally, we can still chain onto them in our SIMPL+ module. Both code paths will be called when either event fires.

We’ve also added a level-sensitive Debug input. If this is high when responses come in, we’ll pass those back to SIMPL Windows using From_Device. Save and compile the wrapper and import into the SIMPL Windows demo program.

SIMPL

The only change needed here is to stick a 1 on the Debug input:

Now save and recompile to get the new library into our program. Once it’s running, you can watch in SIMPL Debugger our neatly trimmed responses appear:

Notice that echo off is echoed before the setting takes effect

Create a new User Macro

Back in SIMPL Windows, go to the File > Convert to Module menu. You’ll be warned that all hardware definitions are about to be removed from your program. Click OK.

Setup your Argument Definition like so:

Just ignore the ambiguous types for now, we’ll start connecting things soon

I’d rather have Connect latch all on its own until we ask to Disconnect, so let’s add a Set/Reset Latch:

Disconnect should connect through an OR:

And make sure we handle disconnects by watching Connect_Fb:

Copy the rest of the argument definitions to our wrapper and pass the parameters in:

Don’t forget to check the Project > Edit Program Header menu to make sure you’ve targeted the correct control system types:

Save this module in the same folder as the SIMPL demo program. I named mine S2N Cisco Room Kit.umc.

An updated SIMPL demo

Drag the new module into your program and copy over the signals from the wrapper. Then, you can delete the wrapper. Now we have a nicer looking interface to use in future programs:

We’re getting there! In the next part, we’ll focus on dialing, mic mute, and standby. And that should be enough to get us the basis for a module you can continue to develop.

Thanks for reading, code is available on GitHub!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s