JSBSim Flight Dynamics Model  1.1.11 (13 Feb 2022)
An Open Source Flight Dynamics and Control Software Library in C++
FGInputSocket.cpp
1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2 
3  Module: FGInputSocket.cpp
4  Author: Paul Chavent
5  Date started: 01/20/15
6  Purpose: Manage input of sim parameters to a socket
7  Called by: FGInput
8 
9  ------------- Copyright (C) 2015 Paul Chavent -------------
10 
11  This program is free software; you can redistribute it and/or modify it under
12  the terms of the GNU Lesser General Public License as published by the Free Software
13  Foundation; either version 2 of the License, or (at your option) any later
14  version.
15 
16  This program is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18  FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
19  details.
20 
21  You should have received a copy of the GNU Lesser General Public License along with
22  this program; if not, write to the Free Software Foundation, Inc., 59 Temple
23  Place - Suite 330, Boston, MA 02111-1307, USA.
24 
25  Further information about the GNU Lesser General Public License can also be found on
26  the world wide web at http://www.gnu.org.
27 
28 FUNCTIONAL DESCRIPTION
29 --------------------------------------------------------------------------------
30 This is the place where you create input routines to dump data for perusal
31 later.
32 
33 HISTORY
34 --------------------------------------------------------------------------------
35 01/20/15 PC Created
36 
37 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
38 INCLUDES
39 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
40 
41 #include <cstring>
42 #include <cstdlib>
43 #include <sstream>
44 #include <iomanip>
45 
46 #include "FGInputSocket.h"
47 #include "FGFDMExec.h"
48 #include "models/FGAircraft.h"
49 #include "input_output/FGXMLElement.h"
50 
51 using namespace std;
52 
53 namespace JSBSim {
54 
55 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
56 CLASS IMPLEMENTATION
57 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
58 
59 FGInputSocket::FGInputSocket(FGFDMExec* fdmex) :
60  FGInputType(fdmex), socket(0), SockProtocol(FGfdmSocket::ptTCP),
61  BlockingInput(false)
62 {
63 }
64 
65 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
66 
68 {
69  delete socket;
70 }
71 
72 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
73 
75 {
76  if (!FGInputType::Load(el))
77  return false;
78 
79  SockPort = atoi(el->GetAttributeValue("port").c_str());
80 
81  if (SockPort == 0) {
82  cerr << endl << "No port assigned in input element" << endl;
83  return false;
84  }
85 
86  string action = el->GetAttributeValue("action");
87  if (to_upper(action) == "BLOCKING_INPUT")
88  BlockingInput = true;
89 
90  return true;
91 }
92 
93 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
94 
96 {
97  if (FGInputType::InitModel()) {
98  delete socket;
99  socket = new FGfdmSocket(SockPort, SockProtocol);
100 
101  if (socket == 0) return false;
102  if (!socket->GetConnectStatus()) return false;
103 
104  return true;
105  }
106 
107  return false;
108 }
109 
110 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
111 
112 void FGInputSocket::Read(bool Holding)
113 {
114  string line, token;
115  size_t start=0, string_start=0, string_end=0;
116  double value=0;
117  FGPropertyNode* node=0;
118 
119  if (socket == 0) return;
120  if (!socket->GetConnectStatus()) return;
121 
122  if (BlockingInput)
123  socket->WaitUntilReadable(); // block until a transmission is received
124  data = socket->Receive(); // read data
125 
126  if (data.size() > 0) {
127  // parse lines
128  while (1) {
129  string_start = data.find_first_not_of("\r\n", start);
130  if (string_start == string::npos) break;
131  string_end = data.find_first_of("\r\n", string_start);
132  if (string_end == string::npos) break;
133  line = data.substr(string_start, string_end-string_start);
134  if (line.size() == 0) break;
135 
136  // now parse individual line
137  vector <string> tokens = split(line,' ');
138 
139  string command="", argument="", str_value="";
140  if (tokens.size() > 0) {
141  command = to_lower(tokens[0]);
142  if (tokens.size() > 1) {
143  argument = trim(tokens[1]);
144  if (tokens.size() > 2) {
145  str_value = trim(tokens[2]);
146  }
147  }
148  }
149 
150  if (command == "set") { // SET PROPERTY
151 
152  if (argument.size() == 0) {
153  socket->Reply("No property argument supplied.\n");
154  break;
155  }
156  try {
157  node = PropertyManager->GetNode(argument);
158  } catch(...) {
159  socket->Reply("Badly formed property query\n");
160  break;
161  }
162 
163  if (node == 0) {
164  socket->Reply("Unknown property\n");
165  break;
166  } else if (!node->hasValue()) {
167  socket->Reply("Not a leaf property\n");
168  break;
169  } else {
170  value = atof(str_value.c_str());
171  node->setDoubleValue(value);
172  }
173  socket->Reply("set successful\n");
174 
175  } else if (command == "get") { // GET PROPERTY
176 
177  if (argument.size() == 0) {
178  socket->Reply("No property argument supplied.\n");
179  break;
180  }
181  try {
182  node = PropertyManager->GetNode(argument);
183  } catch(...) {
184  socket->Reply("Badly formed property query\n");
185  break;
186  }
187 
188  if (node == 0) {
189  socket->Reply("Unknown property\n");
190  break;
191  } else if (!node->hasValue()) {
192  if (Holding) { // if holding can query property list
193  string query = FDMExec->QueryPropertyCatalog(argument);
194  socket->Reply(query);
195  } else {
196  socket->Reply("Must be in HOLD to search properties\n");
197  }
198  } else {
199  ostringstream buf;
200  buf << argument << " = " << setw(12) << setprecision(6) << node->getDoubleValue() << endl;
201  socket->Reply(buf.str());
202  }
203 
204  } else if (command == "hold") { // PAUSE
205 
206  FDMExec->Hold();
207  socket->Reply("Holding\n");
208 
209  } else if (command == "resume") { // RESUME
210 
211  FDMExec->Resume();
212  socket->Reply("Resuming\n");
213 
214  } else if (command == "iterate") { // ITERATE
215 
216  int argumentInt;
217  istringstream (argument) >> argumentInt;
218  if (argument.size() == 0) {
219  socket->Reply("No argument supplied for number of iterations.\n");
220  break;
221  }
222  if ( !(argumentInt > 0) ){
223  socket->Reply("Required argument must be a positive Integer.\n");
224  break;
225  }
226  FDMExec->EnableIncrementThenHold( argumentInt );
227  FDMExec->Resume();
228  socket->Reply("Iterations performed\n");
229 
230  } else if (command == "quit") { // QUIT
231 
232  // close the socket connection
233  socket->Reply("Closing connection\n");
234  socket->Close();
235 
236  } else if (command == "info") { // INFO
237 
238  // get info about the sim run and/or aircraft, etc.
239  ostringstream info;
240  info << "JSBSim version: " << JSBSim_version << endl;
241  info << "Config File version: " << needed_cfg_version << endl;
242  info << "Aircraft simulated: " << FDMExec->GetAircraft()->GetAircraftName() << endl;
243  info << "Simulation time: " << setw(8) << setprecision(3) << FDMExec->GetSimTime() << endl;
244  socket->Reply(info.str());
245 
246  } else if (command == "help") { // HELP
247 
248  socket->Reply(
249  " JSBSim Server commands:\n\n"
250  " get {property name}\n"
251  " set {property name} {value}\n"
252  " hold\n"
253  " resume\n"
254  " iterate {value}\n"
255  " help\n"
256  " quit\n"
257  " info\n\n");
258 
259  } else {
260  socket->Reply(string("Unknown command: ") + token + string("\n"));
261  }
262 
263  start = string_end;
264  }
265  }
266 
267 }
268 
269 }
JSBSim::FGFDMExec
Encapsulates the JSBSim simulation executive.
Definition: FGFDMExec.h:185
JSBSim::FGfdmSocket
Encapsulates an object that enables JSBSim to communicate via socket (input and/or output).
Definition: FGfdmSocket.h:70
JSBSim::FGFDMExec::QueryPropertyCatalog
std::string QueryPropertyCatalog(const std::string &check)
Retrieves property or properties matching the supplied string.
Definition: FGFDMExec.cpp:952
JSBSim::FGInputType::InitModel
bool InitModel(void) override
Init the input model according to its configitation.
Definition: FGInputType.cpp:88
JSBSim::Element::GetAttributeValue
std::string GetAttributeValue(const std::string &key)
Retrieves an attribute.
Definition: FGXMLElement.cpp:260
JSBSim::FGInputType::Load
bool Load(Element *el) override
Init the input directives from an XML file (implement the FGModel interface).
Definition: FGInputType.cpp:72
JSBSim::FGAircraft::GetAircraftName
const std::string & GetAircraftName(void) const
Gets the aircraft name.
Definition: FGAircraft.h:131
JSBSim::FGInputSocket::Read
void Read(bool Holding) override
Generates the input.
Definition: FGInputSocket.cpp:112
JSBSim::FGFDMExec::GetSimTime
double GetSimTime(void) const
Returns the cumulative simulation time in seconds.
Definition: FGFDMExec.h:542
JSBSim::FGFDMExec::GetAircraft
FGAircraft * GetAircraft(void)
Returns the FGAircraft pointer.
Definition: FGFDMExec.h:375
JSBSim::FGPropertyNode
Class wrapper for property handling.
Definition: FGPropertyManager.h:70
JSBSim::FGInputType
Abstract class to provide functions generic to all the input directives.
Definition: FGInputType.h:73
JSBSim::FGFDMExec::EnableIncrementThenHold
void EnableIncrementThenHold(int Timesteps)
Turn on hold after increment.
Definition: FGFDMExec.h:484
JSBSim::FGInputSocket::InitModel
bool InitModel(void) override
Initializes the instance.
Definition: FGInputSocket.cpp:95
JSBSim::FGFDMExec::Hold
void Hold(void)
Pauses execution by preventing time from incrementing.
Definition: FGFDMExec.h:482
JSBSim::FGFDMExec::Resume
void Resume(void)
Resumes execution from a "Hold".
Definition: FGFDMExec.h:488
JSBSim::FGInputSocket::~FGInputSocket
~FGInputSocket() override
Destructor.
Definition: FGInputSocket.cpp:67
JSBSim::Element
Definition: FGXMLElement.h:143
JSBSim::FGInputSocket::Load
bool Load(Element *el) override
Init the input directives from an XML file.
Definition: FGInputSocket.cpp:74