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
RevLine 
[13]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
[26]33#include "MultiGetter.h"
34#include "MultiSetter.h"
35
[14]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
[30]43#ifndef _WIN32
44#include <signal.h>
45#endif
46
[13]47//------------------------------------------------------------------------------
48
49using hu::varadiistvan::xplra::XPlane;
[26]50using hu::varadiistvan::xplra::MultiGetter;
51using hu::varadiistvan::xplra::MultiSetter;
[13]52
[14]53using hu::varadiistvan::scpl::io::LocalClientSocket;
54using hu::varadiistvan::scpl::io::LocalConnector;
55using hu::varadiistvan::scpl::io::DataStream;
56
57using xplra::Protocol;
58
[92]59using std::unique_ptr;
[16]60using std::string;
[54]61using std::min;
[14]62
[13]63//------------------------------------------------------------------------------
[14]64
[107]65void XPlane::checkStream()
[14]66{
67 if (stream==0) {
68 throw NotConnectedException();
69 } else if (stream->failed()) {
70 throw IOException(stream->getErrorCode());
71 }
72}
73
74//------------------------------------------------------------------------------
75
[107]76void XPlane::checkResult(uint8_t result, bool hasParameter, long parameter)
[14]77{
78 switch(result) {
79 case Protocol::RESULT_OK:
80 return;
81 case Protocol::RESULT_INVALID_COMMAND:
[40]82 throw ProtocolException(ProtocolException::INVALID_COMMAND,
83 hasParameter, parameter);
[14]84 case Protocol::RESULT_UNKNOWN_DATAREF:
[40]85 throw ProtocolException(ProtocolException::UNKNOWN_DATAREF,
86 hasParameter, parameter);
[14]87 case Protocol::RESULT_INVALID_TYPE:
[40]88 throw ProtocolException(ProtocolException::INVALID_TYPE,
89 hasParameter, parameter);
[14]90 case Protocol::RESULT_INVALID_LENGTH:
[40]91 throw ProtocolException(ProtocolException::INVALID_LENGTH,
92 hasParameter, parameter);
[14]93 case Protocol::RESULT_INVALID_OFFSET:
[40]94 throw ProtocolException(ProtocolException::INVALID_OFFSET,
95 hasParameter, parameter);
[14]96 case Protocol::RESULT_INVALID_COUNT:
[40]97 throw ProtocolException(ProtocolException::INVALID_COUNT,
98 hasParameter, parameter);
[14]99 case Protocol::RESULT_INVALID_ID:
[40]100 throw ProtocolException(ProtocolException::INVALID_ID,
101 hasParameter, parameter);
102 case Protocol::RESULT_INVALID_DURATION:
103 throw ProtocolException(ProtocolException::INVALID_DURATION,
104 hasParameter, parameter);
[14]105 case Protocol::RESULT_OTHER_ERROR:
106 default:
[40]107 throw ProtocolException(ProtocolException::OTHER,
108 hasParameter, parameter);
[14]109 }
110}
111
112//------------------------------------------------------------------------------
[17]113
[107]114void XPlane::checkResult(bool multi)
[17]115{
116 uint8_t result = stream->readU8();
[40]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 }
[17]125 checkStream();
[40]126 checkResult(result, hasParameter, parameter);
[17]127}
128
129//------------------------------------------------------------------------------
[14]130//------------------------------------------------------------------------------
131
[107]132XPlane::~XPlane() noexcept
[14]133{
134 disconnect();
[26]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 }
[14]142}
143
144//------------------------------------------------------------------------------
145
[107]146void XPlane::connect()
[14]147{
148 if (socket!=0) return;
149
[92]150 unique_ptr<LocalClientSocket> clientSocket(new LocalClientSocket("xplra",
151 &waiter));
[14]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
[30]164#ifndef _WIN32
165 signal(SIGPIPE, SIG_IGN);
166#endif
167
[14]168 socket = clientSocket.release();
169 stream = new DataStream(*socket);
[57]170
171 for(multiBuffers_t::iterator i = multiBuffers.begin();
172 i!=multiBuffers.end(); ++i)
173 {
174 MultiBuffer* buffer = *i;
175 buffer->reregisterInXPlane();
176 }
[14]177}
178
179//------------------------------------------------------------------------------
180
[107]181void XPlane::disconnect() noexcept
[14]182{
183 if (socket==0) return;
184
185 delete stream; stream = 0;
186 delete socket; socket = 0;
187}
188
189//------------------------------------------------------------------------------
190
[107]191MultiGetter& XPlane::createMultiGetter() noexcept
[26]192{
193 MultiGetter* getter = new MultiGetter(*this);
194 multiBuffers.insert(getter);
195 return *getter;
196}
197
198//------------------------------------------------------------------------------
199
[107]200MultiSetter& XPlane::createMultiSetter() noexcept
[26]201{
202 MultiSetter* setter = new MultiSetter(*this);
203 multiBuffers.insert(setter);
204 return *setter;
205}
206
207//------------------------------------------------------------------------------
208
[107]209bool XPlane::destroyMultiBuffer(MultiBuffer& buffer)
[26]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
[107]222void XPlane::getVersions(int& xplaneVersion, int& xplmVersion, int& xplraVersion)
[36]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
[107]237void XPlane::reloadPlugins()
[40]238{
239 stream->writeU8(Protocol::COMMAND_RELOAD_PLUGINS);
240 stream->flush();
241 checkResult();
242}
243
244//------------------------------------------------------------------------------
245
[107]246void XPlane::saveSituation(const char* path)
[87]247{
248 stream->writeU8(Protocol::COMMAND_SAVE_SITUATION);
249 stream->writeString(path);
250 stream->flush();
251 checkResult();
252}
253
254//------------------------------------------------------------------------------
255
[107]256void XPlane::getScalar(const char* name, uint8_t type)
[14]257{
258 checkStream();
259
260 stream->writeU8(Protocol::COMMAND_GET_SINGLE);
261 stream->writeString(name, strlen(name));
[15]262 stream->writeU8(type);
[14]263 if (!stream->flush()) checkStream();
264
[17]265 checkResult();
[15]266}
267
268//------------------------------------------------------------------------------
269
[107]270int XPlane::getInt(const char* name)
[15]271{
272 getScalar(name, Protocol::TYPE_INT);
[14]273
274 int value = stream->readS32();
275 checkStream();
276 return value;
277}
278
[13]279//------------------------------------------------------------------------------
280
[107]281float XPlane::getFloat(const char* name)
[15]282{
283 getScalar(name, Protocol::TYPE_FLOAT);
284
285 float value = stream->readFloat();
286 checkStream();
287 return value;
288}
289
290//------------------------------------------------------------------------------
291
[107]292double XPlane::getDouble(const char* name)
[15]293{
294 getScalar(name, Protocol::TYPE_DOUBLE);
295
296 double value = stream->readDouble();
297 checkStream();
298 return value;
299}
300
301//------------------------------------------------------------------------------
302
[16]303size_t XPlane::getArray(const char* name, uint8_t type,
[107]304 ssize_t length, size_t offset)
[16]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,
[107]326 size_t length, size_t offset)
[16]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,
[107]338 size_t offset)
[16]339{
340 length = getArray(name, Protocol::TYPE_FLOAT_ARRAY, -1, offset);
341
[92]342 unique_ptr<float[]> data(new float[length]);
[16]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,
[107]350 size_t length, size_t offset)
[16]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,
[107]362 size_t offset)
[16]363{
364 length = getArray(name, Protocol::TYPE_INT_ARRAY, -1, offset);
365
[92]366 unique_ptr<int32_t[]> data(new int32_t[length]);
[16]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,
[107]374 size_t length, size_t offset)
[16]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,
[107]386 size_t offset)
[16]387{
388 length = getArray(name, Protocol::TYPE_BYTE_ARRAY, -1, offset);
389
[92]390 unique_ptr<uint8_t[]> data(new uint8_t[length]);
[16]391 if (!stream->read(data.get(), length*sizeof(uint8_t))) checkStream();
392 return data.release();
393}
394
395//------------------------------------------------------------------------------
396
[107]397string XPlane::getString(const char* name, size_t offset)
[16]398{
399 size_t length = 0;
[92]400 unique_ptr<uint8_t[]> data(getByteArray(name, length, offset));
[16]401 return string(reinterpret_cast<char*>(data.get()));
402}
403
404//------------------------------------------------------------------------------
405
[107]406void XPlane::setScalar(const char* name, uint8_t type)
[17]407{
408 stream->writeU8(Protocol::COMMAND_SET_SINGLE);
409 stream->writeString(name, strlen(name));
410 stream->writeU8(type);
411}
412
413//------------------------------------------------------------------------------
414
[107]415void XPlane::setInt(const char* name, int value)
[17]416{
417 setScalar(name, Protocol::TYPE_INT);
418 stream->writeS32(value);
419 stream->flush();
420 checkResult();
421}
422
423//------------------------------------------------------------------------------
424
[107]425void XPlane::setFloat(const char* name, float value)
[17]426{
427 setScalar(name, Protocol::TYPE_FLOAT);
428 stream->writeFloat(value);
429 stream->flush();
430 checkResult();
431}
432
433//------------------------------------------------------------------------------
434
[107]435void XPlane::setDouble(const char* name, double value)
[17]436{
437 setScalar(name, Protocol::TYPE_DOUBLE);
438 stream->writeDouble(value);
439 stream->flush();
440 checkResult();
441}
442
443//------------------------------------------------------------------------------
444
[18]445void XPlane::setArray(const char* name, uint8_t type, size_t length,
[107]446 size_t offset)
[18]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,
[107]458 size_t offset)
[18]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,
[107]469 size_t offset)
[18]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,
[107]480 size_t offset)
[18]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,
[107]491 size_t offset)
[18]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 {
[92]498 unique_ptr<uint8_t[]> buffer(new uint8_t[length]);
[18]499 memcpy(buffer.get(), value, valueLength);
500 memset(buffer.get() + valueLength, 0, length - valueLength);
501 setByteArray(name, buffer.get(), length, offset);
502 }
503}
[40]504
505//------------------------------------------------------------------------------
506
[107]507void XPlane::showMessage(const char* message, float duration)
[40]508{
509 stream->writeU8(Protocol::COMMAND_SHOW_MESSAGE);
510 stream->writeString(message);
511 stream->writeFloat(duration);
512 stream->flush();
513 checkResult();
514}
515
[18]516//------------------------------------------------------------------------------
517
[54]518void XPlane::registerHotkeys(const uint16_t* codes, size_t length)
[107]519
[54]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
[107]530void XPlane::queryHotkeys(uint8_t* states, size_t length)
[54]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
[13]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.