source: xplra/src/client/c/hu/varadiistvan/xplra/XPlane.cc@ 107:614b9ff033c1

Last change on this file since 107:614b9ff033c1 was 107:614b9ff033c1, checked in by István Váradi <ivaradi@…>, 17 months ago

Modernized the exception specifications in the C++ client

File size: 16.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::unique_ptr;
60using std::string;
61using std::min;
62
63//------------------------------------------------------------------------------
64
65void XPlane::checkStream()
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{
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)
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() noexcept
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()
147{
148 if (socket!=0) return;
149
150 unique_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 for(multiBuffers_t::iterator i = multiBuffers.begin();
172 i!=multiBuffers.end(); ++i)
173 {
174 MultiBuffer* buffer = *i;
175 buffer->reregisterInXPlane();
176 }
177}
178
179//------------------------------------------------------------------------------
180
181void XPlane::disconnect() noexcept
182{
183 if (socket==0) return;
184
185 delete stream; stream = 0;
186 delete socket; socket = 0;
187}
188
189//------------------------------------------------------------------------------
190
191MultiGetter& XPlane::createMultiGetter() noexcept
192{
193 MultiGetter* getter = new MultiGetter(*this);
194 multiBuffers.insert(getter);
195 return *getter;
196}
197
198//------------------------------------------------------------------------------
199
200MultiSetter& XPlane::createMultiSetter() noexcept
201{
202 MultiSetter* setter = new MultiSetter(*this);
203 multiBuffers.insert(setter);
204 return *setter;
205}
206
207//------------------------------------------------------------------------------
208
209bool XPlane::destroyMultiBuffer(MultiBuffer& buffer)
210{
211 multiBuffers_t::iterator i = multiBuffers.find(&buffer);
212 if (i==multiBuffers.end()) return false;
213
214 multiBuffers.erase(i);
215 delete &buffer;
216
217 return true;
218}
219
220//------------------------------------------------------------------------------
221
222void XPlane::getVersions(int& xplaneVersion, int& xplmVersion, int& xplraVersion)
223{
224 stream->writeU8(Protocol::COMMAND_GET_VERSIONS);
225 stream->flush();
226 checkResult();
227
228 xplaneVersion = stream->readS32();
229 xplmVersion = stream->readS32();
230 xplraVersion = stream->readS32();
231
232 checkStream();
233}
234
235//------------------------------------------------------------------------------
236
237void XPlane::reloadPlugins()
238{
239 stream->writeU8(Protocol::COMMAND_RELOAD_PLUGINS);
240 stream->flush();
241 checkResult();
242}
243
244//------------------------------------------------------------------------------
245
246void XPlane::saveSituation(const char* path)
247{
248 stream->writeU8(Protocol::COMMAND_SAVE_SITUATION);
249 stream->writeString(path);
250 stream->flush();
251 checkResult();
252}
253
254//------------------------------------------------------------------------------
255
256void XPlane::getScalar(const char* name, uint8_t type)
257{
258 checkStream();
259
260 stream->writeU8(Protocol::COMMAND_GET_SINGLE);
261 stream->writeString(name, strlen(name));
262 stream->writeU8(type);
263 if (!stream->flush()) checkStream();
264
265 checkResult();
266}
267
268//------------------------------------------------------------------------------
269
270int XPlane::getInt(const char* name)
271{
272 getScalar(name, Protocol::TYPE_INT);
273
274 int value = stream->readS32();
275 checkStream();
276 return value;
277}
278
279//------------------------------------------------------------------------------
280
281float XPlane::getFloat(const char* name)
282{
283 getScalar(name, Protocol::TYPE_FLOAT);
284
285 float value = stream->readFloat();
286 checkStream();
287 return value;
288}
289
290//------------------------------------------------------------------------------
291
292double XPlane::getDouble(const char* name)
293{
294 getScalar(name, Protocol::TYPE_DOUBLE);
295
296 double value = stream->readDouble();
297 checkStream();
298 return value;
299}
300
301//------------------------------------------------------------------------------
302
303size_t XPlane::getArray(const char* name, uint8_t type,
304 ssize_t length, size_t offset)
305{
306 checkStream();
307
308 stream->writeU8(Protocol::COMMAND_GET_SINGLE);
309 stream->writeString(name, strlen(name));
310 stream->writeU8(type);
311 stream->writeS32(static_cast<int32_t>(length));
312 stream->writeS32(static_cast<int32_t>(offset));
313 if (!stream->flush()) checkStream();
314
315 uint8_t result = stream->readU8();
316 length = stream->readS32();
317 checkStream();
318 checkResult(result);
319
320 return length;
321}
322
323//------------------------------------------------------------------------------
324
325size_t XPlane::getFloatArray(const char* name, float* dest,
326 size_t length, size_t offset)
327{
328 length = getArray(name, Protocol::TYPE_FLOAT_ARRAY, length, offset);
329
330 if (!stream->read(dest, length*sizeof(float))) checkStream();
331
332 return length;
333}
334
335//------------------------------------------------------------------------------
336
337float* XPlane::getFloatArray(const char* name, size_t& length,
338 size_t offset)
339{
340 length = getArray(name, Protocol::TYPE_FLOAT_ARRAY, -1, offset);
341
342 unique_ptr<float[]> data(new float[length]);
343 if (!stream->read(data.get(), length*sizeof(float))) checkStream();
344 return data.release();
345}
346
347//------------------------------------------------------------------------------
348
349size_t XPlane::getIntArray(const char* name, int32_t* dest,
350 size_t length, size_t offset)
351{
352 length = getArray(name, Protocol::TYPE_INT_ARRAY, length, offset);
353
354 if (!stream->read(dest, length*sizeof(int32_t))) checkStream();
355
356 return length;
357}
358
359//------------------------------------------------------------------------------
360
361int32_t* XPlane::getIntArray(const char* name, size_t& length,
362 size_t offset)
363{
364 length = getArray(name, Protocol::TYPE_INT_ARRAY, -1, offset);
365
366 unique_ptr<int32_t[]> data(new int32_t[length]);
367 if (!stream->read(data.get(), length*sizeof(int32_t))) checkStream();
368 return data.release();
369}
370
371//------------------------------------------------------------------------------
372
373size_t XPlane::getByteArray(const char* name, uint8_t* dest,
374 size_t length, size_t offset)
375{
376 length = getArray(name, Protocol::TYPE_BYTE_ARRAY, length, offset);
377
378 if (!stream->read(dest, length*sizeof(uint8_t))) checkStream();
379
380 return length;
381}
382
383//------------------------------------------------------------------------------
384
385uint8_t* XPlane::getByteArray(const char* name, size_t& length,
386 size_t offset)
387{
388 length = getArray(name, Protocol::TYPE_BYTE_ARRAY, -1, offset);
389
390 unique_ptr<uint8_t[]> data(new uint8_t[length]);
391 if (!stream->read(data.get(), length*sizeof(uint8_t))) checkStream();
392 return data.release();
393}
394
395//------------------------------------------------------------------------------
396
397string XPlane::getString(const char* name, size_t offset)
398{
399 size_t length = 0;
400 unique_ptr<uint8_t[]> data(getByteArray(name, length, offset));
401 return string(reinterpret_cast<char*>(data.get()));
402}
403
404//------------------------------------------------------------------------------
405
406void XPlane::setScalar(const char* name, uint8_t type)
407{
408 stream->writeU8(Protocol::COMMAND_SET_SINGLE);
409 stream->writeString(name, strlen(name));
410 stream->writeU8(type);
411}
412
413//------------------------------------------------------------------------------
414
415void XPlane::setInt(const char* name, int value)
416{
417 setScalar(name, Protocol::TYPE_INT);
418 stream->writeS32(value);
419 stream->flush();
420 checkResult();
421}
422
423//------------------------------------------------------------------------------
424
425void XPlane::setFloat(const char* name, float value)
426{
427 setScalar(name, Protocol::TYPE_FLOAT);
428 stream->writeFloat(value);
429 stream->flush();
430 checkResult();
431}
432
433//------------------------------------------------------------------------------
434
435void XPlane::setDouble(const char* name, double value)
436{
437 setScalar(name, Protocol::TYPE_DOUBLE);
438 stream->writeDouble(value);
439 stream->flush();
440 checkResult();
441}
442
443//------------------------------------------------------------------------------
444
445void XPlane::setArray(const char* name, uint8_t type, size_t length,
446 size_t offset)
447{
448 stream->writeU8(Protocol::COMMAND_SET_SINGLE);
449 stream->writeString(name, strlen(name));
450 stream->writeU8(type);
451 stream->writeS32(static_cast<int32_t>(length));
452 stream->writeS32(static_cast<int32_t>(offset));
453}
454
455//------------------------------------------------------------------------------
456
457void XPlane::setFloatArray(const char* name, const float* values, size_t length,
458 size_t offset)
459{
460 setArray(name, Protocol::TYPE_FLOAT_ARRAY, length, offset);
461 stream->write(values, length*sizeof(*values));
462 stream->flush();
463 checkResult();
464}
465
466//------------------------------------------------------------------------------
467
468void XPlane::setIntArray(const char* name, const int32_t* values, size_t length,
469 size_t offset)
470{
471 setArray(name, Protocol::TYPE_INT_ARRAY, length, offset);
472 stream->write(values, length*sizeof(*values));
473 stream->flush();
474 checkResult();
475}
476
477//------------------------------------------------------------------------------
478
479void XPlane::setByteArray(const char* name, const uint8_t* values, size_t length,
480 size_t offset)
481{
482 setArray(name, Protocol::TYPE_BYTE_ARRAY, length, offset);
483 stream->write(values, length*sizeof(*values));
484 stream->flush();
485 checkResult();
486}
487
488//------------------------------------------------------------------------------
489
490void XPlane::setString(const char* name, const char* value, size_t length,
491 size_t offset)
492{
493 size_t valueLength = strlen(value);
494 if ((valueLength+1)>=length) {
495 setByteArray(name, reinterpret_cast<const uint8_t*>(value),
496 length, offset);
497 } else {
498 unique_ptr<uint8_t[]> buffer(new uint8_t[length]);
499 memcpy(buffer.get(), value, valueLength);
500 memset(buffer.get() + valueLength, 0, length - valueLength);
501 setByteArray(name, buffer.get(), length, offset);
502 }
503}
504
505//------------------------------------------------------------------------------
506
507void XPlane::showMessage(const char* message, float duration)
508{
509 stream->writeU8(Protocol::COMMAND_SHOW_MESSAGE);
510 stream->writeString(message);
511 stream->writeFloat(duration);
512 stream->flush();
513 checkResult();
514}
515
516//------------------------------------------------------------------------------
517
518void XPlane::registerHotkeys(const uint16_t* codes, size_t length)
519
520{
521 stream->writeU8(Protocol::COMMAND_REGISTER_HOTKEYS);
522 stream->writeU32(length);
523 stream->write(codes, sizeof(uint16_t)*length);
524 stream->flush();
525 checkResult();
526}
527
528//------------------------------------------------------------------------------
529
530void XPlane::queryHotkeys(uint8_t* states, size_t length)
531{
532 stream->writeU8(Protocol::COMMAND_QUERY_HOTKEYS);
533 stream->flush();
534 checkResult();
535
536 size_t count = stream->readU32();
537 checkStream();
538 stream->read(states, min(length, count));
539 if (length<count) {
540 while(length<count) {
541 stream->readU8();
542 ++length;
543 }
544 } else if (length>count) {
545 memset(states + count, 0, length - count);
546 }
547 checkStream();
548}
549
550//------------------------------------------------------------------------------
551
552void XPlane::unregisterHotkeys()
553{
554 stream->writeU8(Protocol::COMMAND_UNREGISTER_HOTKEYS);
555 stream->flush();
556 checkResult();
557}
558
559//------------------------------------------------------------------------------
560
561// Local Variables:
562// mode: C++
563// c-basic-offset: 4
564// indent-tabs-mode: nil
565// End:
Note: See TracBrowser for help on using the repository browser.