From 5d31544476efaf950709f45b747a0b26117ddff1 Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sat, 18 Apr 2020 11:30:36 -0700 Subject: [PATCH 01/19] Changed Lat/Lon/h to double in GetP --- xpcPlugin/MessageHandlers.cpp | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/xpcPlugin/MessageHandlers.cpp b/xpcPlugin/MessageHandlers.cpp index 2556fef..5163edc 100644 --- a/xpcPlugin/MessageHandlers.cpp +++ b/xpcPlugin/MessageHandlers.cpp @@ -24,7 +24,6 @@ #include "XPLMScenery.h" #include "XPLMGraphics.h" - #include #include #include @@ -32,7 +31,6 @@ #define MULTICAST_GROUP "239.255.1.1" #define MULITCAST_PORT 49710 - namespace XPC { std::map MessageHandlers::connections; @@ -560,21 +558,20 @@ namespace XPC unsigned char aircraft = buffer[5]; Log::FormatLine(LOG_TRACE, "GPOS", "Getting position information for aircraft %u", aircraft); - unsigned char response[34] = "POSI"; + unsigned char response[46] = "POSI"; response[5] = (char)DataManager::GetInt(DREF_GearHandle, aircraft); - // TODO change lat/lon/h to double? - *((float*)(response + 6)) = (float)DataManager::GetDouble(DREF_Latitude, aircraft); - *((float*)(response + 10)) = (float)DataManager::GetDouble(DREF_Longitude, aircraft); - *((float*)(response + 14)) = (float)DataManager::GetDouble(DREF_Elevation, aircraft); - *((float*)(response + 18)) = DataManager::GetFloat(DREF_Pitch, aircraft); - *((float*)(response + 22)) = DataManager::GetFloat(DREF_Roll, aircraft); - *((float*)(response + 26)) = DataManager::GetFloat(DREF_HeadingTrue, aircraft); + *((double*)(response + 6)) = DataManager::GetDouble(DREF_Latitude, aircraft); + *((double*)(response + 14)) = DataManager::GetDouble(DREF_Longitude, aircraft); + *((double*)(response + 22)) = DataManager::GetDouble(DREF_Elevation, aircraft); + *((float*)(response + 30)) = DataManager::GetFloat(DREF_Pitch, aircraft); + *((float*)(response + 34)) = DataManager::GetFloat(DREF_Roll, aircraft); + *((float*)(response + 38)) = DataManager::GetFloat(DREF_HeadingTrue, aircraft); float gear[10]; DataManager::GetFloatArray(DREF_GearDeploy, gear, 10, aircraft); - *((float*)(response + 30)) = gear[0]; + *((float*)(response + 42)) = gear[0]; - sock->SendTo(response, 34, &connection.addr); + sock->SendTo(response, 46, &connection.addr); } void MessageHandlers::HandlePosi(const Message& msg) @@ -594,6 +591,7 @@ namespace XPC { float posd_32[3]; memcpy(posd_32, buffer + 6, 12); + /* convert float to double */ posd[0] = posd_32[0]; posd[1] = posd_32[1]; posd[2] = posd_32[2]; @@ -612,7 +610,6 @@ namespace XPC return; } - /* convert float to double */ DataManager::SetPosition(posd, aircraftNumber); DataManager::SetOrientation(orient, aircraftNumber); if (gear >= 0) @@ -632,7 +629,7 @@ namespace XPC } } } - + void MessageHandlers::HandleGetT(const Message& msg) { const unsigned char* buffer = msg.GetBuffer(); From 113d664bfe6ebc3197534d42485a5566ee332761 Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sat, 18 Apr 2020 11:48:17 -0700 Subject: [PATCH 02/19] Changed getPOSI to double values --- C/src/xplaneConnect.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/C/src/xplaneConnect.h b/C/src/xplaneConnect.h index 8cfb06f..4a62b17 100644 --- a/C/src/xplaneConnect.h +++ b/C/src/xplaneConnect.h @@ -201,8 +201,9 @@ int getDREFs(XPCSocket sock, const char* drefs[], float* values[], unsigned char /// \param sock The socket used to send the command and receive the response. /// \param values An array to store the position information returned by the /// plugin. The format of values is [Lat, Lon, Alt, Pitch, Roll, Yaw, Gear] +/// \param ac The aircraft number to get the position of. 0 for the main/user's aircraft. /// \returns 0 if successful, otherwise a negative value. -int getPOSI(XPCSocket sock, float values[7], char ac); +int getPOSI(XPCSocket sock, double values[7], char ac); /// Sets the position and orientation of the specified aircraft. /// @@ -211,7 +212,7 @@ int getPOSI(XPCSocket sock, float values[7], char ac); /// [Lat, Lon, Alt, Pitch, Roll, Yaw, Gear]. If less than 7 values are specified, /// the unspecified values will be left unchanged. /// \param size The number of elements in values. -/// \param ac The aircraft number to set the position of. 0 for the player aircraft. +/// \param ac The aircraft number to set the position of. 0 for the main/user's aircraft. /// \returns 0 if successful, otherwise a negative value. int sendPOSI(XPCSocket sock, double values[], int size, char ac); @@ -223,7 +224,7 @@ int sendPOSI(XPCSocket sock, double values[], int size, char ac); /// \param values An array to store the position information returned by the /// plugin. The format of values is [Elevator, Aileron, Rudder, /// Throttle, Gear, Flaps, Speed Brakes] -/// \param ac The aircraft to set the control surfaces of. 0 is the main/player aircraft. +/// \param ac The aircraft to set the control surfaces of. 0 is the main/user's aircraft. /// \returns 0 if successful, otherwise a negative value. int getCTRL(XPCSocket sock, float values[7], char ac); @@ -234,7 +235,7 @@ int getCTRL(XPCSocket sock, float values[7], char ac); /// [Elevator, Aileron, Rudder, Throttle, Gear, Flaps, Speed Brakes]. If less than /// 6 values are specified, the unspecified values will be left unchanged. /// \param size The number of elements in values. -/// \param ac The aircraft number to set the control surfaces of. 0 for the player aircraft. +/// \param ac The aircraft to set the control surfaces of. 0 for the main/user's aircraft. /// \returns 0 if successful, otherwise a negative value. int sendCTRL(XPCSocket sock, float values[], int size, char ac); @@ -246,7 +247,7 @@ int sendCTRL(XPCSocket sock, float values[], int size, char ac); /// \param msg The message to print of the screen. /// \param x The distance in pixels from the left edge of the screen to print the text. /// \param y The distance in pixels from the bottom edge of the screen to print the top line of text. -/// \returns 0 if successful, otherwise a negative value. +/// \returns 0 if successful, otherwise a negative value. int sendTEXT(XPCSocket sock, char* msg, int x, int y); /// Sets the camera view in X-Plane. From 915e0591acf19f900bba26616d75bf92026a7078 Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sat, 18 Apr 2020 12:44:19 -0700 Subject: [PATCH 03/19] Changed getPOSI to double values Also fixed compiler warnings due to unsigned char for buffers. Changed to char. --- C/src/xplaneConnect.c | 51 +++++++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/C/src/xplaneConnect.c b/C/src/xplaneConnect.c index ed984fb..9425c94 100755 --- a/C/src/xplaneConnect.c +++ b/C/src/xplaneConnect.c @@ -387,7 +387,7 @@ int sendDREFs(XPCSocket sock, const char* drefs[], float* values[], int sizes[], { // Setup command // Max size is technically unlimited. - unsigned char buffer[65536] = "DREF"; + char buffer[65536] = "DREF"; int pos = 5; int i; // Iterator for (i = 0; i < count; ++i) @@ -433,7 +433,7 @@ int sendDREFRequest(XPCSocket sock, const char* drefs[], unsigned char count) // Setup command // 6 byte header + potentially 255 drefs, each 256 chars long. // Easiest to just round to an even 2^16. - unsigned char buffer[65536] = "GETD"; + char buffer[65536] = "GETD"; buffer[5] = count; int len = 6; int i; // iterator @@ -460,7 +460,7 @@ int sendDREFRequest(XPCSocket sock, const char* drefs[], unsigned char count) int getDREFResponse(XPCSocket sock, float* values[], unsigned char count, int sizes[]) { - unsigned char buffer[65536]; + char buffer[65536]; int result = readUDP(sock, buffer, 65536); if (result < 0) @@ -537,10 +537,10 @@ int getDREFs(XPCSocket sock, const char* drefs[], float* values[], unsigned char /*****************************************************************************/ /**** POSI functions ****/ /*****************************************************************************/ -int getPOSI(XPCSocket sock, float values[7], char ac) +int getPOSI(XPCSocket sock, double values[7], char ac) { // Setup send command - unsigned char buffer[6] = "GETP"; + char buffer[6] = "GETP"; buffer[5] = ac; // Send command @@ -551,22 +551,41 @@ int getPOSI(XPCSocket sock, float values[7], char ac) } // Get response - unsigned char readBuffer[34]; - int readResult = readUDP(sock, readBuffer, 34); + char readBuffer[46]; + float f[7]; + int readResult = readUDP(sock, readBuffer, 46); + + // Copy response into values if (readResult < 0) { printError("getPOSI", "Failed to read response."); return -2; } - if (readResult != 34) + else if (readResult == 34) /* lat/lon/h as 32-bit float */ + { + memcpy(f, readBuffer + 6, 7 * sizeof(float)); + values[0] = (double)f[0]; + values[1] = (double)f[1]; + values[2] = (double)f[2]; + values[3] = (double)f[3]; + values[4] = (double)f[4]; + values[5] = (double)f[5]; + values[6] = (double)f[6]; + } + else if (readResult == 46) /* lat/lon/h as 64-bit double */ + { + memcpy(values, readBuffer + 6, 3 * sizeof(double)); + memcpy(f, readBuffer + 30, 4 * sizeof(float)); + values[3] = (double)f[0]; + values[4] = (double)f[1]; + values[5] = (double)f[2]; + values[6] = (double)f[3]; + } + else { printError("getPOSI", "Unexpected response length."); return -3; } - // TODO: change this to the 64-bit lat/lon/h - - // Copy response into values - memcpy(values, readBuffer + 6, 7 * sizeof(float)); return 0; } @@ -585,7 +604,7 @@ int sendPOSI(XPCSocket sock, double values[], int size, char ac) } // Setup command - unsigned char buffer[46] = "POSI"; + char buffer[46] = "POSI"; buffer[4] = 0xff; //Placeholder for message length buffer[5] = ac; int i; // iterator @@ -627,7 +646,7 @@ int sendPOSI(XPCSocket sock, double values[], int size, char ac) int getCTRL(XPCSocket sock, float values[7], char ac) { // Setup send command - unsigned char buffer[6] = "GETC"; + char buffer[6] = "GETC"; buffer[5] = ac; // Send command @@ -638,7 +657,7 @@ int getCTRL(XPCSocket sock, float values[7], char ac) } // Get response - unsigned char readBuffer[31]; + char readBuffer[31]; int readResult = readUDP(sock, readBuffer, 31); if (readResult < 0) { @@ -675,7 +694,7 @@ int sendCTRL(XPCSocket sock, float values[], int size, char ac) // Setup Command // 5 byte header + 5 float values * 4 + 2 byte values - unsigned char buffer[31] = "CTRL"; + char buffer[31] = "CTRL"; int cur = 5; int i; // iterator for (i = 0; i < 6; i++) From 32bff7ffe47f00edb6f1f765929fda3ec66a4688 Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sat, 18 Apr 2020 12:55:55 -0700 Subject: [PATCH 04/19] Changed getPOSI to double posi Also fixed compiler error for timeval struct tv not defined for WIN32. --- C/monitorExample/main.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/C/monitorExample/main.c b/C/monitorExample/main.c index e6d2e62..e0af291 100644 --- a/C/monitorExample/main.c +++ b/C/monitorExample/main.c @@ -26,6 +26,8 @@ #include #include "stdio.h" +struct timeval tv; + #ifdef WIN32 HANDLE hStdIn = NULL; INPUT_RECORD buffer; @@ -51,7 +53,6 @@ int waitForInput() #else int fdstdin = 0; fd_set fds; -struct timeval tv; int waitForInput() { @@ -67,10 +68,10 @@ int main(void) { XPCSocket client = openUDP("127.0.0.1"); const int aircraftNum = 0; - tv.tv_usec = 100 * 1000; + tv.tv_usec = 100 * 1000; while (1) { - float posi[7]; // FIXME: change this to the 64-bit lat/lon/h + double posi[7]; int result = getPOSI(client, posi, aircraftNum); if (result < 0) // Error in getPOSI { From 53154e5908a5dabab38c80ae754948291d63270f Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sat, 18 Apr 2020 12:59:49 -0700 Subject: [PATCH 05/19] Changed getPOSI to double posi --- C/playbackExample/src/playback.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/C/playbackExample/src/playback.c b/C/playbackExample/src/playback.c index 4d2e594..dd92e45 100644 --- a/C/playbackExample/src/playback.c +++ b/C/playbackExample/src/playback.c @@ -65,7 +65,7 @@ void record(char* path, int interval, int duration) XPCSocket sock = openUDP("127.0.0.1"); for (int i = 0; i < count; ++i) { - float posi[7]; + double posi[7]; int result = getPOSI(sock, posi, 0); playbackSleep(interval); if (result < 0) From 79110a6f9102e408bd3285e20b926841a4854547 Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sat, 18 Apr 2020 15:05:35 -0700 Subject: [PATCH 06/19] getPOSI and sendPOSI fix to handle Lat/Lon/h doubles getPOSI now can interpret either float or double Lat/Lon/h messages. sendPOSI now sends double Lat/Lon/h messages. Also fixed integer conversion bug in sendCTRL. --- Python3/src/xpc.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/Python3/src/xpc.py b/Python3/src/xpc.py index ddf2be9..9c85942 100644 --- a/Python3/src/xpc.py +++ b/Python3/src/xpc.py @@ -1,7 +1,6 @@ import socket import struct - class XPlaneConnect(object): """XPlaneConnect (XPC) facilitates communication to and from the XPCPlugin.""" socket = None @@ -158,10 +157,13 @@ class XPlaneConnect(object): # Read response resultBuf = self.readUDP() - if len(resultBuf) != 34: + if len(resultBuf) == 34: + result = struct.unpack(b"<4sxBfffffff", resultBuf) + elif len(resultBuf) == 46: + result = struct.unpack(b"<4sxBdddffff", resultBuf) + else: raise ValueError("Unexpected response length.") - result = struct.unpack(b"<4sxBfffffff", resultBuf) if result[0] != b"POSI": raise ValueError("Unexpected header: " + result[0]) @@ -197,7 +199,10 @@ class XPlaneConnect(object): val = -998 if i < len(values): val = values[i] - buffer += struct.pack(b" Date: Sat, 18 Apr 2020 15:24:54 -0700 Subject: [PATCH 07/19] Python3 Tests created Created a Python3 compatible version of Tests.py --- TestScripts/Python3 Tests/Tests.py | 434 +++++++++++++++++++++++++++++ 1 file changed, 434 insertions(+) create mode 100644 TestScripts/Python3 Tests/Tests.py diff --git a/TestScripts/Python3 Tests/Tests.py b/TestScripts/Python3 Tests/Tests.py new file mode 100644 index 0000000..41e2bd4 --- /dev/null +++ b/TestScripts/Python3 Tests/Tests.py @@ -0,0 +1,434 @@ +import random +import unittest +import importlib +import time + +from importlib.machinery import SourceFileLoader +xpc = SourceFileLoader('xpc', '../../Python3/src/xpc.py').load_module() + +class XPCTests(unittest.TestCase): + """Tests the functionality of the XPlaneConnect class.""" + + def test_init(self): + try: + client = xpc.XPlaneConnect() + except: + self.fail("Default constructor failed.") + + try: + client = xpc.XPlaneConnect("I'm not a real host") + self.fail("Failed to catch invalid XP host.") + except ValueError: + pass + + try: + client = xpc.XPlaneConnect("127.0.0.1", 90001) + self.fail("Failed to catch invalid XP port.") + except ValueError: + pass + try: + client = xpc.XPlaneConnect("127.0.0.1", -1) + self.fail("Failed to catch invalid XP port.") + except ValueError: + pass + + try: + client = xpc.XPlaneConnect("127.0.0.1", 49009, 90001) + self.fail("Failed to catch invalid local port.") + except ValueError: + pass + try: + client = xpc.XPlaneConnect("127.0.0.1", 49009, -1) + self.fail("Failed to catch invalid XP port.") + except ValueError: + pass + + try: + client = xpc.XPlaneConnect("127.0.0.1", 49009, 0, -1) + self.fail("Failed to catch invalid timeout.") + except ValueError: + pass + + def test_close(self): + client = xpc.XPlaneConnect("127.0.0.1", 49009, 49063) + client.close() + self.assertIsNone(client.socket) + client = xpc.XPlaneConnect("127.0.0.1", 49009, 49063) + + def test_send_read(self): + # Init + test = "\x00\x01\x02\x03\x05" + + # Setup + sender = xpc.XPlaneConnect("127.0.0.1", 49063, 49064) + receiver = xpc.XPlaneConnect("127.0.0.1", 49009, 49063) + + # Execution + sender.sendUDP(test.encode()) + buf = receiver.readUDP() + + # Cleanup + sender.close() + receiver.close() + + # Tests + for a, b in zip(test, buf.decode()): + self.assertEqual(a, b) + + def test_getDREFs(self): + # Setup + client = xpc.XPlaneConnect() + drefs = ["sim/cockpit/switches/gear_handle_status",\ + "sim/cockpit2/switches/panel_brightness_ratio"] + + # Execution + result = client.getDREFs(drefs) + + # Cleanup + client.close() + + # Tests + self.assertEqual(2, len(result)) + self.assertEqual(1, len(result[0])) + self.assertEqual(4, len(result[1])) + + def test_sendDREF(self): + dref = "sim/cockpit/switches/gear_handle_status" + value = None + def do_test(): + # Setup + client = xpc.XPlaneConnect() + + # Execute + client.sendDREF(dref, value) + result = client.getDREF(dref) + + # Cleanup + client.close() + + # Tests + self.assertEqual(1, len(result)) + self.assertEqual(value, result[0]) + + # Test 1 + value = 1 + do_test() + + # Test 2 + value = 0 + do_test() + + def test_sendDREFs(self): + drefs = [\ + "sim/cockpit/switches/gear_handle_status",\ + "sim/cockpit/autopilot/altitude"] + values = None + def do_test(): + # Setup + client = xpc.XPlaneConnect() + + # Execute + client.sendDREFs(drefs, values) + result = client.getDREFs(drefs) + + # Cleanup + client.close() + + # Tests + self.assertEqual(2, len(result)) + self.assertEqual(1, len(result[0])) + self.assertEqual(values[0], result[0][0]) + self.assertEqual(1, len(result[1])) + self.assertEqual(values[1], result[1][0]) + + # Test 1 + values = [1, 2000] + do_test() + + # Test 2 + values = [0, 4000] + do_test() + + def test_sendDATA(self): + # Setup + dref = "sim/aircraft/parts/acf_gear_deploy" + data = [[ 14, 1, 0, -998, -998, -998, -998, -998, -998 ]] + client = xpc.XPlaneConnect() + + # Execute + client.sendDATA(data) + result = client.getDREF(dref) + + # Cleanup + client.close() + + #Tests + self.assertEqual(result[0], data[0][1]) + + def test_pauseSim(self): + dref = "sim/operation/override/override_planepath" + value = None + expected = None + def do_test(): + # Setup + client = xpc.XPlaneConnect() + + # Execute + client.pauseSim(value) + result = client.getDREF(dref) + + # Cleanup + client.close() + + # Test + self.assertAlmostEqual(expected, result[0]) + + # Test 1 + value = True + expected = 1.0 + do_test() + + # Test 2 + value = False + expected = 0.0 + do_test() + + # Test 3 + value = 1 + expected = 1.0 + do_test() + + # Test 4 + value = 2 + expected = 0.0 + do_test() + + def test_getCTRL(self): + values = None + ac = 0 + expected = None + def do_test(): + with xpc.XPlaneConnect() as client: + # Execute + client.sendCTRL(values, ac) + result = client.getCTRL(ac) + + # Test + self.assertEqual(len(result), len(expected)) + for a, e in zip(result, expected): + self.assertAlmostEqual(a, e, 4) + + values = [0.0, 0.0, 0.0, 0.8, 1.0, 0.5, -1.5] + expected = values + ac = 0 + do_test() + + ac = 3 + do_test() + + + def test_sendCTRL(self): + # Setup + drefs = ["sim/cockpit2/controls/yoke_pitch_ratio",\ + "sim/cockpit2/controls/yoke_roll_ratio",\ + "sim/cockpit2/controls/yoke_heading_ratio",\ + "sim/flightmodel/engine/ENGN_thro",\ + "sim/cockpit/switches/gear_handle_status",\ + "sim/flightmodel/controls/flaprqst"] + ctrl = [] + + def do_test(): + client = xpc.XPlaneConnect() + + # Execute + client.sendCTRL(ctrl) + result = client.getDREFs(drefs) + + # Cleanup + client.close() + + # Tests + self.assertEqual(6, len(result)) + for i in range(6): + self.assertAlmostEqual(ctrl[i], result[i][0], 4) + + # Test 1 + ctrl = [ -1.0, -1.0, -1.0, 0.0, 1.0, 1.0 ] + do_test() + + # Test 2 + ctrl = [ 1.0, 1.0, 1.0, 0.0, 1.0, 0.5 ] + do_test() + + # Test 2 + ctrl = [ 0.0, 0.0, 0.0, 0.8, 1.0, 0.0 ] + do_test() + + def test_sendCTRL_speedbrake(self): + # Setup + dref = "sim/flightmodel/controls/sbrkrqst" + ctrl = [] + + def do_test(): + client = xpc.XPlaneConnect() + + # Execute + client.sendCTRL(ctrl) + result = client.getDREF(dref) + + # Cleanup + client.close() + + # Tests + self.assertAlmostEqual(result[0], ctrl[6]) + + # Test 1 + ctrl = [-998, -998, -998, -998, -998, -998, -0.5] + do_test() + + # Test 2 + ctrl[6] = 1.0 + do_test() + + # Test 2 + ctrl[6] = 0.0 + do_test() + + def test_getPOSI(self): + values = None + ac = 0 + expected = None + def do_test(): + with xpc.XPlaneConnect() as client: + # Execute + client.pauseSim(True) + client.sendPOSI(values, ac) + result = client.getPOSI(ac) + client.pauseSim(False) + + # Test + self.assertEqual(len(result), len(expected)) + for a, e in zip(result, expected): + self.assertAlmostEqual(a, e, 4) + + values = [ 37.524, -122.06899, 2500, 45, -45, 15, 1 ] + expected = values + ac = 0 + do_test() + + ac = 3 + do_test() + + def test_sendPOSI(self): + # Setup + drefs = ["sim/flightmodel/position/latitude",\ + "sim/flightmodel/position/longitude",\ + "sim/flightmodel/position/elevation",\ + "sim/flightmodel/position/theta",\ + "sim/flightmodel/position/phi",\ + "sim/flightmodel/position/psi",\ + "sim/cockpit/switches/gear_handle_status"] + posi = None + def do_test(): + client = xpc.XPlaneConnect() + + # Execute + client.pauseSim(True) + client.sendPOSI(posi) + result = client.getDREFs(drefs) + client.pauseSim(False) + + # Cleanup + client.close() + + # Tests + self.assertEqual(7, len(result)) + for i in range(7): + self.assertAlmostEqual(posi[i], result[i][0], 4) + + # Test 1 + posi = [ 37.524, -122.06899, 2500, 5, 7, 11, 1 ] + do_test() + + # Test 2 + posi = [ 38, -121.0, 2000, -10, 0, 0, 0 ] + do_test() + + def test_sendTEXT(self): + # Setup + client = xpc.XPlaneConnect() + x = 200 + y = 700 + msg = "Python sendTEXT test message." + + # Execution + client.sendTEXT(msg, x, y) + # NOTE: Manually verify that msg appears on the screen in X-Plane + + # Cleanup + client.close() + + def test_sendView(self): + # Setup + dref = "sim/graphics/view/view_type" + fwd = 1000 + chase = 1017 + + #Execution + with xpc.XPlaneConnect() as client: + client.sendVIEW(xpc.ViewType.Forwards) + result = client.getDREF(dref) + self.assertAlmostEqual(fwd, result[0], 1e-4) + client.sendVIEW(xpc.ViewType.Chase) + result = client.getDREF(dref) + self.assertAlmostEqual(chase, result[0], 1e-4) + + + def test_sendWYPT(self): + # Setup + client = xpc.XPlaneConnect() + points = [\ + 37.5245, -122.06899, 2500,\ + 37.455397, -122.050037, 2500,\ + 37.469567, -122.051411, 2500,\ + 37.479376, -122.060509, 2300,\ + 37.482237, -122.076130, 2100,\ + 37.474881, -122.087288, 1900,\ + 37.467660, -122.079391, 1700,\ + 37.466298, -122.090549, 1500,\ + 37.362562, -122.039223, 1000,\ + 37.361448, -122.034416, 1000,\ + 37.361994, -122.026348, 1000,\ + 37.365541, -122.022572, 1000,\ + 37.373727, -122.024803, 1000,\ + 37.403869, -122.041283, 50,\ + 37.418544, -122.049222, 6] + + # Execution + client.sendPOSI([37.5245, -122.06899, 2500]) + client.sendWYPT(3, []) + client.sendWYPT(1, points) + # NOTE: Manually verify that points appear on the screen in X-Plane + + # Cleanup + client.close() + + def test_setCONN(self): + # Setup + dref = "sim/cockpit/switches/gear_handle_status"; + client = xpc.XPlaneConnect() + + # Execute + client.setCONN(49055) + result = client.getDREF(dref) + + # Cleanup + client.close() + + # Test + self.assertEqual(1, len(result)) + + + +if __name__ == '__main__': + unittest.main() From 0713a9553939274b3d250bef0f304551c1c037bc Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sat, 18 Apr 2020 15:26:54 -0700 Subject: [PATCH 08/19] Tests.pyproj copied from Python Tests --- TestScripts/Python3 Tests/Tests.pyproj | 45 ++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 TestScripts/Python3 Tests/Tests.pyproj diff --git a/TestScripts/Python3 Tests/Tests.pyproj b/TestScripts/Python3 Tests/Tests.pyproj new file mode 100644 index 0000000..c1626b5 --- /dev/null +++ b/TestScripts/Python3 Tests/Tests.pyproj @@ -0,0 +1,45 @@ + + + + Debug + 2.0 + 6931ebb2-4e01-4c5a-86b6-668c0e75051b + . + Tests.py + ..\..\Python\src\ + . + . + Tests + Tests + {9a7a9026-48c1-4688-9d5d-e5699d47d074} + 2.7 + + + true + false + + + true + false + + + + + + + + + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Python Tools\Microsoft.PythonTools.targets + + + + + + + + + + \ No newline at end of file From 132978b53dbcbbd78010fa7a1ad9863b95001b26 Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sat, 18 Apr 2020 22:19:53 -0700 Subject: [PATCH 09/19] Changed drefs to const char* to fix compiler warnings --- TestScripts/C Tests/CtrlTests.h | 38 ++++++++++++++++----------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/TestScripts/C Tests/CtrlTests.h b/TestScripts/C Tests/CtrlTests.h index 83e7d36..f000f4e 100644 --- a/TestScripts/C Tests/CtrlTests.h +++ b/TestScripts/C Tests/CtrlTests.h @@ -6,7 +6,7 @@ #include "Test.h" #include "xplaneConnect.h" -int doCTRLTest(XPCSocket *sock, char* drefs[7], float values[], int size, int ac, float expected[7]) +int doCTRLTest(XPCSocket *sock, const char* drefs[7], float values[], int size, int ac, float expected[7]) { float* data[7]; int sizes[7]; @@ -18,7 +18,7 @@ int doCTRLTest(XPCSocket *sock, char* drefs[7], float values[], int size, int ac // Execute command int result = sendCTRL(*sock, values, size, ac); - int d = 0.0f; + int d = 0.0f; if (result >= 0) { result = getDREFs(*sock, drefs, data, 7, sizes); @@ -66,19 +66,19 @@ int doGETCTest(float values[7], int ac, float expected[7]) return 0; } -int basicCTRLTest(char** drefs, int ac) +int basicCTRLTest(const char** drefs, int ac) { // Set control surfaces to known state. float CTRL[6] = { 0.0F, 0.0F, 0.0F, 0.8F, 1.0F, 0.5F }; float expected[7] = { 0.0F, 0.0F, 0.0F, NAN, NAN, NAN, NAN }; - XPCSocket sock = openUDP(IP); - pauseSim(sock, 1); // Pause so the controls wont change between 2 and 3 + XPCSocket sock = openUDP(IP); + pauseSim(sock, 1); // Pause so the controls wont change between 2 and 3 int result = doCTRLTest(&sock, drefs, CTRL, 3, ac, expected); if (result < 0) { return -10000 + result; } - crossPlatformUSleep(SLEEP_AMOUNT); + crossPlatformUSleep(SLEEP_AMOUNT); // Test control surfaces and set other values to known state. expected[0] = CTRL[0] = 0.2F; @@ -92,19 +92,19 @@ int basicCTRLTest(char** drefs, int ac) { return -20000 + result; } - crossPlatformUSleep(SLEEP_AMOUNT); + crossPlatformUSleep(SLEEP_AMOUNT); // Test other values and verify control surfaces unchanged. expected[0] = CTRL[0] = 0.15F; expected[1] = CTRL[1] = 0.15F; expected[2] = CTRL[2] = 0.15F; expected[3] = CTRL[3] = 0.9F; - CTRL[4] = -998; + CTRL[4] = -998; CTRL[5] = -998; result = doCTRLTest(&sock, drefs, CTRL, 6, ac, expected); - pauseSim(sock, 0); - closeUDP(sock); + pauseSim(sock, 0); + closeUDP(sock); if (result < 0) { if (result == -1004) { @@ -112,12 +112,12 @@ int basicCTRLTest(char** drefs, int ac) } return -30000 + result; } - return 0; + return 0; } int testCTRL_Player() { - char* drefs[] = + const char* drefs[] = { "sim/cockpit2/controls/yoke_pitch_ratio", "sim/cockpit2/controls/yoke_roll_ratio", @@ -132,7 +132,7 @@ int testCTRL_Player() int testCTRL_NonPlayer() { - char* drefs[] = + const char* drefs[] = { "sim/multiplayer/position/plane1_yolk_pitch", "sim/multiplayer/position/plane1_yolk_roll", @@ -147,7 +147,7 @@ int testCTRL_NonPlayer() int testCTRL_Speedbrakes() { - char* drefs[] = + const char* drefs[] = { "sim/cockpit2/controls/yoke_pitch_ratio", "sim/cockpit2/controls/yoke_roll_ratio", @@ -161,8 +161,8 @@ int testCTRL_Speedbrakes() // Arm float CTRL[7] = { -998, -998, -998, -998, -998, -998, -0.5F }; float expected[7] = { NAN, NAN, NAN, NAN, NAN, NAN, -0.5F }; - XPCSocket sock = openUDP(IP); - pauseSim(sock, 1); // Pause so the controls wont change between 2 and 3 + XPCSocket sock = openUDP(IP); + pauseSim(sock, 1); // Pause so the controls wont change between 2 and 3 int result = doCTRLTest(&sock, drefs, CTRL, 7, 0, expected); if (result < 0) { @@ -180,13 +180,13 @@ int testCTRL_Speedbrakes() // Retract expected[6] = CTRL[6] = 0.0F; result = doCTRLTest(&sock, drefs, CTRL, 7, 0, expected); - pauseSim(sock, 0); - closeUDP(sock); + pauseSim(sock, 0); + closeUDP(sock); if (result < 0) { return -30000 + result; } - return 0; + return 0; } int testGETC() From 1ff2e1b93eb11509eea7c235d8c747368f08a17d Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sat, 18 Apr 2020 22:23:36 -0700 Subject: [PATCH 10/19] Changed drefs to const char* to fix compiler warnings --- TestScripts/C Tests/DataTests.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TestScripts/C Tests/DataTests.h b/TestScripts/C Tests/DataTests.h index 4fde0ab..233602c 100644 --- a/TestScripts/C Tests/DataTests.h +++ b/TestScripts/C Tests/DataTests.h @@ -10,7 +10,7 @@ int testDATA() { // Initialize int i, j; // Iterator - char* drefs[100] = + const char* drefs[100] = { "sim/aircraft/parts/acf_gear_deploy" }; From 38ddc0adb28d46bfeb5ecc8d21a9a296215d6981 Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sat, 18 Apr 2020 22:29:17 -0700 Subject: [PATCH 11/19] Changed drefs to const char* to fix compiler warnings Also changed actual [7] to a double in doGETPTEST to fix compiler warning --- TestScripts/C Tests/PosiTests.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/TestScripts/C Tests/PosiTests.h b/TestScripts/C Tests/PosiTests.h index fc084ec..1b3983a 100644 --- a/TestScripts/C Tests/PosiTests.h +++ b/TestScripts/C Tests/PosiTests.h @@ -6,7 +6,7 @@ #include "Test.h" #include "xplaneConnect.h" -int doPOSITest(char* drefs[7], double values[], int size, int ac, double expected[7]) +int doPOSITest(const char* drefs[7], double values[], int size, int ac, double expected[7]) { float* data[7]; int sizes[7]; @@ -43,7 +43,7 @@ int doPOSITest(char* drefs[7], double values[], int size, int ac, double expecte int doGETPTest(double values[7], int ac, double expected[7]) { // Execute Test - float actual[7]; + double actual[7]; XPCSocket sock = openUDP(IP); int result = sendPOSI(sock, values, 7, ac); if (result >= 0) @@ -67,7 +67,7 @@ int doGETPTest(double values[7], int ac, double expected[7]) return 0; } -int basicPOSITest(char** drefs, int ac) +int basicPOSITest(const char** drefs, int ac) { // Set psoition and initial orientation double POSI[7] = { 37.524, -122.06899, 2500, 0, 0, 0, 1 }; @@ -110,12 +110,12 @@ int basicPOSITest(char** drefs, int ac) { return -20000 + result; } - return 0; + return 0; } int testPOSI_Player() { - char* drefs[] = + const char* drefs[] = { "sim/flightmodel/position/latitude", "sim/flightmodel/position/longitude", @@ -130,7 +130,7 @@ int testPOSI_Player() int testPOSI_NonPlayer() { - char* drefs[] = + const char* drefs[] = { "sim/multiplayer/position/plane1_lat", "sim/multiplayer/position/plane1_lon", From f17844565beb90e9c7cc85ef0a87bbed0ea5f9c5 Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sat, 18 Apr 2020 22:35:09 -0700 Subject: [PATCH 12/19] Changed drefs to const char* to fix compiler warnings Also fixed compiler warning related to doGETDTEST on line 108 --- TestScripts/C Tests/DrefTests.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/TestScripts/C Tests/DrefTests.h b/TestScripts/C Tests/DrefTests.h index c64ce6d..586b408 100644 --- a/TestScripts/C Tests/DrefTests.h +++ b/TestScripts/C Tests/DrefTests.h @@ -6,7 +6,7 @@ #include "Test.h" #include "xplaneConnect.h" -int doGETDTest(char* drefs[], float* expected[], int count, int sizes[]) +int doGETDTest(const char* drefs[], float* expected[], int count, int sizes[]) { // Setup memory int* asizes = (int*)malloc(sizeof(int) * count); @@ -37,7 +37,7 @@ int doGETDTest(char* drefs[], float* expected[], int count, int sizes[]) return result; } -int doDREFTest(char* drefs[], float* values[], float* expected[], int count, int sizes[]) +int doDREFTest(const char* drefs[], float* values[], float* expected[], int count, int sizes[]) { // Setup memory int* asizes = (int*)malloc(sizeof(int) * count); @@ -74,7 +74,7 @@ int doDREFTest(char* drefs[], float* values[], float* expected[], int count, int int testGETD_Basic() { - char* drefs[] = + const char* drefs[] = { "sim/cockpit/switches/gear_handle_status", //int "sim/cockpit/autopilot/altitude", //float @@ -99,20 +99,20 @@ int testGETD_Basic() int testGETD_TestFloat() { - char* dref = "sim/test/test_float"; + const char* dref = "sim/test/test_float"; int size = 1; float* expected[1]; expected[0] = (float*)malloc(sizeof(float)); expected[0][0] = 0.0F; - int result = doGETDTest(&dref, &expected, 1, &size); + int result = doGETDTest(&dref, expected, 1, &size); free(expected[0]); return result; } int testGETD_Types() { - char* drefs[] = + const char* drefs[] = { "sim/cockpit/switches/gear_handle_status", //int "sim/cockpit/autopilot/altitude", //float @@ -173,7 +173,7 @@ int testGETD_Types() int testDREF() { - char* drefs[] = + const char* drefs[] = { "sim/cockpit/switches/gear_handle_status", //int "sim/cockpit/autopilot/altitude", //float From ab9d0b7ea795a3cd20ec7d578b55135676058b2b Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sun, 19 Apr 2020 00:34:46 -0700 Subject: [PATCH 13/19] Added getTERR function --- C/src/xplaneConnect.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/C/src/xplaneConnect.h b/C/src/xplaneConnect.h index 4a62b17..9fa5faa 100644 --- a/C/src/xplaneConnect.h +++ b/C/src/xplaneConnect.h @@ -216,6 +216,24 @@ int getPOSI(XPCSocket sock, double values[7], char ac); /// \returns 0 if successful, otherwise a negative value. int sendPOSI(XPCSocket sock, double values[], int size, char ac); +// Terrain + +/// Gets the terrain information of the specified aircraft. +/// +/// \param sock The socket to use to send the command. +/// \param posi A double array representing position data about the aircraft. The format of values is +/// [Lat, Lon, Alt]. +/// -998 used for [Lat, Lon, Alt] to request terrain info at the current aircraft position. +/// \param values A double array with the information for the terrain output. The format of values is +/// [Lat, Lon, Alt, Nx, Ny, Nz, Vx, Vy, Vz, wet, result]. The first three are for output of +/// the Lat and Lon of the aircraft with the terrain height directly below. The next three +/// represent the terrain normal. The next three represent the velocity of the terrain. +/// The wet variable is 0.0 if the terrain is dry and 1.0 if wet. +/// The last output is the terrain probe result parameter. +/// \param ac The aircraft number to set the position of. 0 for the main/user's aircraft. +/// \returns 0 if successful, otherwise a negative value. +int getTERR(XPCSocket sock, double posi[3], double values[11], char ac); + // Controls /// Gets the control surface information for the specified aircraft. From 377e19f4c416e6d4936032ca804491722125fc31 Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sun, 19 Apr 2020 01:04:20 -0700 Subject: [PATCH 14/19] Added getTERR function --- C/src/xplaneConnect.c | 111 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 95 insertions(+), 16 deletions(-) diff --git a/C/src/xplaneConnect.c b/C/src/xplaneConnect.c index 9425c94..3aa34cb 100755 --- a/C/src/xplaneConnect.c +++ b/C/src/xplaneConnect.c @@ -58,6 +58,8 @@ int sendUDP(XPCSocket sock, char buffer[], int len); int readUDP(XPCSocket sock, char buffer[], int len); int sendDREFRequest(XPCSocket sock, const char* drefs[], unsigned char count); int getDREFResponse(XPCSocket sock, float* values[], unsigned char count, int sizes[]); +int sendTERRRequest(XPCSocket sock, double posi[3], char ac); +int getTERRResponse(XPCSocket sock, double values[11], char ac); void printError(char *functionName, char *format, ...) { @@ -314,7 +316,7 @@ int sendDATA(XPCSocket sock, float data[][9], int rows) char buffer[4829] = "DATA"; int len = 5 + rows * 9 * sizeof(float); unsigned short step = 9 * sizeof(float); - int i; // iterator + int i; // iterator for (i = 0; i < rows; i++) { buffer[5 + i * step] = (char)data[i][0]; @@ -363,7 +365,7 @@ int readDATA(XPCSocket sock, float data[][9], int rows) } // Parse data - int i; // iterator + int i; // iterator for (i = 0; i < rows; ++i) { data[i][0] = buffer[5 + i * 36]; @@ -389,7 +391,7 @@ int sendDREFs(XPCSocket sock, const char* drefs[], float* values[], int sizes[], // Max size is technically unlimited. char buffer[65536] = "DREF"; int pos = 5; - int i; // Iterator + int i; // Iterator for (i = 0; i < count; ++i) { int drefLen = strnlen(drefs[i], 256); @@ -436,7 +438,7 @@ int sendDREFRequest(XPCSocket sock, const char* drefs[], unsigned char count) char buffer[65536] = "GETD"; buffer[5] = count; int len = 6; - int i; // iterator + int i; // iterator for (i = 0; i < count; ++i) { size_t drefLen = strnlen(drefs[i], 256); @@ -463,15 +465,15 @@ int getDREFResponse(XPCSocket sock, float* values[], unsigned char count, int si char buffer[65536]; int result = readUDP(sock, buffer, 65536); - if (result < 0) - { + if (result < 0) + { #ifdef _WIN32 - printError("getDREFs", "Read operation failed. (%d)", WSAGetLastError()); + printError("getDREFs", "Read operation failed. (%d)", WSAGetLastError()); #else - printError("getDREFs", "Read operation failed."); + printError("getDREFs", "Read operation failed."); #endif - return -1; - } + return -1; + } if (result < 6) { @@ -485,7 +487,7 @@ int getDREFResponse(XPCSocket sock, float* values[], unsigned char count, int si } int cur = 6; - int i; // Iterator + int i; // Iterator for (i = 0; i < count; ++i) { int l = buffer[cur++]; @@ -607,8 +609,8 @@ int sendPOSI(XPCSocket sock, double values[], int size, char ac) char buffer[46] = "POSI"; buffer[4] = 0xff; //Placeholder for message length buffer[5] = ac; - int i; // iterator - + + int i; // iterator for (i = 0; i < 7; i++) // double for lat/lon/h { double val = -998; @@ -623,8 +625,8 @@ int sendPOSI(XPCSocket sock, double values[], int size, char ac) } else /* attitude and gear */ { - float f = (float)val; - memcpy(&buffer[18 + i*4], &f, sizeof(float)); + float f = (float)val; + memcpy(&buffer[18 + i*4], &f, sizeof(float)); } } @@ -640,6 +642,83 @@ int sendPOSI(XPCSocket sock, double values[], int size, char ac) /**** End POSI functions ****/ /*****************************************************************************/ +/*****************************************************************************/ +/**** TERR functions ****/ +/*****************************************************************************/ +int sendTERRRequest(XPCSocket sock, double posi[3], char ac) +{ + // Setup send command + char buffer[30] = "GETT"; + buffer[5] = ac; + memcpy(&buffer[6], posi, 3 * sizeof(double)); + + // Send command + if (sendUDP(sock, buffer, 30) < 0) + { + printError("getTERR", "Failed to send command."); + return -1; + } + return 0; +} + +int getTERRResponse(XPCSocket sock, double values[11], char ac) +{ + // Get response + char readBuffer[62]; + int readResult = readUDP(sock, readBuffer, 62); + if (readResult < 0) + { + printError("getTERR", "Failed to read response."); + return -2; + } + if (readResult != 62) + { + printError("getTERR", "Unexpected response length."); + return -3; + } + + // Copy response into outputs + float f[8]; + ac = readBuffer[5]; + memcpy(values, readBuffer + 6, 3 * sizeof(double)); + memcpy(f, readBuffer + 30, 8 * sizeof(float)); + values[ 3] = (double)f[0]; + values[ 4] = (double)f[1]; + values[ 5] = (double)f[2]; + values[ 6] = (double)f[3]; + values[ 7] = (double)f[4]; + values[ 8] = (double)f[5]; + values[ 9] = (double)f[6]; + values[10] = (double)f[7]; + + return 0; +} + +int getTERR(XPCSocket sock, double posi[3], double values[11], char ac) +{ + // Send Command + int result = sendTERRRequest(sock, posi, ac); + if (result < 0) + { + // An error ocurred while sending. + // sendTERRRequest will print an error message, so just return. + return result; + } + + // Read Response + result = getTERRResponse(sock, values, ac); + if (result < 0) + { + // An error ocurred while reading the response. + // getTERRResponse will print an error message, so just return. + return result; + } + return 0; +} +/*****************************************************************************/ +/**** End TERR functions ****/ +/*****************************************************************************/ + /*****************************************************************************/ /**** CTRL functions ****/ /*****************************************************************************/ @@ -696,7 +775,7 @@ int sendCTRL(XPCSocket sock, float values[], int size, char ac) // 5 byte header + 5 float values * 4 + 2 byte values char buffer[31] = "CTRL"; int cur = 5; - int i; // iterator + int i; // iterator for (i = 0; i < 6; i++) { float val = -998; From d61f70faad6e72774c8eb6769ca45da4b3720bac Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sun, 19 Apr 2020 10:03:58 -0700 Subject: [PATCH 15/19] Improved HandleGetT accuracy Also added the ground velocity output to TERR message so can handle landing on aircraft carrier (moving ground). --- xpcPlugin/MessageHandlers.cpp | 90 ++++++++++++++++++++++------------- 1 file changed, 56 insertions(+), 34 deletions(-) diff --git a/xpcPlugin/MessageHandlers.cpp b/xpcPlugin/MessageHandlers.cpp index 5163edc..05879d7 100644 --- a/xpcPlugin/MessageHandlers.cpp +++ b/xpcPlugin/MessageHandlers.cpp @@ -642,81 +642,103 @@ namespace XPC unsigned char aircraft = buffer[5]; Log::FormatLine(LOG_TRACE, "GETT", "Getting terrain information for aircraft %u", aircraft); - double loc[3]; - double X; - double Y; - double Z; - memcpy(loc, buffer + 6, 24); + double pos[3]; + memcpy(pos, buffer + 6, 24); - if(loc[0] == -998 || loc[1] == -998 || loc[2] == -998) + if(pos[0] == -998 || pos[1] == -998 || pos[2] == -998) { // get terrain properties at aircraft location - // probe needs to be below terrain to work... - X = DataManager::GetDouble(DREF_LocalX, aircraft); - Z = DataManager::GetDouble(DREF_LocalZ, aircraft); - Y = -100.0; - } - else - { - // terrain probe at specified location - XPLMWorldToLocal(loc[0], loc[1], loc[2], &X, &Y, &Z); + pos[0] = DataManager::GetDouble(DREF_Latitude, aircraft); + pos[1] = DataManager::GetDouble(DREF_Longitude, aircraft); + pos[2] = 0.0; } + MessageHandlers::SendTerr(pos, aircraft); + } + + void MessageHandlers::SendTerr(double pos[3], char aircraft) + { + double lat, lon, alt, X, Y, Z; // Init terrain probe (if required) and probe data struct - XPLMProbeInfo_t probe_data; + static XPLMProbeInfo_t probe_data; probe_data.structSize = sizeof(XPLMProbeInfo_t); if(Terrain_probe == nullptr) { - Log::FormatLine(LOG_TRACE, "GETT", "Create terrain probe for aircraft %u", aircraft); + Log::FormatLine(LOG_TRACE, "TERR", "Create terrain probe for aircraft %u", aircraft); Terrain_probe = XPLMCreateProbe(0); } + // terrain probe at specified location + // Follow the process in the following post to get accurate results + // https://forums.x-plane.org/index.php?/forums/topic/38688-how-do-i-use-xplmprobeterrainxyz/&page=2 + + // transform probe location to local coordinates + // Step 1. Convert initial lat/lon/alt to XYZ + XPLMWorldToLocal(pos[0], pos[1], pos[2], &X, &Y, &Z); + // query probe + // Step 2. Probe XYZ to get a new Y int rc = XPLMProbeTerrainXYZ(Terrain_probe, X, Y, Z, &probe_data); - + if(rc > 0) + { + Log::FormatLine(LOG_ERROR, "TERR", "Probe failed. Return Value %u", rc); + XPLMDestroyProbe(Terrain_probe); + return; + } + // transform probe location to world coordinates - double lat; - double lon; - double alt; - + // Step 3. Convert that new XYZ back to LLE + XPLMLocalToWorld(probe_data.locationX, probe_data.locationY, probe_data.locationZ, &lat, &lon, &alt); + Log::FormatLine(LOG_TRACE, "TERR", "Conv LLA=%f, %f, %f", lat, lon, alt); + + // transform probe location to local coordinates + // Step 4. NOW convert your origina lat/lon with the elevation from step 3 to XYZ + XPLMWorldToLocal(pos[0], pos[1], alt, &X, &Y, &Z); + + // query probe + // Step 5. Re-probe with the NEW XYZ + rc = XPLMProbeTerrainXYZ(Terrain_probe, X, Y, Z, &probe_data); if(rc == 0) { + // transform probe location to world coordinates + // Step 6. You now have a new Y, and your XYZ will be closer to correct for high elevations far from the origin. XPLMLocalToWorld(probe_data.locationX, probe_data.locationY, probe_data.locationZ, &lat, &lon, &alt); - - Log::FormatLine(LOG_TRACE, "GETT", "Probe LLA %lf %lf %lf", lat, lon, alt); + Log::FormatLine(LOG_TRACE, "TERR", "Probe LLA %lf %lf %lf", lat, lon, alt); } else { lat = -998; lon = -998; alt = -998; - - Log::FormatLine(LOG_TRACE, "GETT", "Probe failed. Return Value %u", rc); + Log::FormatLine(LOG_TRACE, "TERR", "Probe failed. Return Value %u", rc); } // keep probe for next query - // XPLMDestroyProbe(probe); + // XPLMDestroyProbe(Terrain_probe); // Assemble response message - unsigned char response[50] = "TERR"; + unsigned char response[62] = "TERR"; response[5] = aircraft; // terrain height over msl at lat/lon point memcpy(response + 6, &lat, 8); memcpy(response + 14, &lon, 8); memcpy(response + 22, &alt, 8); - // terrain incidence + // terrain normal vector memcpy(response + 30, &probe_data.normalX, 4); memcpy(response + 34, &probe_data.normalY, 4); memcpy(response + 38, &probe_data.normalZ, 4); + // terrain velocity + memcpy(response + 42, &probe_data.velocityX, 4); + memcpy(response + 46, &probe_data.velocityY, 4); + memcpy(response + 50, &probe_data.velocityZ, 4); // terrain type - memcpy(response + 42, &probe_data.is_wet, 4); + memcpy(response + 54, &probe_data.is_wet, 4); // probe status - memcpy(response + 46, &rc, 4); - - sock->SendTo(response, 50, &connection.addr); - } + memcpy(response + 58, &rc, 4); + sock->SendTo(response, 62, &connection.addr); + } void MessageHandlers::HandleSimu(const Message& msg) { From 6a483db8cc4a94415a84e43d1eb1a78756e7f265 Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sun, 19 Apr 2020 10:46:59 -0700 Subject: [PATCH 16/19] Python3 demos using Python2 syntax were run through 2to3, fixes nasa#191 --- Python3/src/basicExample.py | 30 ++++++++++----------- Python3/src/monitorExample.py | 4 +-- Python3/src/playbackExample.py | 48 +++++++++++++++++----------------- 3 files changed, 41 insertions(+), 41 deletions(-) diff --git a/Python3/src/basicExample.py b/Python3/src/basicExample.py index f381e5d..b42f2c1 100644 --- a/Python3/src/basicExample.py +++ b/Python3/src/basicExample.py @@ -2,8 +2,8 @@ from time import sleep import xpc def ex(): - print "X-Plane Connect example script" - print "Setting up simulation" + print("X-Plane Connect example script") + print("Setting up simulation") with xpc.XPlaneConnect() as client: # Verify connection try: @@ -11,24 +11,24 @@ def ex(): # will be raised. client.getDREF("sim/test/test_float") except: - print "Error establishing connection to X-Plane." - print "Exiting..." + print("Error establishing connection to X-Plane.") + print("Exiting...") return # Set position of the player aircraft - print "Setting position" + print("Setting position") # Lat Lon Alt Pitch Roll Yaw Gear posi = [37.524, -122.06899, 2500, 0, 0, 0, 1] client.sendPOSI(posi) # Set position of a non-player aircraft - print "Setting NPC position" + print("Setting NPC position") # Lat Lon Alt Pitch Roll Yaw Gear posi = [37.52465, -122.06899, 2500, 0, 20, 0, 1] client.sendPOSI(posi, 1) # Set angle of attack, velocity, and orientation using the DATA command - print "Setting orientation" + print("Setting orientation") data = [\ [18, 0, -998, 0, -998, -998, -998, -998, -998],\ [ 3, 130, 130, 130, 130, -998, -998, -998, -998],\ @@ -37,21 +37,21 @@ def ex(): client.sendDATA(data) # Set control surfaces and throttle of the player aircraft using sendCTRL - print "Setting controls" + print("Setting controls") ctrl = [0.0, 0.0, 0.0, 0.8] client.sendCTRL(ctrl) # Pause the sim - print "Pausing" + print("Pausing") client.pauseSim(True) sleep(2) # Toggle pause state to resume - print "Resuming" + print("Resuming") client.pauseSim(False) # Stow landing gear using a dataref - print "Stowing gear" + print("Stowing gear") gear_dref = "sim/cockpit/switches/gear_handle_status" client.sendDREF(gear_dref, 0) @@ -61,12 +61,12 @@ def ex(): # Make sure gear was stowed successfully gear_status = client.getDREF(gear_dref) if gear_status[0] == 0: - print "Gear stowed" + print("Gear stowed") else: - print "Error stowing gear" + print("Error stowing gear") - print "End of Python client example" - raw_input("Press any key to exit...") + print("End of Python client example") + input("Press any key to exit...") if __name__ == "__main__": ex() \ No newline at end of file diff --git a/Python3/src/monitorExample.py b/Python3/src/monitorExample.py index c4cdb48..562ac53 100644 --- a/Python3/src/monitorExample.py +++ b/Python3/src/monitorExample.py @@ -8,8 +8,8 @@ def monitor(): posi = client.getPOSI(); ctrl = client.getCTRL(); - print "Loc: (%4f, %4f, %4f) Aileron:%2f Elevator:%2f Rudder:%2f\n"\ - % (posi[0], posi[1], posi[2], ctrl[1], ctrl[0], ctrl[2]) + print("Loc: (%4f, %4f, %4f) Aileron:%2f Elevator:%2f Rudder:%2f\n"\ + % (posi[0], posi[1], posi[2], ctrl[1], ctrl[0], ctrl[2])) if __name__ == "__main__": diff --git a/Python3/src/playbackExample.py b/Python3/src/playbackExample.py index dfa4f52..17eb2f1 100644 --- a/Python3/src/playbackExample.py +++ b/Python3/src/playbackExample.py @@ -5,78 +5,78 @@ def record(path, interval = 0.1, duration = 60): try: fd = open(path, "w") except: - print "Unable to open file." + print("Unable to open file.") return count = int(duration / interval) if count < 1: - print "duration is less than a single frame." + print("duration is less than a single frame.") return with xpc.XPlaneConnect("localhost", 49009, 0, 1000) as client: - print "Recording..." + print("Recording...") for i in range(0, count): try: posi = client.getPOSI() fd.write("{0}, {1}, {2}, {3}, {4}, {5}, {6}\n".format(*posi)) except: - print "Error reading position" + print("Error reading position") continue sleep(interval); - print "Recording Complete" + print("Recording Complete") fd.close() def playback(path, interval): try: fd = open(path, "r") except: - print "Unable to open file." + print("Unable to open file.") return with xpc.XPlaneConnect("localhost", 49009, 0, 1000) as client: - print "Starting Playback..." + print("Starting Playback...") for line in fd: try: posi = [ float(x) for x in line.split(',') ] posi = client.sendPOSI(posi) except: - print "Error sending position" + print("Error sending position") continue sleep(interval); - print "Playback Complete" + print("Playback Complete") fd.close() def printMenu(title, opts): - print "\n+---------------------------------------------- +" - print "| {0:42} |\n".format(title) - print "+---------------------------------------------- +" + print("\n+---------------------------------------------- +") + print("| {0:42} |\n".format(title)) + print("+---------------------------------------------- +") for i in range(0,len(opts)): - print "| {0:2}. {1:40} |".format(i + 1, opts[i]) - print "+---------------------------------------------- +" - return int(raw_input("Please select and option: ")) + print("| {0:2}. {1:40} |".format(i + 1, opts[i])) + print("+---------------------------------------------- +") + return int(input("Please select and option: ")) def ex(): - print "X-Plane Connect Playback Example [Version 1.2.0]" - print "(c) 2013-2015 United States Government as represented by the Administrator" - print "of the National Aeronautics and Space Administration. All Rights Reserved." + print("X-Plane Connect Playback Example [Version 1.2.0]") + print("(c) 2013-2015 United States Government as represented by the Administrator") + print("of the National Aeronautics and Space Administration. All Rights Reserved.") mainOpts = [ "Record X-Plane", "Playback File", "Exit" ] while True: opt = printMenu("What would you like to do?", mainOpts) if opt == 1: - path = raw_input("Enter save file path: ") - interval = float(raw_input("Enter interval between frames (seconds): ")) - duration = float(raw_input("Enter duration to record for (seconds): ")) + path = input("Enter save file path: ") + interval = float(input("Enter interval between frames (seconds): ")) + duration = float(input("Enter duration to record for (seconds): ")) record(path, interval, duration) elif opt == 2: - path = raw_input("Enter save file path: ") - interval = float(raw_input("Enter interval between frames (seconds): ")) + path = input("Enter save file path: ") + interval = float(input("Enter interval between frames (seconds): ")) playback(path, interval) elif opt == 3: return; else: - print "Unrecognized option." + print("Unrecognized option.") if __name__ == "__main__": ex() \ No newline at end of file From f37f4a4aaebd410065cf5d638fbdcc4a6cd59346 Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sun, 19 Apr 2020 11:36:51 -0700 Subject: [PATCH 17/19] Revert "Improved HandleGetT accuracy" This reverts commit d61f70faad6e72774c8eb6769ca45da4b3720bac. --- xpcPlugin/MessageHandlers.cpp | 90 +++++++++++++---------------------- 1 file changed, 34 insertions(+), 56 deletions(-) diff --git a/xpcPlugin/MessageHandlers.cpp b/xpcPlugin/MessageHandlers.cpp index 05879d7..5163edc 100644 --- a/xpcPlugin/MessageHandlers.cpp +++ b/xpcPlugin/MessageHandlers.cpp @@ -642,104 +642,82 @@ namespace XPC unsigned char aircraft = buffer[5]; Log::FormatLine(LOG_TRACE, "GETT", "Getting terrain information for aircraft %u", aircraft); - double pos[3]; - memcpy(pos, buffer + 6, 24); + double loc[3]; + double X; + double Y; + double Z; + memcpy(loc, buffer + 6, 24); - if(pos[0] == -998 || pos[1] == -998 || pos[2] == -998) + if(loc[0] == -998 || loc[1] == -998 || loc[2] == -998) { // get terrain properties at aircraft location - pos[0] = DataManager::GetDouble(DREF_Latitude, aircraft); - pos[1] = DataManager::GetDouble(DREF_Longitude, aircraft); - pos[2] = 0.0; + // probe needs to be below terrain to work... + X = DataManager::GetDouble(DREF_LocalX, aircraft); + Z = DataManager::GetDouble(DREF_LocalZ, aircraft); + Y = -100.0; + } + else + { + // terrain probe at specified location + XPLMWorldToLocal(loc[0], loc[1], loc[2], &X, &Y, &Z); } - MessageHandlers::SendTerr(pos, aircraft); - } - - void MessageHandlers::SendTerr(double pos[3], char aircraft) - { - double lat, lon, alt, X, Y, Z; // Init terrain probe (if required) and probe data struct - static XPLMProbeInfo_t probe_data; + XPLMProbeInfo_t probe_data; probe_data.structSize = sizeof(XPLMProbeInfo_t); if(Terrain_probe == nullptr) { - Log::FormatLine(LOG_TRACE, "TERR", "Create terrain probe for aircraft %u", aircraft); + Log::FormatLine(LOG_TRACE, "GETT", "Create terrain probe for aircraft %u", aircraft); Terrain_probe = XPLMCreateProbe(0); } - // terrain probe at specified location - // Follow the process in the following post to get accurate results - // https://forums.x-plane.org/index.php?/forums/topic/38688-how-do-i-use-xplmprobeterrainxyz/&page=2 - - // transform probe location to local coordinates - // Step 1. Convert initial lat/lon/alt to XYZ - XPLMWorldToLocal(pos[0], pos[1], pos[2], &X, &Y, &Z); - // query probe - // Step 2. Probe XYZ to get a new Y int rc = XPLMProbeTerrainXYZ(Terrain_probe, X, Y, Z, &probe_data); - if(rc > 0) - { - Log::FormatLine(LOG_ERROR, "TERR", "Probe failed. Return Value %u", rc); - XPLMDestroyProbe(Terrain_probe); - return; - } - + // transform probe location to world coordinates - // Step 3. Convert that new XYZ back to LLE - XPLMLocalToWorld(probe_data.locationX, probe_data.locationY, probe_data.locationZ, &lat, &lon, &alt); - Log::FormatLine(LOG_TRACE, "TERR", "Conv LLA=%f, %f, %f", lat, lon, alt); - - // transform probe location to local coordinates - // Step 4. NOW convert your origina lat/lon with the elevation from step 3 to XYZ - XPLMWorldToLocal(pos[0], pos[1], alt, &X, &Y, &Z); - - // query probe - // Step 5. Re-probe with the NEW XYZ - rc = XPLMProbeTerrainXYZ(Terrain_probe, X, Y, Z, &probe_data); + double lat; + double lon; + double alt; + if(rc == 0) { - // transform probe location to world coordinates - // Step 6. You now have a new Y, and your XYZ will be closer to correct for high elevations far from the origin. XPLMLocalToWorld(probe_data.locationX, probe_data.locationY, probe_data.locationZ, &lat, &lon, &alt); - Log::FormatLine(LOG_TRACE, "TERR", "Probe LLA %lf %lf %lf", lat, lon, alt); + + Log::FormatLine(LOG_TRACE, "GETT", "Probe LLA %lf %lf %lf", lat, lon, alt); } else { lat = -998; lon = -998; alt = -998; - Log::FormatLine(LOG_TRACE, "TERR", "Probe failed. Return Value %u", rc); + + Log::FormatLine(LOG_TRACE, "GETT", "Probe failed. Return Value %u", rc); } // keep probe for next query - // XPLMDestroyProbe(Terrain_probe); + // XPLMDestroyProbe(probe); // Assemble response message - unsigned char response[62] = "TERR"; + unsigned char response[50] = "TERR"; response[5] = aircraft; // terrain height over msl at lat/lon point memcpy(response + 6, &lat, 8); memcpy(response + 14, &lon, 8); memcpy(response + 22, &alt, 8); - // terrain normal vector + // terrain incidence memcpy(response + 30, &probe_data.normalX, 4); memcpy(response + 34, &probe_data.normalY, 4); memcpy(response + 38, &probe_data.normalZ, 4); - // terrain velocity - memcpy(response + 42, &probe_data.velocityX, 4); - memcpy(response + 46, &probe_data.velocityY, 4); - memcpy(response + 50, &probe_data.velocityZ, 4); // terrain type - memcpy(response + 54, &probe_data.is_wet, 4); + memcpy(response + 42, &probe_data.is_wet, 4); // probe status - memcpy(response + 58, &rc, 4); - - sock->SendTo(response, 62, &connection.addr); + memcpy(response + 46, &rc, 4); + + sock->SendTo(response, 50, &connection.addr); } + void MessageHandlers::HandleSimu(const Message& msg) { // Update log From 97c87b48b86d831a0e33c5e748c87f8eafdec2ce Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sun, 19 Apr 2020 11:37:07 -0700 Subject: [PATCH 18/19] Revert "Added getTERR function" This reverts commit 377e19f4c416e6d4936032ca804491722125fc31. --- C/src/xplaneConnect.c | 111 ++++++------------------------------------ 1 file changed, 16 insertions(+), 95 deletions(-) diff --git a/C/src/xplaneConnect.c b/C/src/xplaneConnect.c index 3aa34cb..9425c94 100755 --- a/C/src/xplaneConnect.c +++ b/C/src/xplaneConnect.c @@ -58,8 +58,6 @@ int sendUDP(XPCSocket sock, char buffer[], int len); int readUDP(XPCSocket sock, char buffer[], int len); int sendDREFRequest(XPCSocket sock, const char* drefs[], unsigned char count); int getDREFResponse(XPCSocket sock, float* values[], unsigned char count, int sizes[]); -int sendTERRRequest(XPCSocket sock, double posi[3], char ac); -int getTERRResponse(XPCSocket sock, double values[11], char ac); void printError(char *functionName, char *format, ...) { @@ -316,7 +314,7 @@ int sendDATA(XPCSocket sock, float data[][9], int rows) char buffer[4829] = "DATA"; int len = 5 + rows * 9 * sizeof(float); unsigned short step = 9 * sizeof(float); - int i; // iterator + int i; // iterator for (i = 0; i < rows; i++) { buffer[5 + i * step] = (char)data[i][0]; @@ -365,7 +363,7 @@ int readDATA(XPCSocket sock, float data[][9], int rows) } // Parse data - int i; // iterator + int i; // iterator for (i = 0; i < rows; ++i) { data[i][0] = buffer[5 + i * 36]; @@ -391,7 +389,7 @@ int sendDREFs(XPCSocket sock, const char* drefs[], float* values[], int sizes[], // Max size is technically unlimited. char buffer[65536] = "DREF"; int pos = 5; - int i; // Iterator + int i; // Iterator for (i = 0; i < count; ++i) { int drefLen = strnlen(drefs[i], 256); @@ -438,7 +436,7 @@ int sendDREFRequest(XPCSocket sock, const char* drefs[], unsigned char count) char buffer[65536] = "GETD"; buffer[5] = count; int len = 6; - int i; // iterator + int i; // iterator for (i = 0; i < count; ++i) { size_t drefLen = strnlen(drefs[i], 256); @@ -465,15 +463,15 @@ int getDREFResponse(XPCSocket sock, float* values[], unsigned char count, int si char buffer[65536]; int result = readUDP(sock, buffer, 65536); - if (result < 0) - { + if (result < 0) + { #ifdef _WIN32 - printError("getDREFs", "Read operation failed. (%d)", WSAGetLastError()); + printError("getDREFs", "Read operation failed. (%d)", WSAGetLastError()); #else - printError("getDREFs", "Read operation failed."); + printError("getDREFs", "Read operation failed."); #endif - return -1; - } + return -1; + } if (result < 6) { @@ -487,7 +485,7 @@ int getDREFResponse(XPCSocket sock, float* values[], unsigned char count, int si } int cur = 6; - int i; // Iterator + int i; // Iterator for (i = 0; i < count; ++i) { int l = buffer[cur++]; @@ -609,8 +607,8 @@ int sendPOSI(XPCSocket sock, double values[], int size, char ac) char buffer[46] = "POSI"; buffer[4] = 0xff; //Placeholder for message length buffer[5] = ac; - - int i; // iterator + int i; // iterator + for (i = 0; i < 7; i++) // double for lat/lon/h { double val = -998; @@ -625,8 +623,8 @@ int sendPOSI(XPCSocket sock, double values[], int size, char ac) } else /* attitude and gear */ { - float f = (float)val; - memcpy(&buffer[18 + i*4], &f, sizeof(float)); + float f = (float)val; + memcpy(&buffer[18 + i*4], &f, sizeof(float)); } } @@ -642,83 +640,6 @@ int sendPOSI(XPCSocket sock, double values[], int size, char ac) /**** End POSI functions ****/ /*****************************************************************************/ -/*****************************************************************************/ -/**** TERR functions ****/ -/*****************************************************************************/ -int sendTERRRequest(XPCSocket sock, double posi[3], char ac) -{ - // Setup send command - char buffer[30] = "GETT"; - buffer[5] = ac; - memcpy(&buffer[6], posi, 3 * sizeof(double)); - - // Send command - if (sendUDP(sock, buffer, 30) < 0) - { - printError("getTERR", "Failed to send command."); - return -1; - } - return 0; -} - -int getTERRResponse(XPCSocket sock, double values[11], char ac) -{ - // Get response - char readBuffer[62]; - int readResult = readUDP(sock, readBuffer, 62); - if (readResult < 0) - { - printError("getTERR", "Failed to read response."); - return -2; - } - if (readResult != 62) - { - printError("getTERR", "Unexpected response length."); - return -3; - } - - // Copy response into outputs - float f[8]; - ac = readBuffer[5]; - memcpy(values, readBuffer + 6, 3 * sizeof(double)); - memcpy(f, readBuffer + 30, 8 * sizeof(float)); - values[ 3] = (double)f[0]; - values[ 4] = (double)f[1]; - values[ 5] = (double)f[2]; - values[ 6] = (double)f[3]; - values[ 7] = (double)f[4]; - values[ 8] = (double)f[5]; - values[ 9] = (double)f[6]; - values[10] = (double)f[7]; - - return 0; -} - -int getTERR(XPCSocket sock, double posi[3], double values[11], char ac) -{ - // Send Command - int result = sendTERRRequest(sock, posi, ac); - if (result < 0) - { - // An error ocurred while sending. - // sendTERRRequest will print an error message, so just return. - return result; - } - - // Read Response - result = getTERRResponse(sock, values, ac); - if (result < 0) - { - // An error ocurred while reading the response. - // getTERRResponse will print an error message, so just return. - return result; - } - return 0; -} -/*****************************************************************************/ -/**** End TERR functions ****/ -/*****************************************************************************/ - /*****************************************************************************/ /**** CTRL functions ****/ /*****************************************************************************/ @@ -775,7 +696,7 @@ int sendCTRL(XPCSocket sock, float values[], int size, char ac) // 5 byte header + 5 float values * 4 + 2 byte values char buffer[31] = "CTRL"; int cur = 5; - int i; // iterator + int i; // iterator for (i = 0; i < 6; i++) { float val = -998; From ba9e8b0eee1c06b3c5e0326527f06293db87b60b Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sun, 19 Apr 2020 11:37:14 -0700 Subject: [PATCH 19/19] Revert "Added getTERR function" This reverts commit ab9d0b7ea795a3cd20ec7d578b55135676058b2b. --- C/src/xplaneConnect.h | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/C/src/xplaneConnect.h b/C/src/xplaneConnect.h index 9fa5faa..4a62b17 100644 --- a/C/src/xplaneConnect.h +++ b/C/src/xplaneConnect.h @@ -216,24 +216,6 @@ int getPOSI(XPCSocket sock, double values[7], char ac); /// \returns 0 if successful, otherwise a negative value. int sendPOSI(XPCSocket sock, double values[], int size, char ac); -// Terrain - -/// Gets the terrain information of the specified aircraft. -/// -/// \param sock The socket to use to send the command. -/// \param posi A double array representing position data about the aircraft. The format of values is -/// [Lat, Lon, Alt]. -/// -998 used for [Lat, Lon, Alt] to request terrain info at the current aircraft position. -/// \param values A double array with the information for the terrain output. The format of values is -/// [Lat, Lon, Alt, Nx, Ny, Nz, Vx, Vy, Vz, wet, result]. The first three are for output of -/// the Lat and Lon of the aircraft with the terrain height directly below. The next three -/// represent the terrain normal. The next three represent the velocity of the terrain. -/// The wet variable is 0.0 if the terrain is dry and 1.0 if wet. -/// The last output is the terrain probe result parameter. -/// \param ac The aircraft number to set the position of. 0 for the main/user's aircraft. -/// \returns 0 if successful, otherwise a negative value. -int getTERR(XPCSocket sock, double posi[3], double values[11], char ac); - // Controls /// Gets the control surface information for the specified aircraft.