source: xplra/src/client/c/hu/varadiistvan/xplra/XPlane.cc@ 54:fb6a875ea5d2

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

Added support for the hotkey functions in the C++ client and a test program as well

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