source: xplra/src/client/c/hu/varadiistvan/xplra/XPlane.cc@ 92:e3a0abb22ef4

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

C++11 compatibility

File size: 17.4 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::unique_ptr;
60using std::string;
61using std::min;
62
63//------------------------------------------------------------------------------
64
65void XPlane::checkStream() throw(NotConnectedException, IOException)
66{
67 if (stream==0) {
68 throw NotConnectedException();
69 } else if (stream->failed()) {
70 throw IOException(stream->getErrorCode());
71 }
72}
73
74//------------------------------------------------------------------------------
75
76void XPlane::checkResult(uint8_t result, bool hasParameter, long parameter)
77 throw(ProtocolException)
78{
79 switch(result) {
80 case Protocol::RESULT_OK:
81 return;
82 case Protocol::RESULT_INVALID_COMMAND:
83 throw ProtocolException(ProtocolException::INVALID_COMMAND,
84 hasParameter, parameter);
85 case Protocol::RESULT_UNKNOWN_DATAREF:
86 throw ProtocolException(ProtocolException::UNKNOWN_DATAREF,
87 hasParameter, parameter);
88 case Protocol::RESULT_INVALID_TYPE:
89 throw ProtocolException(ProtocolException::INVALID_TYPE,
90 hasParameter, parameter);
91 case Protocol::RESULT_INVALID_LENGTH:
92 throw ProtocolException(ProtocolException::INVALID_LENGTH,
93 hasParameter, parameter);
94 case Protocol::RESULT_INVALID_OFFSET:
95 throw ProtocolException(ProtocolException::INVALID_OFFSET,
96 hasParameter, parameter);
97 case Protocol::RESULT_INVALID_COUNT:
98 throw ProtocolException(ProtocolException::INVALID_COUNT,
99 hasParameter, parameter);
100 case Protocol::RESULT_INVALID_ID:
101 throw ProtocolException(ProtocolException::INVALID_ID,
102 hasParameter, parameter);
103 case Protocol::RESULT_INVALID_DURATION:
104 throw ProtocolException(ProtocolException::INVALID_DURATION,
105 hasParameter, parameter);
106 case Protocol::RESULT_OTHER_ERROR:
107 default:
108 throw ProtocolException(ProtocolException::OTHER,
109 hasParameter, parameter);
110 }
111}
112
113//------------------------------------------------------------------------------
114
115void XPlane::checkResult(bool multi) throw(ProtocolException, IOException)
116{
117 uint8_t result = stream->readU8();
118 bool hasParameter = false;
119 long parameter = 0;
120 if (multi) {
121 if (result==Protocol::RESULT_UNKNOWN_DATAREF) {
122 parameter = stream->readU32();
123 hasParameter = true;
124 }
125 }
126 checkStream();
127 checkResult(result, hasParameter, parameter);
128}
129
130//------------------------------------------------------------------------------
131//------------------------------------------------------------------------------
132
133XPlane::~XPlane() throw()
134{
135 disconnect();
136 for(multiBuffers_t::iterator i = multiBuffers.begin();
137 i!=multiBuffers.end(); ++i)
138 {
139 MultiBuffer* buffer = *i;
140 buffer->forgetRegistration();
141 delete buffer;
142 }
143}
144
145//------------------------------------------------------------------------------
146
147void XPlane::connect() throw(IOException)
148{
149 if (socket!=0) return;
150
151 unique_ptr<LocalClientSocket> clientSocket(new LocalClientSocket("xplra",
152 &waiter));
153 LocalConnector& connector = clientSocket->getConnector();
154
155 while (!connector.connect()) {
156 if (connector.failed()) {
157 throw IOException(connector.getErrorCode());
158 }
159 waiter.wait();
160 if (waiter.failed()) {
161 throw IOException(waiter.getErrorCode());
162 }
163 }
164
165#ifndef _WIN32
166 signal(SIGPIPE, SIG_IGN);
167#endif
168
169 socket = clientSocket.release();
170 stream = new DataStream(*socket);
171
172 for(multiBuffers_t::iterator i = multiBuffers.begin();
173 i!=multiBuffers.end(); ++i)
174 {
175 MultiBuffer* buffer = *i;
176 buffer->reregisterInXPlane();
177 }
178}
179
180//------------------------------------------------------------------------------
181
182void XPlane::disconnect() throw()
183{
184 if (socket==0) return;
185
186 delete stream; stream = 0;
187 delete socket; socket = 0;
188}
189
190//------------------------------------------------------------------------------
191
192MultiGetter& XPlane::createMultiGetter() throw()
193{
194 MultiGetter* getter = new MultiGetter(*this);
195 multiBuffers.insert(getter);
196 return *getter;
197}
198
199//------------------------------------------------------------------------------
200
201MultiSetter& XPlane::createMultiSetter() throw()
202{
203 MultiSetter* setter = new MultiSetter(*this);
204 multiBuffers.insert(setter);
205 return *setter;
206}
207
208//------------------------------------------------------------------------------
209
210bool XPlane::destroyMultiBuffer(MultiBuffer& buffer) throw(Exception)
211{
212 multiBuffers_t::iterator i = multiBuffers.find(&buffer);
213 if (i==multiBuffers.end()) return false;
214
215 multiBuffers.erase(i);
216 delete &buffer;
217
218 return true;
219}
220
221//------------------------------------------------------------------------------
222
223void XPlane::getVersions(int& xplaneVersion, int& xplmVersion, int& xplraVersion)
224 throw(Exception)
225{
226 stream->writeU8(Protocol::COMMAND_GET_VERSIONS);
227 stream->flush();
228 checkResult();
229
230 xplaneVersion = stream->readS32();
231 xplmVersion = stream->readS32();
232 xplraVersion = stream->readS32();
233
234 checkStream();
235}
236
237//------------------------------------------------------------------------------
238
239void XPlane::reloadPlugins() throw(Exception)
240{
241 stream->writeU8(Protocol::COMMAND_RELOAD_PLUGINS);
242 stream->flush();
243 checkResult();
244}
245
246//------------------------------------------------------------------------------
247
248void XPlane::saveSituation(const char* path) throw(Exception)
249{
250 stream->writeU8(Protocol::COMMAND_SAVE_SITUATION);
251 stream->writeString(path);
252 stream->flush();
253 checkResult();
254}
255
256//------------------------------------------------------------------------------
257
258void XPlane::getScalar(const char* name, uint8_t type) throw(Exception)
259{
260 checkStream();
261
262 stream->writeU8(Protocol::COMMAND_GET_SINGLE);
263 stream->writeString(name, strlen(name));
264 stream->writeU8(type);
265 if (!stream->flush()) checkStream();
266
267 checkResult();
268}
269
270//------------------------------------------------------------------------------
271
272int XPlane::getInt(const char* name) throw(Exception)
273{
274 getScalar(name, Protocol::TYPE_INT);
275
276 int value = stream->readS32();
277 checkStream();
278 return value;
279}
280
281//------------------------------------------------------------------------------
282
283float XPlane::getFloat(const char* name) throw(Exception)
284{
285 getScalar(name, Protocol::TYPE_FLOAT);
286
287 float value = stream->readFloat();
288 checkStream();
289 return value;
290}
291
292//------------------------------------------------------------------------------
293
294double XPlane::getDouble(const char* name) throw(Exception)
295{
296 getScalar(name, Protocol::TYPE_DOUBLE);
297
298 double value = stream->readDouble();
299 checkStream();
300 return value;
301}
302
303//------------------------------------------------------------------------------
304
305size_t XPlane::getArray(const char* name, uint8_t type,
306 ssize_t length, size_t offset) throw(Exception)
307{
308 checkStream();
309
310 stream->writeU8(Protocol::COMMAND_GET_SINGLE);
311 stream->writeString(name, strlen(name));
312 stream->writeU8(type);
313 stream->writeS32(static_cast<int32_t>(length));
314 stream->writeS32(static_cast<int32_t>(offset));
315 if (!stream->flush()) checkStream();
316
317 uint8_t result = stream->readU8();
318 length = stream->readS32();
319 checkStream();
320 checkResult(result);
321
322 return length;
323}
324
325//------------------------------------------------------------------------------
326
327size_t XPlane::getFloatArray(const char* name, float* dest,
328 size_t length, size_t offset) throw(Exception)
329{
330 length = getArray(name, Protocol::TYPE_FLOAT_ARRAY, length, offset);
331
332 if (!stream->read(dest, length*sizeof(float))) checkStream();
333
334 return length;
335}
336
337//------------------------------------------------------------------------------
338
339float* XPlane::getFloatArray(const char* name, size_t& length,
340 size_t offset) throw(Exception)
341{
342 length = getArray(name, Protocol::TYPE_FLOAT_ARRAY, -1, offset);
343
344 unique_ptr<float[]> data(new float[length]);
345 if (!stream->read(data.get(), length*sizeof(float))) checkStream();
346 return data.release();
347}
348
349//------------------------------------------------------------------------------
350
351size_t XPlane::getIntArray(const char* name, int32_t* dest,
352 size_t length, size_t offset) throw(Exception)
353{
354 length = getArray(name, Protocol::TYPE_INT_ARRAY, length, offset);
355
356 if (!stream->read(dest, length*sizeof(int32_t))) checkStream();
357
358 return length;
359}
360
361//------------------------------------------------------------------------------
362
363int32_t* XPlane::getIntArray(const char* name, size_t& length,
364 size_t offset) throw(Exception)
365{
366 length = getArray(name, Protocol::TYPE_INT_ARRAY, -1, offset);
367
368 unique_ptr<int32_t[]> data(new int32_t[length]);
369 if (!stream->read(data.get(), length*sizeof(int32_t))) checkStream();
370 return data.release();
371}
372
373//------------------------------------------------------------------------------
374
375size_t XPlane::getByteArray(const char* name, uint8_t* dest,
376 size_t length, size_t offset) throw(Exception)
377{
378 length = getArray(name, Protocol::TYPE_BYTE_ARRAY, length, offset);
379
380 if (!stream->read(dest, length*sizeof(uint8_t))) checkStream();
381
382 return length;
383}
384
385//------------------------------------------------------------------------------
386
387uint8_t* XPlane::getByteArray(const char* name, size_t& length,
388 size_t offset) throw(Exception)
389{
390 length = getArray(name, Protocol::TYPE_BYTE_ARRAY, -1, offset);
391
392 unique_ptr<uint8_t[]> data(new uint8_t[length]);
393 if (!stream->read(data.get(), length*sizeof(uint8_t))) checkStream();
394 return data.release();
395}
396
397//------------------------------------------------------------------------------
398
399string XPlane::getString(const char* name, size_t offset) throw(Exception)
400{
401 size_t length = 0;
402 unique_ptr<uint8_t[]> data(getByteArray(name, length, offset));
403 return string(reinterpret_cast<char*>(data.get()));
404}
405
406//------------------------------------------------------------------------------
407
408void XPlane::setScalar(const char* name, uint8_t type) throw(Exception)
409{
410 stream->writeU8(Protocol::COMMAND_SET_SINGLE);
411 stream->writeString(name, strlen(name));
412 stream->writeU8(type);
413}
414
415//------------------------------------------------------------------------------
416
417void XPlane::setInt(const char* name, int value) throw(Exception)
418{
419 setScalar(name, Protocol::TYPE_INT);
420 stream->writeS32(value);
421 stream->flush();
422 checkResult();
423}
424
425//------------------------------------------------------------------------------
426
427void XPlane::setFloat(const char* name, float value) throw(Exception)
428{
429 setScalar(name, Protocol::TYPE_FLOAT);
430 stream->writeFloat(value);
431 stream->flush();
432 checkResult();
433}
434
435//------------------------------------------------------------------------------
436
437void XPlane::setDouble(const char* name, double value) throw(Exception)
438{
439 setScalar(name, Protocol::TYPE_DOUBLE);
440 stream->writeDouble(value);
441 stream->flush();
442 checkResult();
443}
444
445//------------------------------------------------------------------------------
446
447void XPlane::setArray(const char* name, uint8_t type, size_t length,
448 size_t offset) throw(Exception)
449{
450 stream->writeU8(Protocol::COMMAND_SET_SINGLE);
451 stream->writeString(name, strlen(name));
452 stream->writeU8(type);
453 stream->writeS32(static_cast<int32_t>(length));
454 stream->writeS32(static_cast<int32_t>(offset));
455}
456
457//------------------------------------------------------------------------------
458
459void XPlane::setFloatArray(const char* name, const float* values, size_t length,
460 size_t offset) throw(Exception)
461{
462 setArray(name, Protocol::TYPE_FLOAT_ARRAY, length, offset);
463 stream->write(values, length*sizeof(*values));
464 stream->flush();
465 checkResult();
466}
467
468//------------------------------------------------------------------------------
469
470void XPlane::setIntArray(const char* name, const int32_t* values, size_t length,
471 size_t offset) throw(Exception)
472{
473 setArray(name, Protocol::TYPE_INT_ARRAY, length, offset);
474 stream->write(values, length*sizeof(*values));
475 stream->flush();
476 checkResult();
477}
478
479//------------------------------------------------------------------------------
480
481void XPlane::setByteArray(const char* name, const uint8_t* values, size_t length,
482 size_t offset) throw(Exception)
483{
484 setArray(name, Protocol::TYPE_BYTE_ARRAY, length, offset);
485 stream->write(values, length*sizeof(*values));
486 stream->flush();
487 checkResult();
488}
489
490//------------------------------------------------------------------------------
491
492void XPlane::setString(const char* name, const char* value, size_t length,
493 size_t offset) throw(Exception)
494{
495 size_t valueLength = strlen(value);
496 if ((valueLength+1)>=length) {
497 setByteArray(name, reinterpret_cast<const uint8_t*>(value),
498 length, offset);
499 } else {
500 unique_ptr<uint8_t[]> buffer(new uint8_t[length]);
501 memcpy(buffer.get(), value, valueLength);
502 memset(buffer.get() + valueLength, 0, length - valueLength);
503 setByteArray(name, buffer.get(), length, offset);
504 }
505}
506
507//------------------------------------------------------------------------------
508
509void XPlane::showMessage(const char* message, float duration) throw(Exception)
510{
511 stream->writeU8(Protocol::COMMAND_SHOW_MESSAGE);
512 stream->writeString(message);
513 stream->writeFloat(duration);
514 stream->flush();
515 checkResult();
516}
517
518//------------------------------------------------------------------------------
519
520void XPlane::registerHotkeys(const uint16_t* codes, size_t length)
521 throw(Exception)
522{
523 stream->writeU8(Protocol::COMMAND_REGISTER_HOTKEYS);
524 stream->writeU32(length);
525 stream->write(codes, sizeof(uint16_t)*length);
526 stream->flush();
527 checkResult();
528}
529
530//------------------------------------------------------------------------------
531
532void XPlane::queryHotkeys(uint8_t* states, size_t length) throw(Exception)
533{
534 stream->writeU8(Protocol::COMMAND_QUERY_HOTKEYS);
535 stream->flush();
536 checkResult();
537
538 size_t count = stream->readU32();
539 checkStream();
540 stream->read(states, min(length, count));
541 if (length<count) {
542 while(length<count) {
543 stream->readU8();
544 ++length;
545 }
546 } else if (length>count) {
547 memset(states + count, 0, length - count);
548 }
549 checkStream();
550}
551
552//------------------------------------------------------------------------------
553
554void XPlane::unregisterHotkeys()
555{
556 stream->writeU8(Protocol::COMMAND_UNREGISTER_HOTKEYS);
557 stream->flush();
558 checkResult();
559}
560
561//------------------------------------------------------------------------------
562
563// Local Variables:
564// mode: C++
565// c-basic-offset: 4
566// indent-tabs-mode: nil
567// End:
Note: See TracBrowser for help on using the repository browser.