1 // multiplay.cxx -- protocol object for multiplay in Flightgear
3 // Written by Diarmuid Tyson, started February 2003.
4 // diarmuid.tyson@airservicesaustralia.com
6 // With addtions by Vivian Meazza, January 2006
8 // Copyright (C) 2003 Airservices Australia
10 // This program is free software; you can redistribute it and/or
11 // modify it under the terms of the GNU General Public License as
12 // published by the Free Software Foundation; either version 2 of the
13 // License, or (at your option) any later version.
15 // This program is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 // General Public License for more details.
20 // You should have received a copy of the GNU General Public License
21 // along with this program; if not, write to the Free Software
22 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
29 #include <simgear/compiler.h>
37 #include <simgear/debug/logstream.hxx>
38 #include <simgear/math/SGMath.hxx>
40 #include <FDM/flight.hxx>
41 #include <MultiPlayer/mpmessages.hxx>
43 #include "multiplay.hxx"
48 // These constants are provided so that the ident command can list file versions.
49 const char sFG_MULTIPLAY_BID[] = "$Id$";
50 const char sFG_MULTIPLAY_HID[] = FG_MULTIPLAY_HID;
53 /******************************************************************
55 * Description: Constructor. Initialises the protocol and stores
56 * host and port information.
57 ******************************************************************/
58 FGMultiplay::FGMultiplay (const string &dir, const int rate, const string &host, const int port) {
64 if (get_direction() == SG_IO_IN) {
66 fgSetInt("/sim/multiplay/rxport", port);
67 fgSetString("/sim/multiplay/rxhost", host.c_str());
69 } else if (get_direction() == SG_IO_OUT) {
71 fgSetInt("/sim/multiplay/txport", port);
72 fgSetString("/sim/multiplay/txhost", host.c_str());
79 /******************************************************************
81 * Description: Destructor.
82 ******************************************************************/
83 FGMultiplay::~FGMultiplay () {
87 /******************************************************************
89 * Description: Enables the protocol.
90 ******************************************************************/
91 bool FGMultiplay::open() {
94 SG_LOG( SG_IO, SG_ALERT, "This shouldn't happen, but the channel "
95 << "is already in use, ignoring" );
101 SGPropertyNode* root = globals->get_props();
103 /// Build up the id to property map
105 while (FGMultiplayMgr::sIdPropertyList[i].name) {
106 const char* name = FGMultiplayMgr::sIdPropertyList[i].name;
107 SGPropertyNode* pNode = root->getNode(name);
109 mPropertyMap[FGMultiplayMgr::sIdPropertyList[i].id] = pNode;
117 /******************************************************************
119 * Description: Prompts the multiplayer mgr to either send
120 * or receive data over the network
121 ******************************************************************/
122 bool FGMultiplay::process() {
124 if (get_direction() == SG_IO_OUT) {
126 // check if we have left initialization phase. That will not provide
127 // interresting data, also the freeze in simulation time hurts the
128 // multiplayer clients
129 double sim_time = globals->get_sim_time_sec();
130 // if (sim_time < 20)
133 FGInterface *ifce = cur_fdm_state;
135 // put together a motion info struct, you will get that later
136 // from FGInterface directly ...
137 FGExternalMotionData motionInfo;
139 // The current simulation time we need to update for,
140 // note that the simulation time is updated before calling all the
141 // update methods. Thus it contains the time intervals *end* time.
142 // The FDM is already run, so the states belong to that time.
143 motionInfo.time = sim_time;
145 // The typical lag will be the reciprocal of the output frequency
146 double hz = get_hz();
147 if (hz != 0) // I guess we can test a double for exact zero in this case
148 motionInfo.lag = 1/get_hz();
150 motionInfo.lag = 0.1; //??
152 // These are for now converted from lat/lon/alt and euler angles.
153 // But this should change in FGInterface ...
154 double lon = ifce->get_Longitude();
155 double lat = ifce->get_Latitude();
156 // first the aprioriate structure for the geodetic one
157 SGGeod geod = SGGeod::fromRadFt(lon, lat, ifce->get_Altitude());
158 // Convert to cartesion coordinate
159 motionInfo.position = geod;
161 // The quaternion rotating from the earth centered frame to the
162 // horizontal local frame
163 SGQuatf qEc2Hl = SGQuatf::fromLonLatRad((float)lon, (float)lat);
164 // The orientation wrt the horizontal local frame
165 float heading = ifce->get_Psi();
166 float pitch = ifce->get_Theta();
167 float roll = ifce->get_Phi();
168 SGQuatf hlOr = SGQuatf::fromYawPitchRoll(heading, pitch, roll);
169 // The orientation of the vehicle wrt the earth centered frame
170 motionInfo.orientation = qEc2Hl*hlOr;
172 if (!ifce->is_suspended()) {
174 motionInfo.linearVel = SG_FEET_TO_METER*SGVec3f(ifce->get_U_body(),
177 motionInfo.angularVel = SGVec3f(ifce->get_P_body(),
181 // accels, set that to zero for now.
182 // Angular accelerations are missing from the interface anyway,
183 // linear accelerations are screwed up at least for JSBSim.
184 // motionInfo.linearAccel = SG_FEET_TO_METER*SGVec3f(ifce->get_U_dot_body(),
185 // ifce->get_V_dot_body(),
186 // ifce->get_W_dot_body());
187 motionInfo.linearAccel = SGVec3f::zeros();
188 motionInfo.angularAccel = SGVec3f::zeros();
190 // if the interface is suspendend, prevent the client from
191 // wild extrapolations
192 motionInfo.linearVel = SGVec3f::zeros();
193 motionInfo.angularVel = SGVec3f::zeros();
194 motionInfo.linearAccel = SGVec3f::zeros();
195 motionInfo.angularAccel = SGVec3f::zeros();
198 // now send the properties
199 PropertyMap::iterator it;
200 for (it = mPropertyMap.begin(); it != mPropertyMap.end(); ++it) {
201 FGFloatPropertyData pData;
202 pData.id = it->first;
203 pData.value = it->second->getFloatValue();
204 motionInfo.properties.push_back(pData);
207 FGMultiplayMgr* mpmgr = globals->get_multiplayer_mgr();
208 mpmgr->SendMyPosition(motionInfo);
215 /******************************************************************
217 * Description: Closes the multiplayer mgrs to stop any further
219 ******************************************************************/
220 bool FGMultiplay::close() {
222 if (get_direction() == SG_IO_IN) {
224 globals->get_multiplayer_mgr()->Close();
226 } else if (get_direction() == SG_IO_OUT) {
228 globals->get_multiplayer_mgr()->Close();