Telnet server

Top  Previous  Next

//-----------------------------------------------------------------------------
// Telnet.vpl, created 2003-03-04 20:05
//
// This is a VERY simple telnet server. It has only a few commands, but still
// shows how to establish a TCP/IP connection. The demo requires that the 
// RTCU unit has a GLOBAL accessible IP address on the internet ! When a Telnet
// client connects to the RTCU, a welcome message is shown, together with a 
// prompt, where the telnet client then can enter commands. The following commnds
// are available: input, on n, off n, quit and help. Input will show the state
// of 4 digital inputs, on/off n will switch digital output n to either on or off
// state, quit will close the connection, and help will show a list of available
// commands.
//-----------------------------------------------------------------------------
INCLUDE rtcu.inc
 
//  Input variables that can be configured via the configuration dialog (These are global)
VAR_INPUT
   Din : ARRAY[1..4] OF BOOL; | Digital inputs (can be read with "input" command)
END_VAR;
 
//  Output variables that can be configured via the configuration dialog (These are global)
VAR_OUTPUT
   LED    : bool; | LED that shows the program scan
   Dout   : ARRAY[1..4] OF BOOL; | Digital outputs (can be set with the "on"/"off" commands)
END_VAR;
 
//  These are the global variables of the program
VAR
   sockrcv  : sockReceive;    // Receives data on a TCP/IP socket
   soccon   : sockConnection; // Manages a TCP/IP connection
   id       : SINT;           // TCP/IP connection id
   rxbuf    : ARRAY[0..512] OF SINT; // Receive buffer for TCP/IP data
   txbuf    : ARRAY[0..512] OF SINT; // Transmit buffer for TCP/IP data
   i        : INT;                   // Temporary variable
   str      : STRING;                // Temporary variable
   extract  : strGetValues;          // Matching of commandstrings
   PartialCommand  : STRING;         // Characters on TCP/IP socket gets assembled in this
   Command  : STRING;                // Final command received (after CR)
   listenport : SINT:=23;            // Which port to listen on (port 23=standard Telnet port)
END_VAR;
 
 
//---------------------------------------------------------------------------
// Send a STRING on a TCP/IP connection
//---------------------------------------------------------------------------
FUNCTION SendData;
VAR_INPUT
   id  : SINT;
   str : STRING;
END_VAR
VAR
   txbuf : ARRAY[0..100] OF SINT;
END_VAR;
   strToMemory(dst:=ADDR(txbuf), str:=str, len:=strLen(str:=str));
   DebugFmt(message:="sockSend=\1", v1:=sockSend(id:=id, data:=ADDR(txbuf), size:=strLen(str:=str)));
END_FUNCTION;
 
 
//---------------------------------------------------------------------------
// Start at TCP/IP socket listen on a specified port
// (and update the sockConnection() and sockReceive() functionblocks)
//---------------------------------------------------------------------------
FUNCTION StartListen;
   // Start listener on port
   id:=sockListen(port:=listenport);
   DebugFmt(message:="socListen()=\1",v1:=id);
   
   // Update id for sockConnection() and sockReceive()
   soccon(id:=id);
   sockrcv(id:=id,data:=ADDR(rxbuf),MaxSize:=SIZEOF(rxbuf));
END_FUNCTION;
 
 
//---------------------------------------------------------------------------
// Main program
//---------------------------------------------------------------------------
PROGRAM Telnet;
 
// Switch on power to the Cellular module
gsmPower(power:=TRUE);
 
// Open the Cellular network connection (connects the RTCU unit to the Internet)
DebugFmt(message:="netOpen()=\1",v1:=netOpen(iface:=_NET_IFACE_CELLULAR));
 
// Wait for connection to the Internet
// (This is actually not needed, as the sockListen() can be called before
// the connection is established)
WHILE NOT netConnected(iface:=_NET_IFACE_CELLULAR) DO
   DebugMsg(message:="Waiting for Cellular network connection");
   Sleep(delay:=3000);
END_WHILE;
 
// Show our assigned IP address (this is the one the telnet client should connect to)
DebugMsg(message:=strConcat(str1:="My IP Address=",str2:=sockIPToName(ip:=sockGetLocalIP())));
 
// Start listening for TCP/IP connects on the Telnet port (port 23)
StartListen();
 
BEGIN
  soccon();  // Update status for sockConnection() functionblock
  sockrcv(); // Update status for sockReceive() functionblock
 
  // Connection status changed (someone connected or disconnected)
  IF soccon.changed THEN
     // Someone just connected to us...
     IF soccon.Connected THEN
        DebugMsg(message:=strConcat(str1:=sockIPToName(ip:=soccon.remoteip), str2:=" has connected"));
        SendData(id:=id, str:="Welcome to the RTCU Telnet Server.$N$N");
        SendData(id:=id, str:="Available commands:$N");
 
        SendData(id:=id, str:="  <input> : Show status of digital inputs$N");
        SendData(id:=id, str:="  <on n>  : Set digital output n to ON$N");
        SendData(id:=id, str:="  <off n> : Set digital output n to OFF$N");
        SendData(id:=id, str:="  <quit>  : Close connection$N");
        SendData(id:=id, str:="  <help>/<?> : Show available commands$N");
       
        SendData(id:=id, str:="$NEnter command> ");
     // Someone disconnected    
     ELSE
        DebugMsg(message:=strConcat(str1:=sockIPToName(ip:=soccon.remoteip), str2:=" is disconnecting !"));
        // Disconnect socket
        sockDisconnect(id:=id);
        // and start listening again
        StartListen();
     END_IF;
  END_IF;
 
 
  // We have received some data...
  IF sockrcv.ready THEN
     DebugFmt(message:="socket data received len=\1",v1:=sockrcv.size);
     // Echo the received data
     DebugFmt(message:="sockSend=\1", v1:=sockSend(id:=id, data:=addr(rxbuf), size:=sockrcv.size));
     // Convert the received data to a string
     str:=strFromMemory(src:=ADDR(rxbuf), len:=sockrcv.size);
     DebugMsg(message:=str);
 
     // concatenate the received data to command string
     PartialCommand:=strConcat(str1:=PartialCommand, str2:=str);
     // If there is a Carriage return in the string...
     i:=strFind(str1:=PartialCommand, str2:="$R");
     IF i>0 THEN
        // We now have a complete command assembled in PartialCommand
        Command:=strLeft(str:=PartialCommand, length:=i-1);
        DebugMsg(message:=strConcat(str1:="Command=", str2:=Command));
        PartialCommand:="";
 
        // Check if it is a "QUIT" command (No prompt sent if it's quit)
        IF strCompare(str1:="QUIT", str2:=Command)=0 THEN
           SendData(id:=id, str:="$NGoodbye.$N");
           
           // Disconnect socket
           // (Note: this will NOT activate a soccon.changed, as it is "ourself" who has disconnected !)
           sockDisconnect(id:=id);
           // and start listening again
           StartListen();
        // Check for other commands   
        ELSE
           // Check if it is a "ON" command
           extract(format:="ON \1", str:=Command);
           IF extract.match AND extract.v1 >= 1 AND extract.v1 <= 8 THEN
             DOut[extract.v1] := ON;
             str:=strFormat(format:="Setting output \1 to ON", v1:=extract.v1);
             DebugMsg(message:=str);
             SendData(id:=id, str:=strConcat(str1:=str, str2:="$N"));
           END_IF;
        
           // Check if it is a "OFF" command
           extract(format:="OFF \1", str:=Command);
           IF extract.match AND extract.v1 >= 1 AND extract.v1 <= 8 THEN
             Dout[extract.v1] := OFF;
             str:=strFormat(format:="Setting output \1 to OFF", v1:=extract.v1);
             DebugMsg(message:=str);
             SendData(id:=id, str:=strConcat(str1:=str, str2:="$N"));
           END_IF;
            
           // Check if it is a "INPUT" command 
           IF strCompare(str1:="INPUT", str2:=Command)=0 THEN
              FOR i:=1 TO 4 DO
                 str:=strFormat(format:="$NInput \1 is \2", v1:=i, v2:=INT(Din[i]));
                 SendData(id:=id, str:=str);
              END_FOR;
           END_IF;            
 
           // Check if it is a "HELP"/"?" command 
           IF strCompare(str1:="HELP", str2:=Command)=0 OR
              strCompare(str1:="?", str2:=Command)=0 THEN
              SendData(id:=id, str:="Available commands:$N");
              SendData(id:=id, str:="  <input> : Show status of digital inputs$N");
              SendData(id:=id, str:="  <on n>  : Set digital output n to ON$N");
              SendData(id:=id, str:="  <off n> : Set digital output n to OFF$N");
              SendData(id:=id, str:="  <quit>  : Close connection$N");
              SendData(id:=id, str:="  <help>/<?> : Show available commands$N");
           END_IF;            
           // Send a new prompt 
           SendData(id:=id, str:="$NEnter command> ");           
        
        END_IF;
        
        
     END_IF;
  END_IF;
 
  Sleep(delay:=50);
  // Update the LED
  LED:=NOT LED;
END;
END_PROGRAM;