source: xplra/src/client/c/hu/varadiistvan/xplra/XPlane.cc@ 40:ec5dde8a6ff6

Last change on this file since 40:ec5dde8a6ff6 was 40:ec5dde8a6ff6, checked in by István Váradi <ivaradi@…>, 11 years ago

Implemented the client support for the new commands and updated the basic test programs with tests showing messages

File size: 15.8 KB
Line 
1// Copyright (c) 2013 by István Váradi
2
3// This file is part of XPLRA, a remote-access plugin for X-Plane
4
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are met:
7
8// 1. Redistributions of source code must retain the above copyright notice, this
9// list of conditions and the following disclaimer.
10// 2. Redistributions in binary form must reproduce the above copyright notice,
11// this list of conditions and the following disclaimer in the documentation
12// and/or other materials provided with the distribution.
13
14// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
18// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24
25// The views and conclusions contained in the software and documentation are those
26// of the authors and should not be interpreted as representing official policies,
27// either expressed or implied, of the FreeBSD Project.
28
29//------------------------------------------------------------------------------
30
31#include "XPlane.h"
32
33#include "MultiGetter.h"
34#include "MultiSetter.h"
35
36#include <hu/varadiistvan/scpl/io/LocalClientSocket.h>
37#include <hu/varadiistvan/scpl/io/DataStream.h>
38
39#include <xplra/Protocol.h>
40
41#include <memory>
42
43#ifndef _WIN32
44#include <signal.h>
45#endif
46
47//------------------------------------------------------------------------------
48
49using hu::varadiistvan::xplra::XPlane;
50using hu::varadiistvan::xplra::MultiGetter;
51using hu::varadiistvan::xplra::MultiSetter;
52
53using hu::varadiistvan::scpl::io::LocalClientSocket;
54using hu::varadiistvan::scpl::io::LocalConnector;
55using hu::varadiistvan::scpl::io::DataStream;
56
57using xplra::Protocol;
58
59using std::auto_ptr;
60using std::string;
61
62//------------------------------------------------------------------------------
63
64void XPlane::checkStream() throw(NotConnectedException, IOException)
65{
66 if (stream==0) {
67 throw NotConnectedException();
68 } else if (stream->failed()) {
69 throw IOException(stream->getErrorCode());
70 }
71}
72
73//------------------------------------------------------------------------------
74
75void XPlane::checkResult(uint8_t result, bool hasParameter, long parameter)
76 throw(ProtocolException)
77{
78 switch(result) {
79 case Protocol::RESULT_OK:
80 return;
81 case Protocol::RESULT_INVALID_COMMAND:
82 throw ProtocolException(ProtocolException::INVALID_COMMAND,
83 hasParameter, parameter);
84 case Protocol::RESULT_UNKNOWN_DATAREF:
85 throw ProtocolException(ProtocolException::UNKNOWN_DATAREF,
86 hasParameter, parameter);
87 case Protocol::RESULT_INVALID_TYPE:
88 throw ProtocolException(ProtocolException::INVALID_TYPE,
89 hasParameter, parameter);
90 case Protocol::RESULT_INVALID_LENGTH:
91 throw ProtocolException(ProtocolException::INVALID_LENGTH,
92 hasParameter, parameter);
93 case Protocol::RESULT_INVALID_OFFSET:
94 throw ProtocolException(ProtocolException::INVALID_OFFSET,
95 hasParameter, parameter);
96 case Protocol::RESULT_INVALID_COUNT:
97 throw ProtocolException(ProtocolException::INVALID_COUNT,
98 hasParameter, parameter);
99 case Protocol::RESULT_INVALID_ID:
100 throw ProtocolException(ProtocolException::INVALID_ID,
101 hasParameter, parameter);
102 case Protocol::RESULT_INVALID_DURATION:
103 throw ProtocolException(ProtocolException::INVALID_DURATION,
104 hasParameter, parameter);
105 case Protocol::RESULT_OTHER_ERROR:
106 default:
107 throw ProtocolException(ProtocolException::OTHER,
108 hasParameter, parameter);
109 }
110}
111
112//------------------------------------------------------------------------------
113
114void XPlane::checkResult(bool multi) throw(ProtocolException, IOException)
115{
116 uint8_t result = stream->readU8();
117 bool hasParameter = false;
118 long parameter = 0;
119 if (multi) {
120 if (result==Protocol::RESULT_UNKNOWN_DATAREF) {
121 parameter = stream->readU32();
122 hasParameter = true;
123 }
124 }
125 checkStream();
126 checkResult(result, hasParameter, parameter);
127}
128
129//------------------------------------------------------------------------------
130//------------------------------------------------------------------------------
131
132XPlane::~XPlane() throw()
133{
134 disconnect();
135 for(multiBuffers_t::iterator i = multiBuffers.begin();
136 i!=multiBuffers.end(); ++i)
137 {
138 MultiBuffer* buffer = *i;
139 buffer->forgetRegistration();
140 delete buffer;
141 }
142}
143
144//------------------------------------------------------------------------------
145
146void XPlane::connect() throw(IOException)
147{
148 if (socket!=0) return;
149
150 auto_ptr<LocalClientSocket> clientSocket(new LocalClientSocket("xplra",
151 &waiter));
152 LocalConnector& connector = clientSocket->getConnector();
153
154 while (!connector.connect()) {
155 if (connector.failed()) {
156 throw IOException(connector.getErrorCode());
157 }
158 waiter.wait();
159 if (waiter.failed()) {
160 throw IOException(waiter.getErrorCode());
161 }
162 }
163
164#ifndef _WIN32
165 signal(SIGPIPE, SIG_IGN);
166#endif
167
168 socket = clientSocket.release();
169 stream = new DataStream(*socket);
170}
171
172//------------------------------------------------------------------------------
173
174void XPlane::disconnect() throw()
175{
176 if (socket==0) return;
177
178 delete stream; stream = 0;
179 delete socket; socket = 0;
180}
181
182//------------------------------------------------------------------------------
183
184MultiGetter& XPlane::createMultiGetter() throw()
185{
186 MultiGetter* getter = new MultiGetter(*this);
187 multiBuffers.insert(getter);
188 return *getter;
189}
190
191//------------------------------------------------------------------------------
192
193MultiSetter& XPlane::createMultiSetter() throw()
194{
195 MultiSetter* setter = new MultiSetter(*this);
196 multiBuffers.insert(setter);
197 return *setter;
198}
199
200//------------------------------------------------------------------------------
201
202bool XPlane::destroyMultiBuffer(MultiBuffer& buffer) throw(Exception)
203{
204 multiBuffers_t::iterator i = multiBuffers.find(&buffer);
205 if (i==multiBuffers.end()) return false;
206
207 multiBuffers.erase(i);
208 delete &buffer;
209
210 return true;
211}
212
213//------------------------------------------------------------------------------
214
215void XPlane::getVersions(int& xplaneVersion, int& xplmVersion, int& xplraVersion)
216 throw(Exception)
217{
218 stream->writeU8(Protocol::COMMAND_GET_VERSIONS);
219 stream->flush();
220 checkResult();
221
222 xplaneVersion = stream->readS32();
223 xplmVersion = stream->readS32();
224 xplraVersion = stream->readS32();
225
226 checkStream();
227}
228
229//------------------------------------------------------------------------------
230
231void XPlane::reloadPlugins() throw(Exception)
232{
233 stream->writeU8(Protocol::COMMAND_RELOAD_PLUGINS);
234 stream->flush();
235 checkResult();
236}
237
238//------------------------------------------------------------------------------
239
240void XPlane::getScalar(const char* name, uint8_t type) throw(Exception)
241{
242 checkStream();
243
244 stream->writeU8(Protocol::COMMAND_GET_SINGLE);
245 stream->writeString(name, strlen(name));
246 stream->writeU8(type);
247 if (!stream->flush()) checkStream();
248
249 checkResult();
250}
251
252//------------------------------------------------------------------------------
253
254int XPlane::getInt(const char* name) throw(Exception)
255{
256 getScalar(name, Protocol::TYPE_INT);
257
258 int value = stream->readS32();
259 checkStream();
260 return value;
261}
262
263//------------------------------------------------------------------------------
264
265float XPlane::getFloat(const char* name) throw(Exception)
266{
267 getScalar(name, Protocol::TYPE_FLOAT);
268
269 float value = stream->readFloat();
270 checkStream();
271 return value;
272}
273
274//------------------------------------------------------------------------------
275
276double XPlane::getDouble(const char* name) throw(Exception)
277{
278 getScalar(name, Protocol::TYPE_DOUBLE);
279
280 double value = stream->readDouble();
281 checkStream();
282 return value;
283}
284
285//------------------------------------------------------------------------------
286
287size_t XPlane::getArray(const char* name, uint8_t type,
288 ssize_t length, size_t offset) throw(Exception)
289{
290 checkStream();
291
292 stream->writeU8(Protocol::COMMAND_GET_SINGLE);
293 stream->writeString(name, strlen(name));
294 stream->writeU8(type);
295 stream->writeS32(static_cast<int32_t>(length));
296 stream->writeS32(static_cast<int32_t>(offset));
297 if (!stream->flush()) checkStream();
298
299 uint8_t result = stream->readU8();
300 length = stream->readS32();
301 checkStream();
302 checkResult(result);
303
304 return length;
305}
306
307//------------------------------------------------------------------------------
308
309size_t XPlane::getFloatArray(const char* name, float* dest,
310 size_t length, size_t offset) throw(Exception)
311{
312 length = getArray(name, Protocol::TYPE_FLOAT_ARRAY, length, offset);
313
314 if (!stream->read(dest, length*sizeof(float))) checkStream();
315
316 return length;
317}
318
319//------------------------------------------------------------------------------
320
321float* XPlane::getFloatArray(const char* name, size_t& length,
322 size_t offset) throw(Exception)
323{
324 length = getArray(name, Protocol::TYPE_FLOAT_ARRAY, -1, offset);
325
326 auto_ptr<float> data(new float[length]);
327 if (!stream->read(data.get(), length*sizeof(float))) checkStream();
328 return data.release();
329}
330
331//------------------------------------------------------------------------------
332
333size_t XPlane::getIntArray(const char* name, int32_t* dest,
334 size_t length, size_t offset) throw(Exception)
335{
336 length = getArray(name, Protocol::TYPE_INT_ARRAY, length, offset);
337
338 if (!stream->read(dest, length*sizeof(int32_t))) checkStream();
339
340 return length;
341}
342
343//------------------------------------------------------------------------------
344
345int32_t* XPlane::getIntArray(const char* name, size_t& length,
346 size_t offset) throw(Exception)
347{
348 length = getArray(name, Protocol::TYPE_INT_ARRAY, -1, offset);
349
350 auto_ptr<int32_t> data(new int32_t[length]);
351 if (!stream->read(data.get(), length*sizeof(int32_t))) checkStream();
352 return data.release();
353}
354
355//------------------------------------------------------------------------------
356
357size_t XPlane::getByteArray(const char* name, uint8_t* dest,
358 size_t length, size_t offset) throw(Exception)
359{
360 length = getArray(name, Protocol::TYPE_BYTE_ARRAY, length, offset);
361
362 if (!stream->read(dest, length*sizeof(uint8_t))) checkStream();
363
364 return length;
365}
366
367//------------------------------------------------------------------------------
368
369uint8_t* XPlane::getByteArray(const char* name, size_t& length,
370 size_t offset) throw(Exception)
371{
372 length = getArray(name, Protocol::TYPE_BYTE_ARRAY, -1, offset);
373
374 auto_ptr<uint8_t> data(new uint8_t[length]);
375 if (!stream->read(data.get(), length*sizeof(uint8_t))) checkStream();
376 return data.release();
377}
378
379//------------------------------------------------------------------------------
380
381string XPlane::getString(const char* name, size_t offset) throw(Exception)
382{
383 size_t length = 0;
384 auto_ptr<uint8_t> data(getByteArray(name, length, offset));
385 return string(reinterpret_cast<char*>(data.get()));
386}
387
388//------------------------------------------------------------------------------
389
390void XPlane::setScalar(const char* name, uint8_t type) throw(Exception)
391{
392 stream->writeU8(Protocol::COMMAND_SET_SINGLE);
393 stream->writeString(name, strlen(name));
394 stream->writeU8(type);
395}
396
397//------------------------------------------------------------------------------
398
399void XPlane::setInt(const char* name, int value) throw(Exception)
400{
401 setScalar(name, Protocol::TYPE_INT);
402 stream->writeS32(value);
403 stream->flush();
404 checkResult();
405}
406
407//------------------------------------------------------------------------------
408
409void XPlane::setFloat(const char* name, float value) throw(Exception)
410{
411 setScalar(name, Protocol::TYPE_FLOAT);
412 stream->writeFloat(value);
413 stream->flush();
414 checkResult();
415}
416
417//------------------------------------------------------------------------------
418
419void XPlane::setDouble(const char* name, double value) throw(Exception)
420{
421 setScalar(name, Protocol::TYPE_DOUBLE);
422 stream->writeDouble(value);
423 stream->flush();
424 checkResult();
425}
426
427//------------------------------------------------------------------------------
428
429void XPlane::setArray(const char* name, uint8_t type, size_t length,
430 size_t offset) throw(Exception)
431{
432 stream->writeU8(Protocol::COMMAND_SET_SINGLE);
433 stream->writeString(name, strlen(name));
434 stream->writeU8(type);
435 stream->writeS32(static_cast<int32_t>(length));
436 stream->writeS32(static_cast<int32_t>(offset));
437}
438
439//------------------------------------------------------------------------------
440
441void XPlane::setFloatArray(const char* name, const float* values, size_t length,
442 size_t offset) throw(Exception)
443{
444 setArray(name, Protocol::TYPE_FLOAT_ARRAY, length, offset);
445 stream->write(values, length*sizeof(*values));
446 stream->flush();
447 checkResult();
448}
449
450//------------------------------------------------------------------------------
451
452void XPlane::setIntArray(const char* name, const int32_t* values, size_t length,
453 size_t offset) throw(Exception)
454{
455 setArray(name, Protocol::TYPE_INT_ARRAY, length, offset);
456 stream->write(values, length*sizeof(*values));
457 stream->flush();
458 checkResult();
459}
460
461//------------------------------------------------------------------------------
462
463void XPlane::setByteArray(const char* name, const uint8_t* values, size_t length,
464 size_t offset) throw(Exception)
465{
466 setArray(name, Protocol::TYPE_BYTE_ARRAY, length, offset);
467 stream->write(values, length*sizeof(*values));
468 stream->flush();
469 checkResult();
470}
471
472//------------------------------------------------------------------------------
473
474void XPlane::setString(const char* name, const char* value, size_t length,
475 size_t offset) throw(Exception)
476{
477 size_t valueLength = strlen(value);
478 if ((valueLength+1)>=length) {
479 setByteArray(name, reinterpret_cast<const uint8_t*>(value),
480 length, offset);
481 } else {
482 auto_ptr<uint8_t> buffer(new uint8_t[length]);
483 memcpy(buffer.get(), value, valueLength);
484 memset(buffer.get() + valueLength, 0, length - valueLength);
485 setByteArray(name, buffer.get(), length, offset);
486 }
487}
488
489//------------------------------------------------------------------------------
490
491void XPlane::showMessage(const char* message, float duration) throw(Exception)
492{
493 stream->writeU8(Protocol::COMMAND_SHOW_MESSAGE);
494 stream->writeString(message);
495 stream->writeFloat(duration);
496 stream->flush();
497 checkResult();
498}
499
500//------------------------------------------------------------------------------
501
502// Local Variables:
503// mode: C++
504// c-basic-offset: 4
505// indent-tabs-mode: nil
506// End:
Note: See TracBrowser for help on using the repository browser.