FlightGear next
ExternalNet.cxx
Go to the documentation of this file.
1/*
2 * SPDX-FileName: ExternalNet.cxx
3 * SPDX-FileComment: an net interface to an external flight dynamics model
4 * SPDX-FileCopyrightText: Copyright (C) 2001 Curtis L. Olson - http://www.flightgear.org/~curt
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 */
7
8#ifdef HAVE_CONFIG_H
9#include <config.h>
10#endif
11
12#include <cstring>
13
14#include <simgear/debug/logstream.hxx>
15#include <simgear/io/lowlevel.hxx> // endian tests
16#include <simgear/io/sg_netBuffer.hxx>
17
18#include <Main/fg_props.hxx>
22
23#include "ExternalNet.hxx"
24
25
26class HTTPClient : public simgear::NetBufferChannel
27{
28 bool done;
29 SGTimeStamp start;
30 simgear::NetChannelPoller poller;
31
32public:
33 HTTPClient(const char* host, int port, const char* path) : done(false)
34 {
35 open();
36 connect(host, port);
37
38 char buffer[300];
39 ::snprintf(buffer, 299, "GET %s HTTP/1.0\r\n\r\n", path);
40 buffer[299] = '\0';
41
42 bufferSend(buffer, strlen(buffer));
43
44 poller.addChannel(this);
45 start.stamp();
46 }
47
48 virtual void handleBufferRead(simgear::NetBuffer& buffer)
49 {
50 const char* s = buffer.getData();
51 while (*s)
52 fputc(*s++, stdout);
53
54 printf("done\n");
55
56 buffer.remove();
57
58 done = true;
59 }
60
61 bool isDone() const { return done; }
62 bool isDone(long usec) const
63 {
64 if (start + SGTimeStamp::fromUSec(usec) < SGTimeStamp::now()) {
65 return true;
66 } else {
67 return done;
68 }
69 }
70
71 void poll(int timeout)
72 {
73 poller.poll(timeout);
74 }
75};
76
77FGExternalNet::FGExternalNet(double dt, std::string host, int dop, int dip, int cp)
78{
79 // set_delta_t( dt );
80
81 valid = true;
82
83 data_in_port = dip;
84 data_out_port = dop;
85 cmd_port = cp;
86 fdm_host = host;
87
89 // Setup client udp connection (sends data to remote fdm)
90
91 if (!data_client.open(false)) {
92 SG_LOG(SG_FLIGHT, SG_ALERT, "Error opening client data channel");
93 valid = false;
94 }
95
96 // fire and forget
97 data_client.setBlocking(false);
98
99 if (data_client.connect(fdm_host.c_str(), data_out_port) == -1) {
100 printf("error connecting to %s:%d\n", fdm_host.c_str(), data_out_port);
101 valid = false;
102 }
103
105 // Setup server udp connection (for receiving data)
106
107 if (!data_server.open(false)) {
108 SG_LOG(SG_FLIGHT, SG_ALERT, "Error opening client server channel");
109 valid = false;
110 }
111
112 // disable blocking
113 data_server.setBlocking(false);
114
115 // allowed to read from a broadcast addr
116 // data_server.setBroadcast( true );
117
118 // if we bind to fdm_host = "" then we accept messages from
119 // anyone.
120 if (data_server.bind("", data_in_port) == -1) {
121 printf("error binding to port %d\n", data_in_port);
122 valid = false;
123 }
124}
125
126
128{
129 data_client.close();
130 data_server.close();
131}
132
133
134// Initialize the ExternalNet flight model, dt is the time increment
135// for each subsequent iteration through the EOM
137{
138 // cout << "FGExternalNet::init()" << endl;
139
140 // Explicitly call the superclass's
141 // init method first.
142 common_init();
143
144 double lon = fgGetDouble("/sim/presets/longitude-deg");
145 double lat = fgGetDouble("/sim/presets/latitude-deg");
146 double alt = fgGetDouble("/sim/presets/altitude-ft");
147 double ground = get_Runway_altitude_m();
148 double heading = fgGetDouble("/sim/presets/heading-deg");
149 double speed = fgGetDouble("/sim/presets/airspeed-kt");
150
151 char cmd[256];
152
153 HTTPClient* http;
154 snprintf(cmd, 256, "/longitude-deg?value=%.8f", lon);
155 http = new HTTPClient(fdm_host.c_str(), cmd_port, cmd);
156 while (!http->isDone(1000000)) http->poll(0);
157 delete http;
158
159 snprintf(cmd, 256, "/latitude-deg?value=%.8f", lat);
160 http = new HTTPClient(fdm_host.c_str(), cmd_port, cmd);
161 while (!http->isDone(1000000)) http->poll(0);
162 delete http;
163
164 snprintf(cmd, 256, "/altitude-ft?value=%.8f", alt);
165 http = new HTTPClient(fdm_host.c_str(), cmd_port, cmd);
166 while (!http->isDone(1000000)) http->poll(0);
167 delete http;
168
169 snprintf(cmd, 256, "/ground-m?value=%.8f", ground);
170 http = new HTTPClient(fdm_host.c_str(), cmd_port, cmd);
171 while (!http->isDone(1000000)) http->poll(0);
172 delete http;
173
174 snprintf(cmd, 256, "/speed-kts?value=%.8f", speed);
175 http = new HTTPClient(fdm_host.c_str(), cmd_port, cmd);
176 while (!http->isDone(1000000)) http->poll(0);
177 delete http;
178
179 snprintf(cmd, 256, "/heading-deg?value=%.8f", heading);
180 http = new HTTPClient(fdm_host.c_str(), cmd_port, cmd);
181 while (!http->isDone(1000000)) http->poll(0);
182 delete http;
183
184 SG_LOG(SG_IO, SG_INFO, "before sending reset command.");
185
186 if (fgGetBool("/sim/presets/onground")) {
187 snprintf(cmd, 256, "/reset?value=ground");
188 } else {
189 snprintf(cmd, 256, "/reset?value=air");
190 }
191 http = new HTTPClient(fdm_host.c_str(), cmd_port, cmd);
192 while (!http->isDone(1000000)) http->poll(0);
193 delete http;
194
195 SG_LOG(SG_IO, SG_INFO, "Remote FDM init() finished.");
196}
197
198
199// Run an iteration of the EOM.
201{
202 int length;
203 int result;
204
205 if (is_suspended())
206 return;
207
208 // Send control positions to remote fdm
209 length = sizeof(ctrls);
210 FGProps2Ctrls<FGNetCtrls>( globals->get_props(), &ctrls, true, true);
211 if (data_client.send((char*)(&ctrls), length, 0) != length) {
212 SG_LOG(SG_IO, SG_DEBUG, "Error writing data.");
213 } else {
214 SG_LOG(SG_IO, SG_DEBUG, "wrote control data.");
215 }
216
217 // Read next set of FDM data (blocking enabled to maintain 'sync')
218 length = sizeof(fdm);
219 while ((result = data_server.recv((char*)(&fdm), length, 0)) >= 0) {
220 SG_LOG(SG_IO, SG_DEBUG, "Success reading data.");
221 FGFDM2Props<FGNetFDM>( globals->get_props(), &fdm);
222 }
223}
224
225// Register the subsystem.
226#if 0
227SGSubsystemMgr::Registrant<FGExternalNet> registrantFGExternalNet;
228#endif
void init() override
void update(double dt) override
FGExternalNet(double dt, std::string host, int dop, int dip, int cp)
void common_init()
Initialize the state of the FDM.
Definition flight.cxx:137
double get_Runway_altitude_m() const
Definition flight.hxx:680
HTTPClient(const char *host, int port, const char *path)
bool isDone() const
bool isDone(long usec) const
virtual void handleBufferRead(simgear::NetBuffer &buffer)
void poll(int timeout)
FGGlobals * globals
Definition globals.cxx:142
void FGProps2Ctrls< FGNetCtrls >(SGPropertyNode *props, FGNetCtrls *net, bool honor_freezes, bool net_byte_order)
void FGFDM2Props< FGNetFDM >(SGPropertyNode *props, FGNetFDM *net, bool net_byte_order)
bool fgGetBool(char const *name, bool def)
Get a bool value for a property.
Definition proptest.cpp:25
double fgGetDouble(const char *name, double defaultValue)
Get a double value for a property.
Definition proptest.cpp:30