Merge pull request #202 from NPrincen/develop

Double Lat/Lon/Alt for getPOSI
This commit is contained in:
Jason Watkins
2020-04-28 11:39:32 -07:00
committed by GitHub
15 changed files with 620 additions and 118 deletions

View File

@@ -26,6 +26,8 @@
#include <sys/time.h>
#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
{

View File

@@ -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)

View File

@@ -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++)

View File

@@ -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.

View File

@@ -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()

View File

@@ -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__":

View File

@@ -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()

View File

@@ -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"<f", val)
if i < 3:
buffer += struct.pack(b"<d", val)
else:
buffer += struct.pack(b"<f", val)
# Send
self.sendUDP(buffer)
@@ -257,7 +262,7 @@ class XPlaneConnect(object):
val = values[i]
if i == 4:
val = -1 if (abs(val + 998) < 1e-4) else val
buffer += struct.pack(b"b", val)
buffer += struct.pack(b"b", int(val))
else:
buffer += struct.pack(b"<f", val)

View File

@@ -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()

View File

@@ -10,7 +10,7 @@ int testDATA()
{
// Initialize
int i, j; // Iterator
char* drefs[100] =
const char* drefs[100] =
{
"sim/aircraft/parts/acf_gear_deploy"
};

View File

@@ -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

View File

@@ -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",

View File

@@ -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()

View File

@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>6931ebb2-4e01-4c5a-86b6-668c0e75051b</ProjectGuid>
<ProjectHome>.</ProjectHome>
<StartupFile>Tests.py</StartupFile>
<SearchPath>..\..\Python\src\</SearchPath>
<WorkingDirectory>.</WorkingDirectory>
<OutputPath>.</OutputPath>
<Name>Tests</Name>
<RootNamespace>Tests</RootNamespace>
<InterpreterId>{9a7a9026-48c1-4688-9d5d-e5699d47d074}</InterpreterId>
<InterpreterVersion>2.7</InterpreterVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DebugSymbols>true</DebugSymbols>
<EnableUnmanagedDebugging>false</EnableUnmanagedDebugging>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DebugSymbols>true</DebugSymbols>
<EnableUnmanagedDebugging>false</EnableUnmanagedDebugging>
</PropertyGroup>
<ItemGroup>
<Compile Include="Tests.py" />
</ItemGroup>
<ItemGroup>
<InterpreterReference Include="{9a7a9026-48c1-4688-9d5d-e5699d47d074}\2.7" />
</ItemGroup>
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
<PtvsTargetsFile>$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Python Tools\Microsoft.PythonTools.targets</PtvsTargetsFile>
</PropertyGroup>
<Import Condition="Exists($(PtvsTargetsFile))" Project="$(PtvsTargetsFile)" />
<Import Condition="!Exists($(PtvsTargetsFile))" Project="$(MSBuildToolsPath)\Microsoft.Common.targets" />
<!-- Uncomment the CoreCompile target to enable the Build command in
Visual Studio and specify your pre- and post-build commands in
the BeforeBuild and AfterBuild targets below. -->
<!--<Target Name="CoreCompile" />-->
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
</Project>

View File

@@ -24,7 +24,6 @@
#include "XPLMScenery.h"
#include "XPLMGraphics.h"
#include <cmath>
#include <cstring>
#include <cstdint>
@@ -32,7 +31,6 @@
#define MULTICAST_GROUP "239.255.1.1"
#define MULITCAST_PORT 49710
namespace XPC
{
std::map<std::string, MessageHandlers::ConnectionInfo> 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();