Examples - 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 device 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 GSM module
gsmPower(power:=TRUE);
// Open the GPRS connection (connects the RTCU device to the Internet)
DebugFmt(message:="gprsOpen()=\1",v1:=gprsOpen());
// Wait for connection to the Internet
// (This is actually not needed, as the sockListen() can be called before
// the connection is established)
WHILE NOT gprsConnected() DO
  DebugMsg(message:="Waiting for cellular 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;