]> git.mxchange.org Git - flightgear.git/commitdiff
Add some example remote controll scripts
authorehofman <ehofman>
Tue, 10 Feb 2004 15:35:48 +0000 (15:35 +0000)
committerehofman <ehofman>
Tue, 10 Feb 2004 15:35:48 +0000 (15:35 +0000)
scripts/example/.cvsignore [new file with mode: 0644]
scripts/example/Makefile.am [new file with mode: 0644]
scripts/example/fgfsclient.c [new file with mode: 0644]
scripts/example/fgfsclient.cxx [new file with mode: 0644]
scripts/example/fgfsscript [new file with mode: 0644]
scripts/example/remote.html [new file with mode: 0644]

diff --git a/scripts/example/.cvsignore b/scripts/example/.cvsignore
new file mode 100644 (file)
index 0000000..282522d
--- /dev/null
@@ -0,0 +1,2 @@
+Makefile
+Makefile.in
diff --git a/scripts/example/Makefile.am b/scripts/example/Makefile.am
new file mode 100644 (file)
index 0000000..6f18c49
--- /dev/null
@@ -0,0 +1 @@
+EXTRA_DIST = fgfsclient.c fgfsclient.cxx fgfsscript remote.html
diff --git a/scripts/example/fgfsclient.c b/scripts/example/fgfsclient.c
new file mode 100644 (file)
index 0000000..820d287
--- /dev/null
@@ -0,0 +1,151 @@
+/* $Id$ */
+/* gcc -O2 -g -pedantic -Wall fgfsclient.c -o fgfsclient */
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <stdarg.h>
+#include <string.h>
+
+
+#define DFLTHOST       "localhost"
+#define DFLTPORT       5501
+#define MAXMSG         256
+#define fgfsclose      close
+
+
+void init_sockaddr(struct sockaddr_in *name, const char *hostname, unsigned port);
+int fgfswrite(int sock, char *msg, ...);
+const char *fgfsread(int sock, int wait);
+void fgfsflush(int sock);
+
+
+
+int fgfswrite(int sock, char *msg, ...)
+{
+       va_list va;
+       ssize_t len;
+       char buf[MAXMSG];
+
+       va_start(va, msg);
+       vsprintf(buf, msg, va);
+       va_end(va);
+       printf("SEND: \t<%s>\n", buf);
+       strcat(buf, "\015\012");
+
+       len = write(sock, buf, strlen(buf));
+       if (len < 0) {
+               perror("fgfswrite");
+               exit(EXIT_FAILURE);
+       }
+       return len;
+}
+
+
+
+const char *fgfsread(int sock, int timeout)
+{
+       static char buf[MAXMSG];
+       char *p;
+       fd_set ready;
+       struct timeval tv;
+       ssize_t len;
+
+       FD_ZERO(&ready);
+       FD_SET(sock, &ready);
+       tv.tv_sec = timeout;
+       tv.tv_usec = 0;
+       if (!select(32, &ready, 0, 0, &tv))
+               return NULL;
+
+       len = read(sock, buf, MAXMSG - 1);
+       if (len < 0) {
+               perror("fgfsread");
+               exit(EXIT_FAILURE);
+       } 
+       if (len == 0)
+               return NULL;
+
+       for (p = &buf[len - 1]; p >= buf; p--)
+               if (*p != '\015' && *p != '\012')
+                       break;
+       *++p = '\0';
+       return strlen(buf) ? buf : NULL;
+}
+
+
+
+void fgfsflush(int sock)
+{
+       const char *p;
+       while ((p = fgfsread(sock, 0)) != NULL) {
+               printf("IGNORE: \t<%s>\n", p);
+       }
+}
+
+
+
+int fgfsconnect(const char *hostname, const int port)
+{
+       struct sockaddr_in serv_addr;
+       struct hostent *hostinfo;
+       int sock;
+
+       sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+       if (sock < 0) {
+               perror("fgfsconnect/socket");
+               return -1;
+       }
+
+       hostinfo = gethostbyname(hostname);
+       if (hostinfo == NULL) {
+               fprintf(stderr, "fgfsconnect: unknown host: \"%s\"\n", hostname);
+               close(sock);
+               return -2;
+       }
+
+       serv_addr.sin_family = AF_INET;
+       serv_addr.sin_port = htons(port);
+       serv_addr.sin_addr = *(struct in_addr *)hostinfo->h_addr;
+
+       if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
+               perror("fgfsconnect/connect");
+               close(sock);
+               return -3;
+       }
+       return sock;
+}
+
+
+
+int main(int argc, char **argv)
+{
+       int sock;
+       unsigned port;
+       const char *hostname, *p;
+
+       hostname = argc > 1 ? argv[1] : DFLTHOST;
+       port = argc > 2 ? atoi(argv[2]) : DFLTPORT;
+
+       sock = fgfsconnect(hostname, port);
+       if (sock < 0)
+               return (EXIT_FAILURE);
+
+       fgfswrite(sock, "data");
+       fgfswrite(sock, "set /controls/engines/engine[%d]/throttle %d", 0, 1);
+       fgfswrite(sock, "get /sim/aircraft");
+       p = fgfsread(sock, 3);
+       if (p != NULL)
+               printf("READ: \t<%s>\n", p);
+       fgfswrite(sock, "quit");
+       fgfsclose(sock);
+       return EXIT_SUCCESS;
+}
+
+
diff --git a/scripts/example/fgfsclient.cxx b/scripts/example/fgfsclient.cxx
new file mode 100644 (file)
index 0000000..fa4012f
--- /dev/null
@@ -0,0 +1,181 @@
+// $Id$
+// g++ -O2 -g -pedantic -Wall fgfsclient.cxx -o fgfsclient -lstdc++
+
+#include <errno.h>
+#include <iostream>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <string.h>
+
+const int maxlen = 256;
+
+
+class FGFSSocket {
+       int             sock;
+       bool            connected;
+       unsigned        timeout;
+    public:
+                       FGFSSocket(const char *name, const unsigned port);
+                       ~FGFSSocket() { close(); };
+
+       int             write(const char *msg, ...);
+       const char      *read(void);
+       inline void     flush(void);
+       void            settimeout(unsigned t) { timeout = t; };
+    private:
+       int             close(void);
+};
+
+
+FGFSSocket::FGFSSocket(const char *hostname = "localhost", const unsigned port = 5501)
+       :
+       sock(-1),
+       connected(false),
+       timeout(1)
+{
+       sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+       if (sock < 0)
+               throw("FGFSSocket/socket");
+
+       struct hostent *hostinfo;
+       hostinfo = gethostbyname(hostname);
+       if (!hostinfo) {
+               close();
+               throw("FGFSSocket/gethostbyname: unknown host");
+       }
+
+       struct sockaddr_in serv_addr;
+       serv_addr.sin_family = AF_INET;
+       serv_addr.sin_port = htons(port);
+       serv_addr.sin_addr = *(struct in_addr *)hostinfo->h_addr;
+
+       if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
+               close();
+               throw("FGFSSocket/connect");
+       }
+       connected = true;
+       try {
+               write("data");
+       } catch (...) {
+               close();
+               throw;
+       }
+}
+
+
+int FGFSSocket::close(void)
+{
+       if (connected)
+               write("quit");
+       if (sock < 0)
+               return 0;
+       int ret = ::close(sock);
+       sock = -1;
+       return ret;
+}
+
+
+int FGFSSocket::write(const char *msg, ...)
+{
+       va_list va;
+       ssize_t len;
+       char buf[maxlen];
+       fd_set fd;
+       struct timeval tv;
+
+       FD_ZERO(&fd);
+       FD_SET(sock, &fd);
+       tv.tv_sec = timeout;
+       tv.tv_usec = 0;
+       if (!select(FD_SETSIZE, 0, &fd, 0, &tv))
+               throw("FGFSSocket::write/select: timeout exceeded");
+
+       va_start(va, msg);
+       vsprintf(buf, msg, va);
+       va_end(va);
+       std::cout << "SEND: " << buf << std::endl;
+       strcat(buf, "\015\012");
+
+       len = ::write(sock, buf, strlen(buf));
+       if (len < 0)
+               throw("FGFSSocket::write");
+       return len;
+}
+
+
+const char *FGFSSocket::read(void)
+{
+       static char buf[maxlen];
+       char *p;
+       fd_set fd;
+       struct timeval tv;
+       ssize_t len;
+
+       FD_ZERO(&fd);
+       FD_SET(sock, &fd);
+       tv.tv_sec = timeout;
+       tv.tv_usec = 0;
+       if (!select(FD_SETSIZE, &fd, 0, 0, &tv)) {
+               if (timeout == 0)
+                       return 0;
+               else
+                       throw("FGFSSocket::read/select: timeout exceeded");
+       }
+
+       len = ::read(sock, buf, maxlen - 1);
+       if (len < 0)
+               throw("FGFSSocket::read/read");
+       if (len == 0)
+               return 0;
+
+       for (p = &buf[len - 1]; p >= buf; p--)
+               if (*p != '\015' && *p != '\012')
+                       break;
+       *++p = '\0';
+       return strlen(buf) ? buf : 0;
+}
+
+
+inline void FGFSSocket::flush(void)
+{
+       int i = timeout;
+       timeout = 0;
+       while (read())
+               ;
+       timeout = i;
+}
+
+
+int main(const int argc, const char *argv[])
+try {
+       const char *hostname = argc > 1 ? argv[1] : "localhost";
+       int port = argc > 2 ? atoi(argv[2]) : 5501;
+
+       FGFSSocket f(hostname, port);
+       f.flush();
+       f.write("set /controls/engines/engine[%d]/throttle %lg", 0, 1.0);
+       f.write("set /controls/engines/engine[%d]/throttle %lg", 1, 1.0);
+       f.write("get /sim/aircraft");
+       const char *p = f.read();
+       if (p)
+               std::cout << "RECV: " << p << std::endl;
+       return 0;
+
+} catch (const char s[]) {
+       std::cerr << "Error: " << s << ": " << strerror(errno) << std::endl;
+       return -1;
+
+} catch (...) {
+       std::cerr << "Error: unknown exception" << std::endl;
+       return -1;
+}
+
+
+// vim:cindent
diff --git a/scripts/example/fgfsscript b/scripts/example/fgfsscript
new file mode 100644 (file)
index 0000000..0357253
--- /dev/null
@@ -0,0 +1,95 @@
+#!/usr/bin/perl -w
+# USAGE: fgfsscript [host [port]]
+# Melchior FRANZ, a8603365@unet.univie.ac.at
+# $Id$
+
+use strict;
+use IO::Socket;
+
+my $host = (shift || 'localhost');
+my $port = (shift || 5501);
+my ($fgfs, $i);
+
+
+
+# main()
+{
+       chdir;
+       $fgfs = &connect($host, $port, 120) || die " can't open socket\n";
+       &send("data");
+
+       # wait for random altitude (0--3000 ft.) to be reached
+       my $alt = int(rand(3000));
+       print "disaster begins at $alt ft. AGL\n";
+       while (1) {
+               sleep(1);
+               $i = &get("/position/altitude-agl-ft");
+               print "\r" . int($i) . " ft.";
+               print "\n" and last if $i > $alt;
+       }
+
+       print "start fuel dumping  :-)\n";
+       for ($i = 0; $i < 4; $i++) {
+               sleep(rand(60));
+               &set("/consumables/fuel/tank[$i]/level-gal_us", 0);
+               print "tank $i empty\n";
+       }
+       
+       &send("quit");
+       close $fgfs;
+}
+
+
+
+
+sub get()
+{      
+       &send("get " . shift);
+       eof $fgfs and die "\nconnection closed by host";
+       $_ = <$fgfs>;
+       s/\015?\012$//;
+       /^-ERR (.*)/ and die "\nfgfs error: $1\n";
+       return $_;
+}
+
+
+sub set()
+{      
+       my $prop = shift;
+       my $value = shift;
+       &send("set $prop $value");
+}
+
+
+sub send()
+{      
+       print $fgfs shift, "\015\012";
+}
+
+
+sub connect()
+{
+       my $host = shift;
+       my $port = shift;
+       my $timeout = (shift || 120);
+       my $socket;
+       STDOUT->autoflush(1);
+       print "connect ";
+       while ($timeout--) {
+               if ($socket = IO::Socket::INET->new(
+                               Proto => 'tcp',
+                               PeerAddr => $host,
+                               PeerPort => $port)) {
+                       print ".. done.\n";
+                       $socket->autoflush(1);
+                       sleep 1;
+                       return $socket;
+               }       
+               print ".";
+               sleep(1);
+       }
+               return 0;
+}
+
+
+# vi:ts=8:sw=8:noet:nowrap:cindent
diff --git a/scripts/example/remote.html b/scripts/example/remote.html
new file mode 100644 (file)
index 0000000..133b31c
--- /dev/null
@@ -0,0 +1,133 @@
+<html>
+<head>
+       <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+       <title>FlightGear: Remote control</title>
+       <meta name="Author" content="Melchior FRANZ">
+       <meta name="KeyWords" content="flightgear,fgfs,flightsimulator,simulator,remote,control,perl,c,c++">
+       <link rel="StyleSheet" type="text/css" href="fgfs.css">
+       <link rel="SHORTCUT ICON" href="mf.ico">
+
+</head>
+
+<body>
+<h1>FlightGear: Remote control</h1>
+
+
+<p>FlightGear has several interfaces that provide access to internal
+parameters. The HTTP interface is best suited for human interaction
+via a web browser. The telnet interface is the ideal choice for
+remotely controlling FlightGear by means of external programs.
+</p>
+
+<p>To activate FlightGear's telnet server capabilities, call it with
+a <em>--props</em> specifiaction:
+
+<blockquote>
+<pre>
+$ fgfs --props=socket,bi,5,localhost,5501,tcp
+</pre>
+
+<br>
+<br>
+<table>
+<tr><td><strong>socket:</strong></td><td>FlightGear protocol</td></tr>
+<tr><td><strong>bi:</strong></td><td>bidirectional</td></tr>
+<tr><td><strong>5:</strong></td><td>polling frequency in Hertz</td></tr>
+<tr><td><strong>localhost: </strong></td><td>server name or IP-address</td></tr>
+<tr><td><strong>5501: </strong></td><td>server port</td></tr>
+<tr><td><strong>tcp:</strong></td><td>internet protocol type</td></tr>
+</table>
+</blockquote>
+
+<br>
+<br>
+In newer versions of FlightGear just type:
+<blockquote>
+<pre>
+$ fgfs --telnet=5501
+</pre>
+</blockquote>
+</p>
+
+<p>To learn more about the supported commands, connect to FlightGear
+with a telnet program and type in "help&lt;RETURN&gt;". This is what you'll get:<p>
+
+<blockquote>
+<pre>
+$ telnet localhost 5501
+Trying ::1...
+Trying 127.0.0.1...
+Connected to localhost.
+Escape character is '^]'.
+help
+
+Valid commands are:
+
+help             show help message
+ls [&lt;dir&gt;]       list directory
+dump             dump current state (in xml)
+cd &lt;dir&gt;         cd to a directory, '..' to move back
+pwd              display your current path
+get &lt;var&gt;        show the value of a parameter
+show &lt;var&gt;       synonym for get
+set &lt;var&gt; &lt;val&gt;  set &lt;var&gt; to a new &lt;val&gt;
+data             switch to raw data mode
+prompt           switch to interactive mode (default)
+quit             terminate connection
+
+/&gt;
+</pre>
+</blockquote>
+
+<p>Now you can browse in the property system like in a Linux file
+system with <em>cd, ls, pwd</em>.</p>
+
+
+
+
+<p>Here you can <a href="fgfsscript">download a sample script</a> 
+written in Perl, that shows how to access and manipulate FlightGear's
+internal parameters. It can be started before FlightGear (in which
+case it tries up to 2&nbsp;minutes to connect) or afterwards. Then
+it picks a random AGL altitude and checks every 5&nbsp;seconds
+if the aircraft has already climbed at this height. Now it starts
+to empty all four tanks, one after the other, until the engines
+stop working. Try to find a place where you can land safely. :-)</p>
+
+<blockquote>
+<pre>
+$ fgfsscript&amp;
+$ fgfs --props=socket,bi,5,localhost,5501,tcp
+</pre>
+</blockquote>
+
+<p>The script defaults to <em>localhost</em> and <em>port 5501</em>,
+but you can let the script control FlightGear on another host and
+under another port.</p>
+
+<blockquote>
+<pre>
+$ fgfsscript some.host.org 1234&amp;
+</pre>
+</blockquote>
+
+
+<p>Demo programs are available in:<br>
+<ul>
+<li><a href="fgfsclient.c">C</a></li>
+<li><a href="fgfsclient.cxx">C++</a></li>
+<li><a href="fgfsscript">Perl (same as mentioned above)</a></li>
+</ul>
+</p>
+
+
+<br>
+<hr>
+<address>
+$Id$<br>
+<a href="http://www.unet.univie.ac.at/~a8603365/">Melchior FRANZ</a>
+(mfranz at aon dot at</a>)
+</address>
+
+</body>
+</html>