From b8ac6687196c80e447efbcda04e07180fd799b10 Mon Sep 17 00:00:00 2001
From: ehofman
Date: Tue, 10 Feb 2004 15:35:48 +0000
Subject: [PATCH] Add some example remote controll scripts
---
scripts/example/.cvsignore | 2 +
scripts/example/Makefile.am | 1 +
scripts/example/fgfsclient.c | 151 +++++++++++++++++++++++++++
scripts/example/fgfsclient.cxx | 181 +++++++++++++++++++++++++++++++++
scripts/example/fgfsscript | 95 +++++++++++++++++
scripts/example/remote.html | 133 ++++++++++++++++++++++++
6 files changed, 563 insertions(+)
create mode 100644 scripts/example/.cvsignore
create mode 100644 scripts/example/Makefile.am
create mode 100644 scripts/example/fgfsclient.c
create mode 100644 scripts/example/fgfsclient.cxx
create mode 100644 scripts/example/fgfsscript
create mode 100644 scripts/example/remote.html
diff --git a/scripts/example/.cvsignore b/scripts/example/.cvsignore
new file mode 100644
index 000000000..282522db0
--- /dev/null
+++ b/scripts/example/.cvsignore
@@ -0,0 +1,2 @@
+Makefile
+Makefile.in
diff --git a/scripts/example/Makefile.am b/scripts/example/Makefile.am
new file mode 100644
index 000000000..6f18c49ec
--- /dev/null
+++ b/scripts/example/Makefile.am
@@ -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
index 000000000..820d28730
--- /dev/null
+++ b/scripts/example/fgfsclient.c
@@ -0,0 +1,151 @@
+/* $Id$ */
+/* gcc -O2 -g -pedantic -Wall fgfsclient.c -o fgfsclient */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+#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
index 000000000..fa4012f38
--- /dev/null
+++ b/scripts/example/fgfsclient.cxx
@@ -0,0 +1,181 @@
+// $Id$
+// g++ -O2 -g -pedantic -Wall fgfsclient.cxx -o fgfsclient -lstdc++
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+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
index 000000000..03572538f
--- /dev/null
+++ b/scripts/example/fgfsscript
@@ -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
index 000000000..133b31c68
--- /dev/null
+++ b/scripts/example/remote.html
@@ -0,0 +1,133 @@
+
+
+
+ FlightGear: Remote control
+
+
+
+
+
+
+
+
+FlightGear: Remote control
+
+
+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.
+
+
+To activate FlightGear's telnet server capabilities, call it with
+a --props specifiaction:
+
+
+
+$ fgfs --props=socket,bi,5,localhost,5501,tcp
+
+
+
+
+
+socket: FlightGear protocol
+bi: bidirectional
+5: polling frequency in Hertz
+localhost: server name or IP-address
+5501: server port
+tcp: internet protocol type
+
+
+
+
+
+In newer versions of FlightGear just type:
+
+
+$ fgfs --telnet=5501
+
+
+
+
+To learn more about the supported commands, connect to FlightGear
+with a telnet program and type in "help<RETURN>". This is what you'll get:
+
+
+
+$ 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 [<dir>] list directory
+dump dump current state (in xml)
+cd <dir> cd to a directory, '..' to move back
+pwd display your current path
+get <var> show the value of a parameter
+show <var> synonym for get
+set <var> <val> set <var> to a new <val>
+data switch to raw data mode
+prompt switch to interactive mode (default)
+quit terminate connection
+
+/>
+
+
+
+Now you can browse in the property system like in a Linux file
+system with cd, ls, pwd .
+
+
+
+
+Here you can download a sample script
+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 minutes to connect) or afterwards. Then
+it picks a random AGL altitude and checks every 5 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. :-)
+
+
+
+$ fgfsscript&
+$ fgfs --props=socket,bi,5,localhost,5501,tcp
+
+
+
+The script defaults to localhost and port 5501 ,
+but you can let the script control FlightGear on another host and
+under another port.
+
+
+
+$ fgfsscript some.host.org 1234&
+
+
+
+
+Demo programs are available in:
+
+
+
+
+
+
+
+$Id$
+Melchior FRANZ
+(mfranz at aon dot at)
+
+
+
+