Graphics.RemoteCommandingCapability - lordmundi/wikidoctest GitHub Wiki

EDGE Remote Commanding Capability

« Using DNS Service Discovery | EDGE User’s Guide | Web Commanding Capability »

This page contains information on the EDGE Remote Server (included in EDGE 2.1 and later) and how to setup a client to connect to the server and send commands.


Purpose

In response to Issue 00150 a remote commanding capability was implemented by adding a server to EDGE which executes tcl commands sent from external clients.

What it does

The remote commanding server is a way to remotely command tcl procedures over the network. Since EDGE is fully scriptable via tcl throughout (almost ever menu action and dialog is done via tcl), this allows almost anything to be done remotely and gives maximum flexibility without requiring a command language.

For example, the doug.node command allows you to do extensive operations on a node, both reading and writing to its state. With this server, someone could open a socket over the network and send a doug.node command directly to it in plain ascii.

This is a great solution for situations where you need to command something on an instance of EDGE that is not maintained by the node tree - such as camera assignments. This would be a great tool to remotely assign cameras to views, bring up and down overlays remotely, trigger scripts from a remote machine, etc.

Limitations

Since it may not be safe to open a socket and execute untrusted strings blindly, the remote commanding server uses a safe slave tcl interpreter which has many commands removed. We then manually specify what commands we want to allow.

By default, all of the doug.* commands are allowed, along with some others. The important note here is that the user can add on to the list of allowed functions, making them able to write procedures that cannot be called remotely, and if they so choose, also specify the alias for remote access. This is done in the file specified by the env variable "RCS_USER_PROC_ALLOW". The syntax that should be used in this file can be found in "gui/remote_commanding_proc_allow.tcl".

Also, it should be noted that this shouldn't be used for high data rate applications. If you are doing cyclically faster than approx 1 Hz, you should probably consider another data path.

Instructions

  1. Run EDGE

    • Server included in EDGE 2.1 and later
    • Runs upon executing run_graphics
    • Host name and port number of EDGE Server is printed to terminal
    • There is also a gui in the options menu labeled as "Remote Commanding" which will show you what port the server is on, along with other information
    • Default port number is 5451
    • If port 5451 is unavailable, the port number will increment until an available port number is found
  2. Make a Client

    • Write your own client code or use/modify client source code included in the distribution under "src.dist/scripts"
  3. Run the client and connect to a running copy of EDGE

    • The client basically implements the following algorithm:
      • Connect to socket
      • Read off of socket until hitting ascii character 4 (End of Transmission). This first message is the version of the remote commanding server in "YYMMDD" format. Use it to check compatibility with your clients if you need to
      • Send command to socket. The command should not be very long. Consider writing a tcl procedure that is exposed remotely and calling it if you need to send a large string.
      • Read off of socket until hitting ascii character 4 (End of Transmission). This is the result of the command.
      • Close socket. Most of our clients typically open a connection, send their command, then close the socket rather than remaining connected.

Example

An example of using a client to execute Doug commands remotely. (some source included below - refer to src.dist/scripts for example clients)

  1. Run Server
    • Load EDGE and look for host name and port number in EDGE Terminal

  1. Make a Client
    • Source code that creates a simple GUI to connect and send commands to the EDGE Server:

remote_commanding_client.tcl

#!/usr/bin/wish

# The minimum rcs version this script requires
set min_rcs_version 100218

# Function to read a message from the remote commanding server.  See
# usage below.
proc read_rcs_response { rcs_socket } {
    set incoming_char ""
    set more_to_read 1
    set rcs_response ""

    while { $more_to_read } {
        set incoming_char [read $rcs_socket 1]
        scan $incoming_char %c ascii_value
        if { $ascii_value != 4 } {
            set rcs_response ${rcs_response}${incoming_char}
        } else {
            set more_to_read 0
        }
    }
    return $rcs_response
}

# Function to open up a socket and send over a single command
proc send_rcs_command { server_host server_port cmd_string } {
     global min_rcs_version

     # Attempt to connect to EDGE Server and either print error message 
     #or print the connection message sent from server
     set ret [catch { set sockChan [socket $server_host $server_port] } sock_var ]
     if { $ret != 0 } {
          puts "Connection failed\:\nSpecify the correct host and port.\n"
          puts "These options may be entered upon command line execution as\:"
          puts "\t<script> host port\n"
          return

     } else {
          set rcs_version [read_rcs_response $sockChan]
          puts "EDGE Remote commanding server version: $rcs_version"
          if { $rcs_version < $min_rcs_version } {
              puts "Compatible: No"
              puts "ERROR: This client only works with RCS version > $min_rcs_version"
              close $sockChan
              exit
          }
          puts "Compatible: Yes!"
          puts ""
     }

     puts $sockChan $cmd_string
     flush $sockChan
     set cmd_result [read_rcs_response $sockChan]

     # Disconnect from EDGE Remote Server
     close $sockChan

     return $cmd_result
}


# Function called when GUI button is pushed - connects to EDGE Server 
# and sends Doug Commands to be evaluated
proc push_button { } {

     # Call global command line variables
     global argc ; # tcl variable representing the number of command line arguments
     global argv ; # tcl variable containing command line arguments

     # If command line arguments given, define them as host and port; 
     # otherwise use this computer's hostname and port 5451
     if { $argc == 2 } {
          set server_host [lindex $argv 0]
          set server_port [lindex $argv 1]
          puts "\nAttempting to connect to:\n\tHost: $server_host\n\tPort: $server_port\n"

     } else {
          set server_host [info hostname]
          set server_port 5451
          puts "\nAttempting to connect to:\n\tHost: $server_host\n\tPort: $server_port\n"
          puts "To use a different host and\/or port, rerun this script as follows\:"
          puts "\t<script> host port\n"
     }

     # Read commands from GUI entry boxes and send to EDGE Server
     global string_ent
     set command_count 0
     foreach strg $string_ent {
          set string_init [.ent$command_count get]
          puts "Command: $string_init"
          set command_result [send_rcs_command $server_host $server_port $string_init]
          puts "Result : $command_result"
          puts ""
          incr command_count
     }
}


# Initialize and define variables
global string_ent
set string_ent [list]
set command_count 0

####### Write default GUI strings into list "string_ent" - these will 
####### be sent to EDGE server and evaluated in EDGE
lappend string_ent {doug.scene get -cameras}
#lappend string_ent {doug.node "ALPHA_PORT" set -flags HIDE}
lappend string_ent {puts "hello world"}
#lappend string_ent {}
#lappend string_ent {}

####### Make GUI button to run function "push_button"
button .but -text "Push to Send Commands to EDGE Remote Server" -command "push_button"
pack .but

####### Make a GUI entry box for each line defined in list "string_ent"
foreach strg $string_ent {
     entry .ent$command_count -width 80
     .ent$command_count insert 0 [lindex ${string_ent} $command_count]
     pack .ent$command_count
     incr command_count
}

: * The resulting GUI:

  1. Run the client and connect to server
    • Example source code has a command line option to specify the EDGE Server host name and port number

  • For this GUI, simple push the button at the top. The result of the command execution will be printed in the terminal that the client was started in.
  • See "Example Commands" Section below for command results

Some ideas/examples on how to use the capability

  1. Ask EDGE to return a list of the cameras

Command ("doug.scene get -cameras"):

Result - EDGE output returned to client:

  1. Command Doug to hide the "ALPHA_PORT" node in the scene

Command (doug.node ALPHA_PORT set -flags HIDE):

Result - AlPHA_PORT node image is removed from the scene:

  1. Command the script plugin to execute an entry in the reconfig menu:

Command (doug.plugin script.run "ARRAYS_DEPLOY→ON"):

> ./doug_command_client localhost 5451 doug.plugin script.run "ARRAYS_DEPLOY->ON"
Command sent successfully.
RCS Version: 100312
Command result:

Result - CM solar array deploy reconfig is activated

Command Grouping

Sometimes when creating a gui or overlay or something that needs to collect data over remote commanding, a user has to walk through many commands to get all of the data they want. For example, they may have an overlay and need to collect:

  • the xyz of a node
  • the PYR of a different node
  • the current framerate
  • the current time
  • etc.

This normally requires a sequence of commands to get all the data. Command grouping provides the capability to define all these commands into a group and then have the capability to "dump" a particular group with a single command, returning all the data back in one shot. You can use following tcl commands to do this:

# Returns a list of the current group ids
proc list_command_groups { }

# Creates a new empty command group
# Returns the group id of the newly created group
proc create_command_group { } 

# Appends a command to an existing group
# Returns:
#  >0: the new number of commands in the group
#  -1: specified groupid does not exist 
proc add_command_to_group { groupid cmd_string }

# Removes the command at the specifed index from an existing group
# Returns:
#  >0: the new number of commands in the group
#  -1: specified groupid does not exist
#  -2: specified cmd_index does not exist
proc remove_command_from_group { groupid cmd_index }

# Returns a list of commands in a group
#  -1: specified groupid does not exist
proc get_command_group { groupid }

# Fires the commands in a command group
# Returns:
#  list of resulta/error messagess from each command execution
#  -1: specified groupid does not exist
proc execute_command_group { groupid }

More info

There are many doug.* commands available. See the EDGE Tcl Commands page for more details.

« Using DNS Service Discovery | EDGE User’s Guide | Web Commanding Capability »

⚠️ **GitHub.com Fallback** ⚠️