Home AMX User Forum AMXForums Archive Threads Tips and Tricks

Telnet server

I was frustrated with trying to use the unreliable G3 browser control for remote admin / testing / config so I decided to build a command line server.

This code is a "telnet server" in the form of an include. It won't compile as is because it uses my code infrastructure, you'll have to modify it to yours.

It just listens for an incoming IP connection on a given port and replies to or acts upon text received. Note that you need to use a telnet client in which you can specify the port.

I'm not sure how robust this is yet, comments welcome.
(*** iTelnetServer.axi ***)

(******************************************************************************)
define_device
(******************************************************************************)

dTelnetServer                                    = 0:3:0

(******************************************************************************)
define_variable
(******************************************************************************)

volatile char    sTelnetServerBuffer[1000]       = ''
volatile integer bTelnetServerOpen               = False
volatile integer bTelnetServerOnline             = False
volatile integer nTelnetServerPort               = 8001

(******************************************************************************)
define_function TelnetSend             (
  char    sArgString[]                 )
(******************************************************************************)
{
send_string dTelnetServer,"sArgString,cCR,cLF"
} (* TelnetSendMessage *)

(******************************************************************************)
define_function integer TelnetServerOpen(
  dev     dArgDevice                   ,
	integer nArgPort                     )
(******************************************************************************)
{
stack_var integer nMyResult
stack_var integer bMyServerOpen

nMyResult                                        = type_cast(ip_server_open(dTelnetServer.Port,nArgPort,ip_tcp) * -1)

switch (nMyResult)
  {
  case 0: 
    {
    Debug('OpenTelnetServer successful')
    bMyServerOpen                                = True
    }
		
  case 1: 
    {
    Error('OpenTelnetServer invalid server port')
    bMyServerOpen                                = False
    }
		
  case 2: 
    {
    Error('OpenTelnetServer invalid value for Protocol')
    bMyServerOpen                                = False
    }
	
  case 3: 
    {
    Error('OpenTelnetServer unable to open communication port')
    bMyServerOpen                                = False
    }
	
  default: 
    {
    ErrorNumber('OpenTelnetServer unknown result',nMyResult)
    bMyServerOpen                                = False
    }
  }
	
return bMyServerOpen;
} (* TelnetServerOpen *)

(******************************************************************************)
(*
Handle string on incoming telnet session
*)
define_function HandleTelnetServerBuffer()
(******************************************************************************)
{
stack_var char    sMyString[1000]
stack_var char    sMyTerminator[10]
stack_var char    sMyTokens[100][100]
stack_var integer nMyTokenCount

DebugHex('HandleTelnetServerBuffer',sTelnetServerBuffer)

sMyTerminator                                      = "cLF"

while (find_string(sTelnetServerBuffer,sMyTerminator,1))
  {
  DebugHex('Terminator',sTelnetServerBuffer)
	
  sMyString                                        = remove_string(sTelnetServerBuffer,sMyTerminator,1)
  sMyString                                        = TruncateString(sMyString) (* Ditch trailing whitespace, CR, LF *)
	
  while (length_string(sMyString) > 0)
    {
    nMyTokenCount++
    sMyTokens[nMyTokenCount]                       = RemoveString(sMyString,' ')
    }
  
  sMyTokens[1]                                     = upper_string(sMyTokens[1])
	
  DebugHex('Token',sMyTokens[1])
			
  (* First token is the keyword *)
  switch (sMyTokens[1])
    {
    case 'HELLO':
      {
      TelnetSend('How the heck are you?')
      }
			
    case 'REBOOT': 
      {
      TelnetSend('Rebooting')
      RebootController()
      }
	
    default:
      {
      DebugHex('Unknown keyword',sMyTokens[1])
      TelnetSend("'Unknown keyword [',sMyTokens[1],']'")
      }				
    }
  }
} (* HandleTelnetServerBuffer *)

(******************************************************************************)
define_event
(******************************************************************************)

data_event[dTelnetServer]
  {
  onerror:
    {
    ErrorNumber('dTelnetServer onerror',type_cast(data.number))
    }

  online:
    {
    Debug('dTelnetServer online')		
    bTelnetServerOnline                              = True
    }
	
  offline:
    {
    Debug('dTelnetServer offline')		
    bTelnetServerOnline                              = False
    }
	
string:
    {
    DebugHex('dTelnetServer string',data.text)
    sTelnetServerBuffer                              = "sTelnetServerBuffer,data.text"
    HandleTelnetServerBuffer()
    }
  }

(******************************************************************************)
define_program
(******************************************************************************)

if (bModuleReady)
  {
  wait nOneMinuteTenths
    {
    if (not bTelnetServerOpen)
      {
      bTelnetServerOpen                            = TelnetServerOpen(dTelnetServer,nTelnetServerPort)
      }
    }
  }

(*** End of iTelnetServer.axi ***)

This may be old hat to some but I was pleased with how easy it was to do!

Comments

  • Joe HebertJoe Hebert Posts: 2,159
    I decided to build a command line server?.I'm not sure how robust this is yet, comments welcome.
    Unless I?m missing your point, one virtual device is all you need to get the job done. The rest is already built into Netlinx. Consider the following:
    DEFINE_DEVICE
    
    vdvCLI	= 33001:1:0	//Virtual Command Line Interpreter
    
    DEFINE_EVENT
    
    DATA_EVENT[vdvCLI] {
       COMMAND: {
          SEND_STRING 0, "'Got your command to ',DATA.TEXT"
       }
       STRING: {
          SEND_STRING 0, "'Got your string: ',DATA.TEXT"
          IF (FIND_STRING(UPPER_STRING(DATA.TEXT),'HELLO',1)) {
    	 SEND_STRING 0, 'Hello to you too'
          }
       }   
    }
    

    Now you just telnet into the NI master, turn on messages with ?msg on?, and SEND_COMMANDs or SEND_STRINGs to your virtual CLI.
    >msg on
    Extended diagnostic information messages turned on.
    >send_command vdvcli, 'Jump in the lake.'
    >(0000245303) Got your command to Jump in the lake.
    send_string vdvcli, 'hello'
    >(0000259360) Got your string: hello
    (0000259360) Hello to you too
    And make sure you say ?hello? to the NI master. :)
  • I guess I was looking for something that could do anything, not just what could be reached via send_commands (etc), plus I wouldn't have to type "send_command etc" all the time.

    So far I have experimentally implemented push, pulse, release, and also get and set for a bunch of regular variables and config variables that I already have in a diagnostics structure which allows me to refer to them by their name in a string.

    I should note that I have more or less given up using NS2 debug cos it's unreliable when you have multiple modules.
  • hi mark, richard here, we met in the Gold Coast.

    i described then what i was doing with my application for all installations.

    basically, every device is described in a text file database.

    i've prepared a masssive arrary of commands for my command line interface.

    also, the system runs scripts similiar to DOS batch files. all script commands are compatible with the command line interface.

    my scripts also store their own local status variables and can use them for compares when the script runs. all devices report to a 'central' variable stack, so the scripts can also get the status of just about every device.

    i've made the commands and variables to be fast indexed/lookup.

    my objective is to do all processing thru scripts. this is close to being achieved after nearly three years of working on the one application.

    the benefits include installing a known and thoroughly tested application, that hopefully only needs to be altered in it's text database and script files, ensuring a robust installation.

    another benefit is to be able to quickly and quietly change functionality, even remotely over the net, without rebooting a system or recompiling and uploading.

    a feature of this system is it contains a full web interface to all devices in the installation. command lines can be executed thru the web interface. lights and audio etc can be controlled (and automatically labelled from the database) from a mobile phone with web access.

    i'm fairly happy now with the end product and willing to brag about it :) . if anyone wants to see the web interface i'll setup a demo link.

    here is some sample text from one of my script files. the DO statement begins the command. DO can be replaced by IF x=y to create a conditional command line.
    do toggle lights bed 2
    do delayscript bed2button3:5

    if light~bed 2 = 0 goto killEnsuite

    do on lights bed 2 ensuite

    do goto endScript

    :killEnsuite

    do off lights bed 2 ensuite

    :endScript

    note the GOTO commands. there is also a GOSUB command to call repeated functions within the script.

    i haven't provided source code samples. the project has become quite massive. it takes a couple of minutes for the controller to fully reboot and reload the application and it's data. a bit longer than usual, but many benefits once the reboot is done. (the compiled source file is over 2MBs).

    i guess some wont agree with me on the taking this path. but i didn't want to rewrite a new application for every customer, so i have tried to create one application that does all.

    so now, i write all my functions to be command line ready. then when a script wants access to something, it's already there.

    more raving then help here i know, but i hope it gives you some food for thought.

    i've setup a link to a demo system webpage if you care to take a look.

    try http://zentra.com.au:888
  • DHawthorneDHawthorne Posts: 4,584
    I've often thought about doing this exact thing - and never took it so far, because I found in most cases using a virtual interface and using "send command" was adequate. However, there is no reason you couldn't make an entire telnet interface to a master that anyone could use, with different access levels and the whole nine yards. I've always thought the approach had a lot of potential.
Sign In or Register to comment.