//----------------------------------------------------------------------------- // 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;