source: xplra/src/client/c/hu/varadiistvan/xplra/XPlane.cc@ 57:f52efb9ba3d8

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

Implemented the C++ client part of the re-registration support

File size: 17.1 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;
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 auto_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::getScalar(const char* name, uint8_t type) throw(Exception)
249{
250 checkStream();
251
252 stream->writeU8(Protocol::COMMAND_GET_SINGLE);
253 stream->writeString(name, strlen(name));
254 stream->writeU8(type);
255 if (!stream->flush()) checkStream();
256
257 checkResult();
258}
259
260//------------------------------------------------------------------------------
261
262int XPlane::getInt(const char* name) throw(Exception)
263{
264 getScalar(name, Protocol::TYPE_INT);
265
266 int value = stream->readS32();
267 checkStream();
268 return value;
269}
270
271//------------------------------------------------------------------------------
272
273float XPlane::getFloat(const char* name) throw(Exception)
274{
275 getScalar(name, Protocol::TYPE_FLOAT);
276
277 float value = stream->readFloat();
278 checkStream();
279 return value;
280}
281
282//------------------------------------------------------------------------------
283
284double XPlane::getDouble(const char* name) throw(Exception)
285{
286 getScalar(name, Protocol::TYPE_DOUBLE);
287
288 double value = stream->readDouble();
289 checkStream();
290 return value;
291}
292
293//------------------------------------------------------------------------------
294
295size_t XPlane::getArray(const char* name, uint8_t type,
296 ssize_t length, size_t offset) throw(Exception)
297{
298 checkStream();
299
300 stream->writeU8(Protocol::COMMAND_GET_SINGLE);
301 stream->writeString(name, strlen(name));
302 stream->writeU8(type);
303 stream->writeS32(static_cast<int32_t>(length));
304 stream->writeS32(static_cast<int32_t>(offset));
305 if (!stream->flush()) checkStream();
306
307 uint8_t result = stream->readU8();
308 length = stream->readS32();
309 checkStream();
310 checkResult(result);
311
312 return length;
313}
314
315//------------------------------------------------------------------------------
316
317size_t XPlane::getFloatArray(const char* name, float* dest,
318 size_t length, size_t offset) throw(Exception)
319{
320 length = getArray(name, Protocol::TYPE_FLOAT_ARRAY, length, offset);
321
322 if (!stream->read(dest, length*sizeof(float))) checkStream();
323
324 return length;
325}
326
327//------------------------------------------------------------------------------
328
329float* XPlane::getFloatArray(const char* name, size_t& length,
330 size_t offset) throw(Exception)
331{
332 length = getArray(name, Protocol::TYPE_FLOAT_ARRAY, -1, offset);
333
334 auto_ptr<float> data(new float[length]);
335 if (!stream->read(data.get(), length*sizeof(float))) checkStream();
336 return data.release();
337}
338
339//------------------------------------------------------------------------------
340
341size_t XPlane::getIntArray(const char* name, int32_t* dest,
342 size_t length, size_t offset) throw(Exception)
343{
344 length = getArray(name, Protocol::TYPE_INT_ARRAY, length, offset);
345
346 if (!stream->read(dest, length*sizeof(int32_t))) checkStream();
347
348 return length;
349}
350
351//------------------------------------------------------------------------------
352
353int32_t* XPlane::getIntArray(const char* name, size_t& length,
354 size_t offset) throw(Exception)
355{
356 length = getArray(name, Protocol::TYPE_INT_ARRAY, -1, offset);
357
358 auto_ptr<int32_t> data(new int32_t[length]);
359 if (!stream->read(data.get(), length*sizeof(int32_t))) checkStream();
360 return data.release();
361}
362
363//------------------------------------------------------------------------------
364
365size_t XPlane::getByteArray(const char* name, uint8_t* dest,
366 size_t length, size_t offset) throw(Exception)
367{
368 length = getArray(name, Protocol::TYPE_BYTE_ARRAY, length, offset);
369
370 if (!stream->read(dest, length*sizeof(uint8_t))) checkStream();
371
372 return length;
373}
374
375//------------------------------------------------------------------------------
376
377uint8_t* XPlane::getByteArray(const char* name, size_t& length,
378 size_t offset) throw(Exception)
379{
380 length = getArray(name, Protocol::TYPE_BYTE_ARRAY, -1, offset);
381
382 auto_ptr<uint8_t> data(new uint8_t[length]);
383 if (!stream->read(data.get(), length*sizeof(uint8_t))) checkStream();
384 return data.release();
385}
386
387//------------------------------------------------------------------------------
388
389string XPlane::getString(const char* name, size_t offset) throw(Exception)
390{
391 size_t length = 0;
392 auto_ptr<uint8_t> data(getByteArray(name, length, offset));
393 return string(reinterpret_cast<char*>(data.get()));
394}
395
396//------------------------------------------------------------------------------
397
398void XPlane::setScalar(const char* name, uint8_t type) throw(Exception)
399{
400 stream->writeU8(Protocol::COMMAND_SET_SINGLE);
401 stream->writeString(name, strlen(name));
402 stream->writeU8(type);
403}
404
405//------------------------------------------------------------------------------
406
407void XPlane::setInt(const char* name, int value) throw(Exception)
408{
409 setScalar(name, Protocol::TYPE_INT);
410 stream->writeS32(value);
411 stream->flush();
412 checkResult();
413}
414
415//------------------------------------------------------------------------------
416
417void XPlane::setFloat(const char* name, float value) throw(Exception)
418{
419 setScalar(name, Protocol::TYPE_FLOAT);
420 stream->writeFloat(value);
421 stream->flush();
422 checkResult();
423}
424
425//------------------------------------------------------------------------------
426
427void XPlane::setDouble(const char* name, double value) throw(Exception)
428{
429 setScalar(name, Protocol::TYPE_DOUBLE);
430 stream->writeDouble(value);
431 stream->flush();
432 checkResult();
433}
434
435//------------------------------------------------------------------------------
436
437void XPlane::setArray(const char* name, uint8_t type, size_t length,
438 size_t offset) throw(Exception)
439{
440 stream->writeU8(Protocol::COMMAND_SET_SINGLE);
441 stream->writeString(name, strlen(name));
442 stream->writeU8(type);
443 stream->writeS32(static_cast<int32_t>(length));
444 stream->writeS32(static_cast<int32_t>(offset));
445}
446
447//------------------------------------------------------------------------------
448
449void XPlane::setFloatArray(const char* name, const float* values, size_t length,
450 size_t offset) throw(Exception)
451{
452 setArray(name, Protocol::TYPE_FLOAT_ARRAY, length, offset);
453 stream->write(values, length*sizeof(*values));
454 stream->flush();
455 checkResult();
456}
457
458//------------------------------------------------------------------------------
459
460void XPlane::setIntArray(const char* name, const int32_t* values, size_t length,
461 size_t offset) throw(Exception)
462{
463 setArray(name, Protocol::TYPE_INT_ARRAY, length, offset);
464 stream->write(values, length*sizeof(*values));
465 stream->flush();
466 checkResult();
467}
468
469//------------------------------------------------------------------------------
470
471void XPlane::setByteArray(const char* name, const uint8_t* values, size_t length,
472 size_t offset) throw(Exception)
473{
474 setArray(name, Protocol::TYPE_BYTE_ARRAY, length, offset);
475 stream->write(values, length*sizeof(*values));
476 stream->flush();
477 checkResult();
478}
479
480//------------------------------------------------------------------------------
481
482void XPlane::setString(const char* name, const char* value, size_t length,
483 size_t offset) throw(Exception)
484{
485 size_t valueLength = strlen(value);
486 if ((valueLength+1)>=length) {
487 setByteArray(name, reinterpret_cast<const uint8_t*>(value),
488 length, offset);
489 } else {
490 auto_ptr<uint8_t> buffer(new uint8_t[length]);
491 memcpy(buffer.get(), value, valueLength);
492 memset(buffer.get() + valueLength, 0, length - valueLength);
493 setByteArray(name, buffer.get(), length, offset);
494 }
495}
496
497//------------------------------------------------------------------------------
498
499void XPlane::showMessage(const char* message, float duration) throw(Exception)
500{
501 stream->writeU8(Protocol::COMMAND_SHOW_MESSAGE);
502 stream->writeString(message);
503 stream->writeFloat(duration);
504 stream->flush();
505 checkResult();
506}
507
508//------------------------------------------------------------------------------
509
510void XPlane::registerHotkeys(const uint16_t* codes, size_t length)
511 throw(Exception)
512{
513 stream->writeU8(Protocol::COMMAND_REGISTER_HOTKEYS);
514 stream->writeU32(length);
515 stream->write(codes, sizeof(uint16_t)*length);
516 stream->flush();
517 checkResult();
518}
519
520//------------------------------------------------------------------------------
521
522void XPlane::queryHotkeys(uint8_t* states, size_t length) throw(Exception)
523{
524 stream->writeU8(Protocol::COMMAND_QUERY_HOTKEYS);
525 stream->flush();
526 checkResult();
527
528 size_t count = stream->readU32();
529 checkStream();
530 stream->read(states, min(length, count));
531 if (length<count) {
532 while(length<count) {
533 stream->readU8();
534 ++length;
535 }
536 } else if (length>count) {
537 memset(states + count, 0, length - count);
538 }
539 checkStream();
540}
541
542//------------------------------------------------------------------------------
543
544void XPlane::unregisterHotkeys()
545{
546 stream->writeU8(Protocol::COMMAND_UNREGISTER_HOTKEYS);
547 stream->flush();
548 checkResult();
549}
550
551//------------------------------------------------------------------------------
552
553// Local Variables:
554// mode: C++
555// c-basic-offset: 4
556// indent-tabs-mode: nil
557// End:
Note: See TracBrowser for help on using the repository browser.