Merge pull request #218 from nasa/develop

Version 1.3 RC6
This commit is contained in:
Jason Watkins
2020-06-27 12:54:00 -07:00
committed by GitHub
26 changed files with 1846 additions and 666 deletions

3
.gitignore vendored
View File

@@ -92,4 +92,5 @@ out/
# Internal Docs # # Internal Docs #
################# #################
Docs/~$Capability Matrix.xlsx Docs/~$Capability Matrix.xlsx
*.xpl

View File

@@ -26,6 +26,8 @@
#include <sys/time.h> #include <sys/time.h>
#include "stdio.h" #include "stdio.h"
struct timeval tv;
#ifdef WIN32 #ifdef WIN32
HANDLE hStdIn = NULL; HANDLE hStdIn = NULL;
INPUT_RECORD buffer; INPUT_RECORD buffer;
@@ -51,7 +53,6 @@ int waitForInput()
#else #else
int fdstdin = 0; int fdstdin = 0;
fd_set fds; fd_set fds;
struct timeval tv;
int waitForInput() int waitForInput()
{ {
@@ -67,10 +68,10 @@ int main(void)
{ {
XPCSocket client = openUDP("127.0.0.1"); XPCSocket client = openUDP("127.0.0.1");
const int aircraftNum = 0; const int aircraftNum = 0;
tv.tv_usec = 100 * 1000; tv.tv_usec = 100 * 1000;
while (1) while (1)
{ {
float posi[7]; // FIXME: change this to the 64-bit lat/lon/h double posi[7];
int result = getPOSI(client, posi, aircraftNum); int result = getPOSI(client, posi, aircraftNum);
if (result < 0) // Error in getPOSI 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"); XPCSocket sock = openUDP("127.0.0.1");
for (int i = 0; i < count; ++i) for (int i = 0; i < count; ++i)
{ {
float posi[7]; double posi[7];
int result = getPOSI(sock, posi, 0); int result = getPOSI(sock, posi, 0);
playbackSleep(interval); playbackSleep(interval);
if (result < 0) if (result < 0)

View File

@@ -117,13 +117,16 @@ XPCSocket aopenUDP(const char *xpIP, unsigned short xpPort, unsigned short port)
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
// Set timeout to 100ms // Set socket timeout period for sendUDP to 1 millisecond
// Without this, playback may become choppy due to process blocking
#ifdef _WIN32 #ifdef _WIN32
DWORD timeout = 100; // Minimum socket timeout in Windows is 1 millisecond (0 makes it blocking)
DWORD timeout = 1;
#else #else
// Set socket timeout to 1 millisecond = 1,000 microseconds to make it the same as Windows (0 makes it blocking)
struct timeval timeout; struct timeval timeout;
timeout.tv_sec = 0; timeout.tv_sec = 0;
timeout.tv_usec = 250000; timeout.tv_usec = 1000;
#endif #endif
if (setsockopt(sock.sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)) < 0) if (setsockopt(sock.sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)) < 0)
{ {
@@ -185,16 +188,16 @@ int sendUDP(XPCSocket sock, char buffer[], int len)
/// \param sock The socket to read from. /// \param sock The socket to read from.
/// \param buffer A pointer to the location to store the data. /// \param buffer A pointer to the location to store the data.
/// \param len The number of bytes to read. /// \param len The number of bytes to read.
/// \returns If an error occurs, a negative number. Otehrwise, the number of bytes read. /// \returns If an error occurs, a negative number. Otherwise, the number of bytes read.
int readUDP(XPCSocket sock, char buffer[], int len) int readUDP(XPCSocket sock, char buffer[], int len)
{ {
#ifdef _WIN32 // For readUDP, use the select command - minimum timeout of 0 makes it polling.
// Windows readUDP needs the select command- minimum timeout is 1ms. // Without this, playback may become choppy due to process blocking
// Without this playback becomes choppy
// Definitions // Definitions
FD_SET stReadFDS; fd_set stReadFDS;
FD_SET stExceptFDS; fd_set stExceptFDS;
struct timeval timeout;
// Setup for Select // Setup for Select
FD_ZERO(&stReadFDS); FD_ZERO(&stReadFDS);
@@ -202,12 +205,13 @@ int readUDP(XPCSocket sock, char buffer[], int len)
FD_ZERO(&stExceptFDS); FD_ZERO(&stExceptFDS);
FD_SET(sock.sock, &stExceptFDS); FD_SET(sock.sock, &stExceptFDS);
struct timeval tv; // Set timeout period for select to 0.05 sec = 50 milliseconds = 50,000 microseconds (0 makes it polling)
tv.tv_sec = 0; // TO DO - This could be set to 0 if a message handling system were implemented, like in the plugin.
tv.tv_usec = 100000; timeout.tv_sec = 0;
timeout.tv_usec = 50000;
// Select Command // Select Command
int status = select(-1, &stReadFDS, (FD_SET*)0, &stExceptFDS, &tv); int status = select(sock.sock+1, &stReadFDS, NULL, &stExceptFDS, &timeout);
if (status < 0) if (status < 0)
{ {
printError("readUDP", "Select command error"); printError("readUDP", "Select command error");
@@ -218,11 +222,9 @@ int readUDP(XPCSocket sock, char buffer[], int len)
// No data // No data
return 0; return 0;
} }
// If no error: Read Data
status = recv(sock.sock, buffer, len, 0); status = recv(sock.sock, buffer, len, 0);
#else
// For apple or linux-just read - will timeout in 0.5 ms
int status = (int)recv(sock.sock, buffer, len, 0);
#endif
if (status < 0) if (status < 0)
{ {
printError("readUDP", "Error reading socket"); printError("readUDP", "Error reading socket");
@@ -378,16 +380,16 @@ int readDATA(XPCSocket sock, float data[][9], int rows)
/*****************************************************************************/ /*****************************************************************************/
/**** DREF functions ****/ /**** DREF functions ****/
/*****************************************************************************/ /*****************************************************************************/
int sendDREF(XPCSocket sock, const char* dref, float value[], int size) int sendDREF(XPCSocket sock, const char* dref, float values[], int size)
{ {
return sendDREFs(sock, &dref, &value, &size, 1); return sendDREFs(sock, &dref, &values, &size, 1);
} }
int sendDREFs(XPCSocket sock, const char* drefs[], float* values[], int sizes[], int count) int sendDREFs(XPCSocket sock, const char* drefs[], float* values[], int sizes[], int count)
{ {
// Setup command // Setup command
// Max size is technically unlimited. // Max size is technically unlimited.
unsigned char buffer[65536] = "DREF"; char buffer[65536] = "DREF";
int pos = 5; int pos = 5;
int i; // Iterator int i; // Iterator
for (i = 0; i < count; ++i) for (i = 0; i < count; ++i)
@@ -433,7 +435,7 @@ int sendDREFRequest(XPCSocket sock, const char* drefs[], unsigned char count)
// Setup command // Setup command
// 6 byte header + potentially 255 drefs, each 256 chars long. // 6 byte header + potentially 255 drefs, each 256 chars long.
// Easiest to just round to an even 2^16. // Easiest to just round to an even 2^16.
unsigned char buffer[65536] = "GETD"; char buffer[65536] = "GETD";
buffer[5] = count; buffer[5] = count;
int len = 6; int len = 6;
int i; // iterator int i; // iterator
@@ -460,7 +462,7 @@ int sendDREFRequest(XPCSocket sock, const char* drefs[], unsigned char count)
int getDREFResponse(XPCSocket sock, float* values[], unsigned char count, int sizes[]) int getDREFResponse(XPCSocket sock, float* values[], unsigned char count, int sizes[])
{ {
unsigned char buffer[65536]; char buffer[65536];
int result = readUDP(sock, buffer, 65536); int result = readUDP(sock, buffer, 65536);
if (result < 0) if (result < 0)
@@ -516,7 +518,7 @@ int getDREFs(XPCSocket sock, const char* drefs[], float* values[], unsigned char
int result = sendDREFRequest(sock, drefs, count); int result = sendDREFRequest(sock, drefs, count);
if (result < 0) if (result < 0)
{ {
// A error ocurred while sending. // An error ocurred while sending.
// sendDREFRequest will print an error message, so just return. // sendDREFRequest will print an error message, so just return.
return -1; return -1;
} }
@@ -524,7 +526,7 @@ int getDREFs(XPCSocket sock, const char* drefs[], float* values[], unsigned char
// Read Response // Read Response
if (getDREFResponse(sock, values, count, sizes) < 0) if (getDREFResponse(sock, values, count, sizes) < 0)
{ {
// A error ocurred while reading the response. // An error ocurred while reading the response.
// getDREFResponse will print an error message, so just return. // getDREFResponse will print an error message, so just return.
return -2; return -2;
} }
@@ -537,10 +539,10 @@ int getDREFs(XPCSocket sock, const char* drefs[], float* values[], unsigned char
/*****************************************************************************/ /*****************************************************************************/
/**** POSI functions ****/ /**** POSI functions ****/
/*****************************************************************************/ /*****************************************************************************/
int getPOSI(XPCSocket sock, float values[7], char ac) int getPOSI(XPCSocket sock, double values[7], char ac)
{ {
// Setup send command // Setup send command
unsigned char buffer[6] = "GETP"; char buffer[6] = "GETP";
buffer[5] = ac; buffer[5] = ac;
// Send command // Send command
@@ -551,22 +553,41 @@ int getPOSI(XPCSocket sock, float values[7], char ac)
} }
// Get response // Get response
unsigned char readBuffer[34]; char readBuffer[46];
int readResult = readUDP(sock, readBuffer, 34); float f[7];
int readResult = readUDP(sock, readBuffer, 46);
// Copy response into values
if (readResult < 0) if (readResult < 0)
{ {
printError("getPOSI", "Failed to read response."); printError("getPOSI", "Failed to read response.");
return -2; 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."); printError("getPOSI", "Unexpected response length.");
return -3; 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; return 0;
} }
@@ -585,7 +606,7 @@ int sendPOSI(XPCSocket sock, double values[], int size, char ac)
} }
// Setup command // Setup command
unsigned char buffer[46] = "POSI"; char buffer[46] = "POSI";
buffer[4] = 0xff; //Placeholder for message length buffer[4] = 0xff; //Placeholder for message length
buffer[5] = ac; buffer[5] = ac;
int i; // iterator int i; // iterator
@@ -621,13 +642,147 @@ int sendPOSI(XPCSocket sock, double values[], int size, char ac)
/**** End POSI functions ****/ /**** 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 sendPOST(XPCSocket sock, double posi[], int size, double values[11], char ac)
{
// Validate input
if (ac < 0 || ac > 20)
{
printError("sendPOST", "aircraft should be a value between 0 and 20.");
return -1;
}
if (size < 1 || size > 7)
{
printError("sendPOST", "size should be a value between 1 and 7.");
return -2;
}
// Setup command
char buffer[46] = "POST";
buffer[4] = 0xff; //Placeholder for message length
buffer[5] = ac;
int i; // iterator
for (i = 0; i < 7; i++) // double for lat/lon/h
{
double val = -998;
if (i < size)
{
val = posi[i];
}
if (i < 3) /* lat/lon/h */
{
memcpy(&buffer[6 + i*8], &val, sizeof(double));
}
else /* attitude and gear */
{
float f = (float)val;
memcpy(&buffer[18 + i*4], &f, sizeof(float));
}
}
// Send Command
if (sendUDP(sock, buffer, 46) < 0)
{
printError("sendPOST", "Failed to send command");
return -3;
}
// Read Response
int result = getTERRResponse(sock, values, ac);
if (result < 0)
{
// A error ocurred while reading the response.
// getTERRResponse will print an error message, so just return.
return result;
}
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 ****/ /**** CTRL functions ****/
/*****************************************************************************/ /*****************************************************************************/
int getCTRL(XPCSocket sock, float values[7], char ac) int getCTRL(XPCSocket sock, float values[7], char ac)
{ {
// Setup send command // Setup send command
unsigned char buffer[6] = "GETC"; char buffer[6] = "GETC";
buffer[5] = ac; buffer[5] = ac;
// Send command // Send command
@@ -638,7 +793,7 @@ int getCTRL(XPCSocket sock, float values[7], char ac)
} }
// Get response // Get response
unsigned char readBuffer[31]; char readBuffer[31];
int readResult = readUDP(sock, readBuffer, 31); int readResult = readUDP(sock, readBuffer, 31);
if (readResult < 0) if (readResult < 0)
{ {
@@ -675,7 +830,7 @@ int sendCTRL(XPCSocket sock, float values[], int size, char ac)
// Setup Command // Setup Command
// 5 byte header + 5 float values * 4 + 2 byte values // 5 byte header + 5 float values * 4 + 2 byte values
unsigned char buffer[31] = "CTRL"; char buffer[31] = "CTRL";
int cur = 5; int cur = 5;
int i; // iterator int i; // iterator
for (i = 0; i < 6; i++) for (i = 0; i < 6; i++)
@@ -818,3 +973,40 @@ int sendVIEW(XPCSocket sock, VIEW_TYPE view)
/*****************************************************************************/ /*****************************************************************************/
/**** End View functions ****/ /**** End View functions ****/
/*****************************************************************************/ /*****************************************************************************/
/*****************************************************************************/
/**** Comm functions ****/
/*****************************************************************************/
int sendCOMM(XPCSocket sock, const char* comm) {
// Setup command
// Max size is technically unlimited.
unsigned char buffer[65536] = "COMM";
int pos = 5;
int commLen = strnlen(comm, 256);
if (pos + commLen + 2 > 65536)
{
printError("sendCOMM", "About to overrun the send buffer!");
return -4;
}
if (commLen > 255)
{
printError("sendCOMM", "comm is too long. Must be less than 256 characters.");
return -1;
}
// Copy comm to buffer
buffer[pos++] = (unsigned char)commLen;
memcpy(buffer + pos, comm, commLen);
pos += commLen;
// Send command
if (sendUDP(sock, buffer, pos) < 0)
{
printError("setDREF", "Failed to send command");
return -3;
}
return 0;
}
/*****************************************************************************/
/**** End Comm functions ****/
/*****************************************************************************/

View File

@@ -113,7 +113,7 @@ int setCONN(XPCSocket* sock, unsigned short port);
/// ///
/// \param sock The socket to use to send the command. /// \param sock The socket to use to send the command.
/// \param pause 0 to unpause the sim; 1 to pause, 100:119 to pause a/c 0:19, 200:219 to unpause a/c 0:19. /// \param pause 0 to unpause the sim; 1 to pause, 100:119 to pause a/c 0:19, 200:219 to unpause a/c 0:19.
/// \returns 0 if successful, otherwise a negative value. /// \returns 0 if successful, otherwise a negative value.
int pauseSim(XPCSocket sock, char pause); int pauseSim(XPCSocket sock, char pause);
// X-Plane UDP DATA // X-Plane UDP DATA
@@ -122,7 +122,7 @@ int pauseSim(XPCSocket sock, char pause);
/// ///
/// \details This command is compatible with the X-Plane data API. /// \details This command is compatible with the X-Plane data API.
/// \param sock The socket to use to send the command. /// \param sock The socket to use to send the command.
/// \param data A 2D array of data rows to read into. /// \param data A 2D array of data rows to read into.
/// \param rows The number of rows in dataRef. /// \param rows The number of rows in dataRef.
/// \returns 0 if successful, otherwise a negative value. /// \returns 0 if successful, otherwise a negative value.
int readDATA(XPCSocket sock, float data[][9], int rows); int readDATA(XPCSocket sock, float data[][9], int rows);
@@ -131,7 +131,7 @@ int readDATA(XPCSocket sock, float data[][9], int rows);
/// ///
/// \details This command is compatible with the X-Plane data API. /// \details This command is compatible with the X-Plane data API.
/// \param sock The socket to use to send the command. /// \param sock The socket to use to send the command.
/// \param data A 2D array of data rows to send. /// \param data A 2D array of data rows to send.
/// \param rows The number of rows in dataRef. /// \param rows The number of rows in dataRef.
/// \returns 0 if successful, otherwise a negative value. /// \returns 0 if successful, otherwise a negative value.
int sendDATA(XPCSocket sock, float data[][9], int rows); int sendDATA(XPCSocket sock, float data[][9], int rows);
@@ -144,12 +144,12 @@ int sendDATA(XPCSocket sock, float data[][9], int rows);
/// http://www.xsquawkbox.net/xpsdk/docs/DataRefs.html. The size of values should match /// http://www.xsquawkbox.net/xpsdk/docs/DataRefs.html. The size of values should match
/// the size given on that page. XPC currently sends all values as floats regardless of /// the size given on that page. XPC currently sends all values as floats regardless of
/// the type described on the wiki. This doesn't cause any data loss for most datarefs. /// the type described on the wiki. This doesn't cause any data loss for most datarefs.
/// \param sock The socket to use to send the command. /// \param sock The socket to use to send the command.
/// \param dref The name of the dataref to set. /// \param dref The name of the dataref to set.
/// \param value An array of values representing the data to set. /// \param values An array of values representing the data to set.
/// \param size The number of elements in values. /// \param size The number of elements in values.
/// \returns 0 if successful, otherwise a negative value. /// \returns 0 if successful, otherwise a negative value.
int sendDREF(XPCSocket sock, const char* dref, float value[], int size); int sendDREF(XPCSocket sock, const char* dref, float values[], int size);
/// Sets the specified datarefs to the specified values. /// Sets the specified datarefs to the specified values.
/// ///
@@ -159,7 +159,7 @@ int sendDREF(XPCSocket sock, const char* dref, float value[], int size);
/// the type described on the wiki. This doesn't cause any data loss for most datarefs. /// the type described on the wiki. This doesn't cause any data loss for most datarefs.
/// \param sock The socket to use to send the command. /// \param sock The socket to use to send the command.
/// \param drefs The names of the datarefs to set. /// \param drefs The names of the datarefs to set.
/// \param values A multidimensional array containing the values for each dataref to set. /// \param values A 2D array containing the values for each dataref to set.
/// \param sizes The number of elements in each array in values /// \param sizes The number of elements in each array in values
/// \param count The number of datarefs being set. /// \param count The number of datarefs being set.
/// \returns 0 if successful, otherwise a negative value. /// \returns 0 if successful, otherwise a negative value.
@@ -173,13 +173,13 @@ int sendDREFs(XPCSocket sock, const char* drefs[], float* values[], int sizes[],
/// the type described on the wiki. This doesn't cause any data loss for most datarefs. /// the type described on the wiki. This doesn't cause any data loss for most datarefs.
/// \param sock The socket to use to send the command. /// \param sock The socket to use to send the command.
/// \param dref The name of the dataref to get. /// \param dref The name of the dataref to get.
/// \param values The array in which the value of the dataref will be stored. /// \param values The array in which the values of the dataref will be stored.
/// \param size The number of elements in values. The actual number of elements copied in will /// \param size The number of elements in values. The actual number of elements copied in will
/// be set when the function returns. /// be set when the function returns.
/// \returns 0 if successful, otherwise a negative value. /// \returns 0 if successful, otherwise a negative value.
int getDREF(XPCSocket sock, const char* dref, float values[], int* size); int getDREF(XPCSocket sock, const char* dref, float values[], int* size);
/// Gets the value of the specified dataref. /// Gets the values of the specified datarefs.
/// ///
/// \details dref names and their associated data types can be found on the XPSDK wiki at /// \details dref names and their associated data types can be found on the XPSDK wiki at
/// http://www.xsquawkbox.net/xpsdk/docs/DataRefs.html. The size of values should match /// http://www.xsquawkbox.net/xpsdk/docs/DataRefs.html. The size of values should match
@@ -189,7 +189,7 @@ int getDREF(XPCSocket sock, const char* dref, float values[], int* size);
/// \param drefs The names of the datarefs to get. /// \param drefs The names of the datarefs to get.
/// \param values A 2D array in which the values of the datarefs will be stored. /// \param values A 2D array in which the values of the datarefs will be stored.
/// \param count The number of datarefs being requested. /// \param count The number of datarefs being requested.
/// \param size The number of elements in each row of values. The size of each row will be set /// \param sizes The number of elements in each row of values. The size of each row will be set
/// to the actual number of elements copied in for that row. /// to the actual number of elements copied in for that row.
/// \returns 0 if successful, otherwise a negative value. /// \returns 0 if successful, otherwise a negative value.
int getDREFs(XPCSocket sock, const char* drefs[], float* values[], unsigned char count, int sizes[]); int getDREFs(XPCSocket sock, const char* drefs[], float* values[], unsigned char count, int sizes[]);
@@ -201,20 +201,56 @@ 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 sock The socket used to send the command and receive the response.
/// \param values An array to store the position information returned by the /// \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] /// 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. /// \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. /// Sets the position and orientation of the specified aircraft.
/// ///
/// \param sock The socket to use to send the command. /// \param sock The socket to use to send the command.
/// \param values An array representing position data about the aircraft. The format of values is /// \param values A double array representing position data about the aircraft. The format of values is
/// [Lat, Lon, Alt, Pitch, Roll, Yaw, Gear]. If less than 7 values are specified, /// [Lat, Lon, Alt, Pitch, Roll, Yaw, Gear]. If less than 7 values are specified,
/// the unspecified values will be left unchanged. /// the unspecified values will be left unchanged.
/// \param size The number of elements in values. /// \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. /// \returns 0 if successful, otherwise a negative value.
int sendPOSI(XPCSocket sock, double values[], int size, char ac); int sendPOSI(XPCSocket sock, double values[], int size, char ac);
// Terrain
/// Sets the position and orientation and 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, 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 posi.
/// \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 sendPOST(XPCSocket sock, double posi[], int size, double values[11], char ac);
/// 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 get the terrain data 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 // Controls
/// Gets the control surface information for the specified aircraft. /// Gets the control surface information for the specified aircraft.
@@ -223,7 +259,7 @@ int sendPOSI(XPCSocket sock, double values[], int size, char ac);
/// \param values An array to store the position information returned by the /// \param values An array to store the position information returned by the
/// plugin. The format of values is [Elevator, Aileron, Rudder, /// plugin. The format of values is [Elevator, Aileron, Rudder,
/// Throttle, Gear, Flaps, Speed Brakes] /// 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 get the control surfaces of. 0 is the main/user's aircraft.
/// \returns 0 if successful, otherwise a negative value. /// \returns 0 if successful, otherwise a negative value.
int getCTRL(XPCSocket sock, float values[7], char ac); int getCTRL(XPCSocket sock, float values[7], char ac);
@@ -234,7 +270,7 @@ int getCTRL(XPCSocket sock, float values[7], char ac);
/// [Elevator, Aileron, Rudder, Throttle, Gear, Flaps, Speed Brakes]. If less than /// [Elevator, Aileron, Rudder, Throttle, Gear, Flaps, Speed Brakes]. If less than
/// 6 values are specified, the unspecified values will be left unchanged. /// 6 values are specified, the unspecified values will be left unchanged.
/// \param size The number of elements in values. /// \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. /// \returns 0 if successful, otherwise a negative value.
int sendCTRL(XPCSocket sock, float values[], int size, char ac); int sendCTRL(XPCSocket sock, float values[], int size, char ac);
@@ -246,7 +282,7 @@ int sendCTRL(XPCSocket sock, float values[], int size, char ac);
/// \param msg The message to print of the screen. /// \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 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. /// \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); int sendTEXT(XPCSocket sock, char* msg, int x, int y);
/// Sets the camera view in X-Plane. /// Sets the camera view in X-Plane.
@@ -267,6 +303,13 @@ int sendVIEW(XPCSocket sock, VIEW_TYPE view);
/// \returns 0 if successful, otherwise a negative value. /// \returns 0 if successful, otherwise a negative value.
int sendWYPT(XPCSocket sock, WYPT_OP op, float points[], int count); int sendWYPT(XPCSocket sock, WYPT_OP op, float points[], int count);
/// Sends commands.
///
/// \param sock The socket to use to send the command.
/// \param comm The command string.
/// \returns 0 if successful, otherwise a negative value.
int sendCOMM(XPCSocket sock, const char* comm);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -889,6 +889,42 @@ public class XPlaneConnect implements AutoCloseable
sendUDP(os.toByteArray()); sendUDP(os.toByteArray());
} }
/**
* Send a command to X-Plane.
*
* @param comm The name of the X-Plane command to send.
* @throws IOException If the command cannot be sent.
*/
public void sendCOMM(String comm) throws IOException
{
//Preconditions
if(comm == null || comm.length() == 0)
{
throw new IllegalArgumentException(("comm must be non-empty."));
}
ByteArrayOutputStream os = new ByteArrayOutputStream();
os.write("COMM".getBytes(StandardCharsets.UTF_8));
os.write(0xFF); //Placeholder for message length
//Convert comm to bytes.
byte[] commBytes = comm.getBytes(StandardCharsets.UTF_8);
if (commBytes.length == 0)
{
throw new IllegalArgumentException("COMM is an empty string!");
}
if (commBytes.length > 255)
{
throw new IllegalArgumentException("comm must be less than 255 bytes in UTF-8. Are you sure this is a valid comm?");
}
//Build and send message
os.write(commBytes.length);
os.write(commBytes);
sendUDP(os.toByteArray());
}
/** /**
* Sets the port on which the client will receive data from X-Plane. * Sets the port on which the client will receive data from X-Plane.
* *

View File

@@ -416,6 +416,27 @@ class XPlaneConnect(object):
buffer = struct.pack("<4sxBB" + str(len(points)) + "f", "WYPT", op, len(points), *points) buffer = struct.pack("<4sxBB" + str(len(points)) + "f", "WYPT", op, len(points), *points)
self.sendUDP(buffer) self.sendUDP(buffer)
def sendCOMM(self, comm):
'''Sets the specified datarefs to the specified values.
Args:
drefs: A list of names of the datarefs to set.
values: A list of scalar or vector values to set.
'''
if comm == None:
raise ValueError("comm must be non-empty.")
buffer = struct.pack("<4sx", "COMM")
if len(comm) == 0 or len(comm) > 255:
raise ValueError("comm must be a non-empty string less than 256 characters.")
# Pack message
fmt = "<B{0:d}s".format(len(comm))
buffer += struct.pack(fmt, len(comm), comm)
# Send
self.sendUDP(buffer)
class ViewType(object): class ViewType(object):
Forwards = 73 Forwards = 73
Down = 74 Down = 74

View File

@@ -1,7 +1,6 @@
import socket import socket
import struct import struct
class XPlaneConnect(object): class XPlaneConnect(object):
"""XPlaneConnect (XPC) facilitates communication to and from the XPCPlugin.""" """XPlaneConnect (XPC) facilitates communication to and from the XPCPlugin."""
socket = None socket = None
@@ -121,7 +120,7 @@ class XPlaneConnect(object):
buffer = self.readUDP() buffer = self.readUDP()
if len(buffer) < 6: if len(buffer) < 6:
return None return None
rows = (len(buffer) - 5) / 36 rows = (len(buffer) - 5) // 36
data = [] data = []
for i in range(rows): for i in range(rows):
data.append(struct.unpack_from(b"9f", buffer, 5 + 36*i)) data.append(struct.unpack_from(b"9f", buffer, 5 + 36*i))
@@ -158,10 +157,13 @@ class XPlaneConnect(object):
# Read response # Read response
resultBuf = self.readUDP() 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.") raise ValueError("Unexpected response length.")
result = struct.unpack(b"<4sxBfffffff", resultBuf)
if result[0] != b"POSI": if result[0] != b"POSI":
raise ValueError("Unexpected header: " + result[0]) raise ValueError("Unexpected header: " + result[0])
@@ -197,7 +199,10 @@ class XPlaneConnect(object):
val = -998 val = -998
if i < len(values): if i < len(values):
val = values[i] 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 # Send
self.sendUDP(buffer) self.sendUDP(buffer)
@@ -257,7 +262,7 @@ class XPlaneConnect(object):
val = values[i] val = values[i]
if i == 4: if i == 4:
val = -1 if (abs(val + 998) < 1e-4) else val val = -1 if (abs(val + 998) < 1e-4) else val
buffer += struct.pack(b"b", val) buffer += struct.pack(b"b", int(val))
else: else:
buffer += struct.pack(b"<f", val) buffer += struct.pack(b"<f", val)

View File

@@ -6,7 +6,7 @@
#include "Test.h" #include "Test.h"
#include "xplaneConnect.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]; float* data[7];
int sizes[7]; int sizes[7];
@@ -18,7 +18,7 @@ int doCTRLTest(XPCSocket *sock, char* drefs[7], float values[], int size, int ac
// Execute command // Execute command
int result = sendCTRL(*sock, values, size, ac); int result = sendCTRL(*sock, values, size, ac);
int d = 0.0f; int d = 0.0f;
if (result >= 0) if (result >= 0)
{ {
result = getDREFs(*sock, drefs, data, 7, sizes); result = getDREFs(*sock, drefs, data, 7, sizes);
@@ -66,19 +66,19 @@ int doGETCTest(float values[7], int ac, float expected[7])
return 0; return 0;
} }
int basicCTRLTest(char** drefs, int ac) int basicCTRLTest(const char** drefs, int ac)
{ {
// Set control surfaces to known state. // Set control surfaces to known state.
float CTRL[6] = { 0.0F, 0.0F, 0.0F, 0.8F, 1.0F, 0.5F }; 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 }; float expected[7] = { 0.0F, 0.0F, 0.0F, NAN, NAN, NAN, NAN };
XPCSocket sock = openUDP(IP); XPCSocket sock = openUDP(IP);
pauseSim(sock, 1); // Pause so the controls wont change between 2 and 3 pauseSim(sock, 1); // Pause so the controls wont change between 2 and 3
int result = doCTRLTest(&sock, drefs, CTRL, 3, ac, expected); int result = doCTRLTest(&sock, drefs, CTRL, 3, ac, expected);
if (result < 0) if (result < 0)
{ {
return -10000 + result; return -10000 + result;
} }
crossPlatformUSleep(SLEEP_AMOUNT); crossPlatformUSleep(SLEEP_AMOUNT);
// Test control surfaces and set other values to known state. // Test control surfaces and set other values to known state.
expected[0] = CTRL[0] = 0.2F; expected[0] = CTRL[0] = 0.2F;
@@ -92,19 +92,19 @@ int basicCTRLTest(char** drefs, int ac)
{ {
return -20000 + result; return -20000 + result;
} }
crossPlatformUSleep(SLEEP_AMOUNT); crossPlatformUSleep(SLEEP_AMOUNT);
// Test other values and verify control surfaces unchanged. // Test other values and verify control surfaces unchanged.
expected[0] = CTRL[0] = 0.15F; expected[0] = CTRL[0] = 0.15F;
expected[1] = CTRL[1] = 0.15F; expected[1] = CTRL[1] = 0.15F;
expected[2] = CTRL[2] = 0.15F; expected[2] = CTRL[2] = 0.15F;
expected[3] = CTRL[3] = 0.9F; expected[3] = CTRL[3] = 0.9F;
CTRL[4] = -998; CTRL[4] = -998;
CTRL[5] = -998; CTRL[5] = -998;
result = doCTRLTest(&sock, drefs, CTRL, 6, ac, expected); result = doCTRLTest(&sock, drefs, CTRL, 6, ac, expected);
pauseSim(sock, 0); pauseSim(sock, 0);
closeUDP(sock); closeUDP(sock);
if (result < 0) if (result < 0)
{ {
if (result == -1004) { if (result == -1004) {
@@ -112,12 +112,12 @@ int basicCTRLTest(char** drefs, int ac)
} }
return -30000 + result; return -30000 + result;
} }
return 0; return 0;
} }
int testCTRL_Player() int testCTRL_Player()
{ {
char* drefs[] = const char* drefs[] =
{ {
"sim/cockpit2/controls/yoke_pitch_ratio", "sim/cockpit2/controls/yoke_pitch_ratio",
"sim/cockpit2/controls/yoke_roll_ratio", "sim/cockpit2/controls/yoke_roll_ratio",
@@ -132,7 +132,7 @@ int testCTRL_Player()
int testCTRL_NonPlayer() int testCTRL_NonPlayer()
{ {
char* drefs[] = const char* drefs[] =
{ {
"sim/multiplayer/position/plane1_yolk_pitch", "sim/multiplayer/position/plane1_yolk_pitch",
"sim/multiplayer/position/plane1_yolk_roll", "sim/multiplayer/position/plane1_yolk_roll",
@@ -147,7 +147,7 @@ int testCTRL_NonPlayer()
int testCTRL_Speedbrakes() int testCTRL_Speedbrakes()
{ {
char* drefs[] = const char* drefs[] =
{ {
"sim/cockpit2/controls/yoke_pitch_ratio", "sim/cockpit2/controls/yoke_pitch_ratio",
"sim/cockpit2/controls/yoke_roll_ratio", "sim/cockpit2/controls/yoke_roll_ratio",
@@ -161,8 +161,8 @@ int testCTRL_Speedbrakes()
// Arm // Arm
float CTRL[7] = { -998, -998, -998, -998, -998, -998, -0.5F }; float CTRL[7] = { -998, -998, -998, -998, -998, -998, -0.5F };
float expected[7] = { NAN, NAN, NAN, NAN, NAN, NAN, -0.5F }; float expected[7] = { NAN, NAN, NAN, NAN, NAN, NAN, -0.5F };
XPCSocket sock = openUDP(IP); XPCSocket sock = openUDP(IP);
pauseSim(sock, 1); // Pause so the controls wont change between 2 and 3 pauseSim(sock, 1); // Pause so the controls wont change between 2 and 3
int result = doCTRLTest(&sock, drefs, CTRL, 7, 0, expected); int result = doCTRLTest(&sock, drefs, CTRL, 7, 0, expected);
if (result < 0) if (result < 0)
{ {
@@ -180,13 +180,13 @@ int testCTRL_Speedbrakes()
// Retract // Retract
expected[6] = CTRL[6] = 0.0F; expected[6] = CTRL[6] = 0.0F;
result = doCTRLTest(&sock, drefs, CTRL, 7, 0, expected); result = doCTRLTest(&sock, drefs, CTRL, 7, 0, expected);
pauseSim(sock, 0); pauseSim(sock, 0);
closeUDP(sock); closeUDP(sock);
if (result < 0) if (result < 0)
{ {
return -30000 + result; return -30000 + result;
} }
return 0; return 0;
} }
int testGETC() int testGETC()

View File

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

View File

@@ -6,7 +6,7 @@
#include "Test.h" #include "Test.h"
#include "xplaneConnect.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 // Setup memory
int* asizes = (int*)malloc(sizeof(int) * count); int* asizes = (int*)malloc(sizeof(int) * count);
@@ -37,7 +37,7 @@ int doGETDTest(char* drefs[], float* expected[], int count, int sizes[])
return result; 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 // Setup memory
int* asizes = (int*)malloc(sizeof(int) * count); 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() int testGETD_Basic()
{ {
char* drefs[] = const char* drefs[] =
{ {
"sim/cockpit/switches/gear_handle_status", //int "sim/cockpit/switches/gear_handle_status", //int
"sim/cockpit/autopilot/altitude", //float "sim/cockpit/autopilot/altitude", //float
@@ -99,20 +99,20 @@ int testGETD_Basic()
int testGETD_TestFloat() int testGETD_TestFloat()
{ {
char* dref = "sim/test/test_float"; const char* dref = "sim/test/test_float";
int size = 1; int size = 1;
float* expected[1]; float* expected[1];
expected[0] = (float*)malloc(sizeof(float)); expected[0] = (float*)malloc(sizeof(float));
expected[0][0] = 0.0F; expected[0][0] = 0.0F;
int result = doGETDTest(&dref, &expected, 1, &size); int result = doGETDTest(&dref, expected, 1, &size);
free(expected[0]); free(expected[0]);
return result; return result;
} }
int testGETD_Types() int testGETD_Types()
{ {
char* drefs[] = const char* drefs[] =
{ {
"sim/cockpit/switches/gear_handle_status", //int "sim/cockpit/switches/gear_handle_status", //int
"sim/cockpit/autopilot/altitude", //float "sim/cockpit/autopilot/altitude", //float
@@ -173,7 +173,7 @@ int testGETD_Types()
int testDREF() int testDREF()
{ {
char* drefs[] = const char* drefs[] =
{ {
"sim/cockpit/switches/gear_handle_status", //int "sim/cockpit/switches/gear_handle_status", //int
"sim/cockpit/autopilot/altitude", //float "sim/cockpit/autopilot/altitude", //float

View File

@@ -6,7 +6,7 @@
#include "Test.h" #include "Test.h"
#include "xplaneConnect.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]; float* data[7];
int sizes[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]) int doGETPTest(double values[7], int ac, double expected[7])
{ {
// Execute Test // Execute Test
float actual[7]; double actual[7];
XPCSocket sock = openUDP(IP); XPCSocket sock = openUDP(IP);
int result = sendPOSI(sock, values, 7, ac); int result = sendPOSI(sock, values, 7, ac);
if (result >= 0) if (result >= 0)
@@ -67,7 +67,7 @@ int doGETPTest(double values[7], int ac, double expected[7])
return 0; return 0;
} }
int basicPOSITest(char** drefs, int ac) int basicPOSITest(const char** drefs, int ac)
{ {
// Set psoition and initial orientation // Set psoition and initial orientation
double POSI[7] = { 37.524, -122.06899, 2500, 0, 0, 0, 1 }; 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 -20000 + result;
} }
return 0; return 0;
} }
int testPOSI_Player() int testPOSI_Player()
{ {
char* drefs[] = const char* drefs[] =
{ {
"sim/flightmodel/position/latitude", "sim/flightmodel/position/latitude",
"sim/flightmodel/position/longitude", "sim/flightmodel/position/longitude",
@@ -130,7 +130,7 @@ int testPOSI_Player()
int testPOSI_NonPlayer() int testPOSI_NonPlayer()
{ {
char* drefs[] = const char* drefs[] =
{ {
"sim/multiplayer/position/plane1_lat", "sim/multiplayer/position/plane1_lat",
"sim/multiplayer/position/plane1_lon", "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

@@ -6,11 +6,11 @@
trigger: trigger:
branches: branches:
include: include:
# Build all branches starting with 'ms-' This is useful when making and testing chanes made to this file # Build all branches starting with 'ms-' This is useful when making and testing chanes made to this file
- ms-* - ms-*
tags: tags:
include: include:
- '*' - "*"
# pr: # pr:
# - '*' # - '*'
variables: variables:
@@ -27,140 +27,139 @@ variables:
# https://docs.microsoft.com/en-us/azure/devops/pipelines/library/service-endpoints?view=azure-devops&tabs=yaml#sep-github # https://docs.microsoft.com/en-us/azure/devops/pipelines/library/service-endpoints?view=azure-devops&tabs=yaml#sep-github
xpcGitHubConnection: XPC-Azure xpcGitHubConnection: XPC-Azure
stages: stages:
- stage: Build - stage: Build
jobs: jobs:
- job: macOS - job: macOS
pool: pool:
vmImage: 'macos-latest' vmImage: "macos-latest"
steps: steps:
- task: Xcode@5 - task: Xcode@5
inputs: inputs:
actions: 'build' actions: "build"
scheme: '' scheme: ""
sdk: 'macosx10.14' sdk: "macosx10.15"
configuration: 'Release' configuration: "Release"
xcWorkspacePath: 'xpcPlugin/xpcPlugin.xcodeproj' xcWorkspacePath: "xpcPlugin/xpcPlugin.xcodeproj"
xcodeVersion: 'default' # Options: 8, 9, 10, default, specifyPath xcodeVersion: "default" # Options: 8, 9, 10, default, specifyPath
- task: PublishPipelineArtifact@0 - task: PublishPipelineArtifact@0
inputs: inputs:
artifactName: '$(xpcArtifactNameMac)' artifactName: "$(xpcArtifactNameMac)"
targetPath: '$(xpcBuildOutputPath)' targetPath: "$(xpcBuildOutputPath)"
- job: Linux - job: Linux
pool: pool:
vmImage: 'ubuntu-latest' vmImage: "ubuntu-latest"
steps: steps:
- script: | - script: |
sudo add-apt-repository ppa:ubuntu-toolchain-r/test sudo add-apt-repository ppa:ubuntu-toolchain-r/test
sudo apt-get update sudo apt-get update
sudo apt-get install -y g++-5 mesa-common-dev g++-multilib g++-5-multilib sudo apt-get install -y g++-5 mesa-common-dev g++-multilib g++-5-multilib
displayName: 'apt install' displayName: "apt install"
- script: | - script: |
cd xpcPlugin cd xpcPlugin
cmake . cmake .
make make
displayName: 'make' displayName: "make"
- task: PublishPipelineArtifact@0 - task: PublishPipelineArtifact@0
inputs: inputs:
artifactName: 'xpc-linux' artifactName: "xpc-linux"
targetPath: '$(xpcBuildOutputPath)' targetPath: "$(xpcBuildOutputPath)"
- job: Windows - job: Windows
pool: pool:
vmImage: 'vs2017-win2016' vmImage: "vs2017-win2016"
variables: variables:
solution: 'xpcPlugin/xpcPlugin/xpcPlugin.sln' solution: "xpcPlugin/xpcPlugin/xpcPlugin.sln"
buildPlatform: 'Win32|x64' buildPlatform: "Win32|x64"
buildConfiguration: 'Release' buildConfiguration: "Release"
appxPackageDir: '$(build.artifactStagingDirectory)\AppxPackages\\' appxPackageDir: '$(build.artifactStagingDirectory)\AppxPackages\\'
steps: steps:
- task: NuGetToolInstaller@0 - task: NuGetToolInstaller@0
- task: NuGetCommand@2 - task: NuGetCommand@2
inputs: inputs:
restoreSolution: '$(solution)' restoreSolution: "$(solution)"
- task: VSBuild@1 - task: VSBuild@1
inputs: inputs:
platform: 'Win32' platform: "Win32"
solution: '$(solution)' solution: "$(solution)"
configuration: '$(buildConfiguration)' configuration: "$(buildConfiguration)"
msbuildArgs: '/p:AppxBundlePlatforms="$(buildPlatform)" /p:AppxPackageDir="$(appxPackageDir)" /p:AppxBundle=Always /p:UapAppxPackageBuildMode=StoreUpload' msbuildArgs: '/p:AppxBundlePlatforms="$(buildPlatform)" /p:AppxPackageDir="$(appxPackageDir)" /p:AppxBundle=Always /p:UapAppxPackageBuildMode=StoreUpload'
- task: VSBuild@1 - task: VSBuild@1
inputs: inputs:
platform: 'x64' platform: "x64"
solution: '$(solution)' solution: "$(solution)"
configuration: '$(buildConfiguration)' configuration: "$(buildConfiguration)"
msbuildArgs: '/p:AppxBundlePlatforms="$(buildPlatform)" /p:AppxPackageDir="$(appxPackageDir)" /p:AppxBundle=Always /p:UapAppxPackageBuildMode=StoreUpload' msbuildArgs: '/p:AppxBundlePlatforms="$(buildPlatform)" /p:AppxPackageDir="$(appxPackageDir)" /p:AppxBundle=Always /p:UapAppxPackageBuildMode=StoreUpload'
- task: Bash@3 - task: Bash@3
inputs: inputs:
targetType: 'inline' targetType: "inline"
script: | script: |
rm $(xpcBuildOutputPath)/win.exp rm $(xpcBuildOutputPath)/win.exp
rm $(xpcBuildOutputPath)/win.lib rm $(xpcBuildOutputPath)/win.lib
rm $(xpcBuildOutputPath)/64/win.exp rm $(xpcBuildOutputPath)/64/win.exp
rm $(xpcBuildOutputPath)/64/win.lib rm $(xpcBuildOutputPath)/64/win.lib
- task: PublishPipelineArtifact@0 - task: PublishPipelineArtifact@0
inputs: inputs:
artifactName: '$(xpcArtifactNameWindows)' artifactName: "$(xpcArtifactNameWindows)"
targetPath: '$(xpcBuildOutputPath)' targetPath: "$(xpcBuildOutputPath)"
- stage: Deploy - stage: Deploy
jobs: jobs:
- job: Package_Binaries - job: Package_Binaries
displayName: 'Package Binaries' displayName: "Package Binaries"
pool: pool:
vmImage: 'ubuntu-latest' vmImage: "ubuntu-latest"
steps: steps:
- task: DownloadPipelineArtifact@0 - task: DownloadPipelineArtifact@0
inputs: inputs:
artifactName: '$(xpcArtifactNameMac)' artifactName: "$(xpcArtifactNameMac)"
targetPath: $(System.DefaultWorkingDirectory)/$(xpcPackageName) targetPath: $(System.DefaultWorkingDirectory)/$(xpcPackageName)
- task: DownloadPipelineArtifact@0 - task: DownloadPipelineArtifact@0
inputs: inputs:
artifactName: '$(xpcArtifactNameLinux)' artifactName: "$(xpcArtifactNameLinux)"
targetPath: $(System.DefaultWorkingDirectory)/$(xpcPackageName) targetPath: $(System.DefaultWorkingDirectory)/$(xpcPackageName)
- task: DownloadPipelineArtifact@0 - task: DownloadPipelineArtifact@0
inputs: inputs:
artifactName: '$(xpcArtifactNameWindows)' artifactName: "$(xpcArtifactNameWindows)"
targetPath: $(System.DefaultWorkingDirectory)/$(xpcPackageName) targetPath: $(System.DefaultWorkingDirectory)/$(xpcPackageName)
- task: PublishPipelineArtifact@0 - task: PublishPipelineArtifact@0
inputs: inputs:
artifactName: '$(xpcPackageName)' artifactName: "$(xpcPackageName)"
targetPath: $(System.DefaultWorkingDirectory)/$(xpcPackageName) targetPath: $(System.DefaultWorkingDirectory)/$(xpcPackageName)
# Archive Files # Archive Files
- task: ArchiveFiles@2 - task: ArchiveFiles@2
inputs: inputs:
rootFolderOrFile: '$(System.DefaultWorkingDirectory)/$(xpcPackageName)' rootFolderOrFile: "$(System.DefaultWorkingDirectory)/$(xpcPackageName)"
includeRootFolder: true includeRootFolder: true
archiveType: 'zip' archiveType: "zip"
archiveFile: '$(Build.ArtifactStagingDirectory)/$(xpcPackageName).zip' archiveFile: "$(Build.ArtifactStagingDirectory)/$(xpcPackageName).zip"
# Uploads the .zip to GitHub and creates a new "Release" with the commit tag # Uploads the .zip to GitHub and creates a new "Release" with the commit tag
# This tasks runs only on pushed tags # This tasks runs only on pushed tags
- task: GitHubRelease@0 - task: GitHubRelease@0
inputs: inputs:
gitHubConnection: '$(xpcGitHubConnection)' gitHubConnection: "$(xpcGitHubConnection)"
repositoryName: '$(Build.Repository.Name)' repositoryName: "$(Build.Repository.Name)"
action: 'create' action: "create"
target: '$(Build.SourceVersion)' target: "$(Build.SourceVersion)"
tagSource: 'auto' tagSource: "auto"
tag: $(tagName) tag: $(tagName)
assets: '$(Build.ArtifactStagingDirectory)/$(xpcPackageName).zip' assets: "$(Build.ArtifactStagingDirectory)/$(xpcPackageName).zip"
isPreRelease: true isPreRelease: true
isDraft: true isDraft: true

View File

@@ -0,0 +1,173 @@
//
// support.cpp
// xpcPlugin
//
// Created by Kai Lehmkuehler on 14/01/2019.
//
#include <stdio.h>
#include "MessageHandlers.h"
#include "DataManager.h"
#include "Log.h"
#include "XPLMUtilities.h"
#include "XPLMGraphics.h"
#include <cmath>
#include <cstring>
namespace XPC
{
// Runway Camera Callback: Places the camera at campos.loc and points it at the aircraft, similar to a remote piloting experience.
// Optionally, the direction of the camera can be specified by the user.
int MessageHandlers::CamCallback_RunwayCam( XPLMCameraPosition_t * outCameraPosition, int inIsLosingControl, void *inRefcon)
{
if (outCameraPosition && !inIsLosingControl)
{
struct CameraProperties* campos = (struct CameraProperties*)inRefcon;
// camera position
double clat = campos->loc[0];
double clon = campos->loc[1];
double calt = campos->loc[2];
double cX;
double cY;
double cZ;
XPLMWorldToLocal(clat, clon, calt, &cX, &cY, &cZ);
outCameraPosition->x = cX;
outCameraPosition->y = cY;
outCameraPosition->z = cZ;
// Log::FormatLine(LOG_TRACE, "CAM", "Cam pos %f %f %f", clat, clon, calt);
// calculate camera direction to point at the aircraft
if(campos->direction[0] < -180)
{
// local aircraft position
double x = XPC::DataManager::GetDouble(XPC::DREF_LocalX, 0);
double y = XPC::DataManager::GetDouble(XPC::DREF_LocalY, 0);
double z = XPC::DataManager::GetDouble(XPC::DREF_LocalZ, 0);
// relative position vector camera to aircraft
double dx = x - cX;
double dy = y - cY;
double dz = z - cZ;
// Log::FormatLine(LOG_TRACE, "CAM", "Cam vect %f %f %f", dx, dy, dz);
double pi = 3.141592653589793;
// horizontal distance
double dist = sqrt(dx*dx + dz*dz);
outCameraPosition->pitch = atan2(dy, dist) * 180.0/pi;
double angle = atan2(dz, dx) * 180.0/pi; // rel to pos right (pos X)
outCameraPosition->heading = 90 + angle; // rel to north
// Log::FormatLine(LOG_TRACE, "CAM", "Cam p %f hdg %f ", outCameraPosition->pitch, outCameraPosition->heading);
outCameraPosition->roll = 0;
}
// point camera at specified direction
else
{
outCameraPosition->roll = campos->direction[0];
outCameraPosition->pitch = campos->direction[1];
outCameraPosition->heading = campos->direction[2];
}
outCameraPosition->zoom = campos->zoom;
}
return 1;
}
// Chase Camera Callback: Places the camera at campos.loc RELATIVE to and MOVING with the aircraft, pointing at the specified
// direction.
int MessageHandlers::CamCallback_ChaseCam( XPLMCameraPosition_t * outCameraPosition, int inIsLosingControl, void *inRefcon)
{
if (outCameraPosition && !inIsLosingControl)
{
double DTR = 3.141592653589793 / 180.0;
struct CameraProperties* campos = (struct CameraProperties*)inRefcon;
// Camera location relative to aircraft (local axes)
// local aircraft position
double x = XPC::DataManager::GetDouble(XPC::DREF_LocalX, 0); // +east
double y = XPC::DataManager::GetDouble(XPC::DREF_LocalY, 0); // +up
double z = XPC::DataManager::GetDouble(XPC::DREF_LocalZ, 0); // +south
// aircraft attitude - degrees
double phi = XPC::DataManager::GetFloat(XPC::DREF_Roll, 0);
double the = XPC::DataManager::GetFloat(XPC::DREF_Pitch, 0);
double psi = XPC::DataManager::GetFloat(XPC::DREF_HeadingTrue, 0);
// camera position vector with respect to aircraft CG [m] (body axes)
double c_x = campos->loc[0]; // back
double c_y = campos->loc[1]; // right
double c_z = campos->loc[2]; // up
// camera position vector in local axes - will move with aircraft if not along principal axes
// cLocal = Leb * cBody
// http://www.xsquawkbox.net/xpsdk/mediawiki/ScreenCoordinates
double x_phi=c_y*cos(phi*DTR) + c_z*sin(phi*DTR);
double y_phi=c_z*cos(phi*DTR) - c_y*sin(phi*DTR);
double z_phi=c_x;
double x_the=x_phi;
double y_the=y_phi*cos(the*DTR) - z_phi*sin(the*DTR);
double z_the=z_phi*cos(the*DTR) + y_phi*sin(the*DTR);
double x_wrl=x_the*cos(psi*DTR) - z_the*sin(psi*DTR);
double y_wrl=y_the ;
double z_wrl=z_the*cos(psi*DTR) + x_the*sin(psi*DTR);
outCameraPosition->x = x + x_wrl;
outCameraPosition->y = y + y_wrl;
outCameraPosition->z = z + z_wrl;
// set direction value to -998 to keep camera pointing straight along that axis
if(campos->direction[0] < -180)
{
outCameraPosition->roll = 0;
}
else
{
outCameraPosition->roll = phi + campos->direction[0];
}
if(campos->direction[1] < -180)
{
outCameraPosition->pitch = 0;
}
else
{
outCameraPosition->pitch = the + campos->direction[1];
}
if(campos->direction[2] < -180)
{
outCameraPosition->heading = 0;
}
else
{
outCameraPosition->heading = psi + campos->direction[2];
}
outCameraPosition->zoom = campos->zoom;
}
return 1;
}
}

View File

@@ -19,6 +19,7 @@
#include "XPLMDataAccess.h" #include "XPLMDataAccess.h"
#include "XPLMGraphics.h" #include "XPLMGraphics.h"
#include "XPLMUtilities.h"
#include <algorithm> #include <algorithm>
#include <cmath> #include <cmath>
@@ -668,6 +669,11 @@ namespace XPC
return; return;
} }
if (IsDefault(pos[0]) && IsDefault(pos[1]) && IsDefault(pos[2]))
{
Log::WriteLine(LOG_INFO, "DMAN", "Skipped SetPosition. All values were default");
return;
}
if (IsDefault(pos[0])) if (IsDefault(pos[0]))
{ {
pos[0] = GetDouble(DREF_Latitude, aircraft); pos[0] = GetDouble(DREF_Latitude, aircraft);
@@ -718,6 +724,12 @@ namespace XPC
return; return;
} }
if (IsDefault(orient[0]) && IsDefault(orient[1]) && IsDefault(orient[2]))
{
Log::WriteLine(LOG_INFO, "DMAN", "Skipped SetPosition. All values were default");
return;
}
if (IsDefault(orient[0])) if (IsDefault(orient[0]))
{ {
orient[0] = GetFloat(DREF_Pitch, aircraft); orient[0] = GetFloat(DREF_Pitch, aircraft);
@@ -780,6 +792,21 @@ namespace XPC
Set(DREF_FlapActual, value); Set(DREF_FlapActual, value);
} }
void DataManager::Execute(const std::string& comm)
{
Log::FormatLine(LOG_INFO, "DMAN", "Executing command (value:%s)", comm.c_str());
XPLMCommandRef xcref = XPLMFindCommand(comm.c_str());
if (!xcref)
{
// COMM does not exist
Log::FormatLine(LOG_ERROR, "DMAN", "ERROR: invalid COMM %s", comm.c_str());
return;
}
XPLMCommandOnce(xcref);
}
float DataManager::GetDefaultValue() float DataManager::GetDefaultValue()
{ {
return -998.0F; return -998.0F;

View File

@@ -410,6 +410,11 @@ namespace XPC
/// \param value The flaps settings. Should be between 0.0 (no flaps) and 1.0 (full flaps). /// \param value The flaps settings. Should be between 0.0 (no flaps) and 1.0 (full flaps).
static void SetFlaps(float value); static void SetFlaps(float value);
/// Executes a command
///
/// \param comm The name of the command to execute.
static void Execute(const std::string& comm);
/// Gets a default value that indicates that a dataref should not be changed. /// Gets a default value that indicates that a dataref should not be changed.
static float GetDefaultValue(); static float GetDefaultValue();

View File

@@ -121,7 +121,7 @@ namespace XPC
} }
Log::WriteLine(LOG_DEBUG, "DBUG", ss.str()); Log::WriteLine(LOG_DEBUG, "DBUG", ss.str());
} }
else if (head == "GETC" || head == "GETP") else if (head == "GETC" || head == "GETP" || head == "GETT")
{ {
ss << " Aircraft:" << (int)buffer[5]; ss << " Aircraft:" << (int)buffer[5];
Log::WriteLine(LOG_DEBUG, "DBUG", ss.str()); Log::WriteLine(LOG_DEBUG, "DBUG", ss.str());
@@ -138,14 +138,28 @@ namespace XPC
cur += 1 + buffer[cur]; cur += 1 + buffer[cur];
} }
} }
else if (head == "POSI") else if (head == "POSI" || head == "POST")
{ {
char aircraft = buffer[5]; char aircraft = buffer[5];
float gear = *((float*)(buffer + 30)); float gear;
float pos[3]; double pos[3];
float orient[3]; float orient[3];
memcpy(pos, buffer + 6, 12); if (size == 34) /* lat/lon/h as 32-bit float */
memcpy(orient, buffer + 18, 12); {
float posd_32[3];
memcpy(posd_32, buffer + 6, 12);
pos[0] = posd_32[0];
pos[1] = posd_32[1];
pos[2] = posd_32[2];
memcpy(orient, buffer + 18, 12);
memcpy(&gear, buffer + 30, 4);
}
else if (size == 46) /* lat/lon/h as 64-bit double */
{
memcpy(pos, buffer + 6, 24);
memcpy(orient, buffer + 30, 12);
memcpy(&gear, buffer + 42, 4);
}
ss << " AC:" << (int)aircraft; ss << " AC:" << (int)aircraft;
ss << " Pos:(" << pos[0] << ' ' << pos[1] << ' ' << pos[2] << ") Orient:("; ss << " Pos:(" << pos[0] << ' ' << pos[1] << ' ' << pos[2] << ") Orient:(";
ss << orient[0] << ' ' << orient[1] << ' ' << orient[2] << ") Gear:"; ss << orient[0] << ' ' << orient[1] << ' ' << orient[2] << ") Gear:";
@@ -162,6 +176,11 @@ namespace XPC
ss << "Type:" << *((unsigned long*)(buffer + 5)); ss << "Type:" << *((unsigned long*)(buffer + 5));
Log::WriteLine(LOG_DEBUG, "DBUG", ss.str()); Log::WriteLine(LOG_DEBUG, "DBUG", ss.str());
} }
else if (head == "COMM")
{
ss << "Type:" << *((unsigned long*)(buffer + 5));
Log::WriteLine(LOG_DEBUG, "DBUG", ss.str());
}
else else
{ {
ss << " UNKNOWN HEADER "; ss << " UNKNOWN HEADER ";

View File

@@ -8,21 +8,22 @@
// including without limitation the rights to use, copy, modify, merge, publish, distribute, // including without limitation the rights to use, copy, modify, merge, publish, distribute,
// sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is // sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions : // furnished to do so, subject to the following conditions :
// * Redistributions of source code must retain the above copyright notice, // * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer. // this list of conditions and the following disclaimer.
// * Neither the names of the authors nor that of X - Plane or Laminar Research // * Neither the names of the authors nor that of X - Plane or Laminar Research
// may be used to endorse or promote products derived from this software // may be used to endorse or promote products derived from this software
// without specific prior written permission from the authors or // without specific prior written permission from the authors or
// Laminar Research, respectively. // Laminar Research, respectively.
#include "MessageHandlers.h" #include "MessageHandlers.h"
#include "DataManager.h" #include "DataManager.h"
#include "Drawing.h" #include "Drawing.h"
#include "Log.h" #include "Log.h"
#include "XPLMUtilities.h" #include "XPLMUtilities.h"
#include "XPLMScenery.h"
#include "XPLMGraphics.h" #include "XPLMGraphics.h"
#include <cmath> #include <cmath>
#include <cstring> #include <cstring>
#include <cstdint> #include <cstdint>
@@ -30,7 +31,6 @@
#define MULTICAST_GROUP "239.255.1.1" #define MULTICAST_GROUP "239.255.1.1"
#define MULITCAST_PORT 49710 #define MULITCAST_PORT 49710
namespace XPC namespace XPC
{ {
std::map<std::string, MessageHandlers::ConnectionInfo> MessageHandlers::connections; std::map<std::string, MessageHandlers::ConnectionInfo> MessageHandlers::connections;
@@ -39,8 +39,11 @@ namespace XPC
std::string MessageHandlers::connectionKey; std::string MessageHandlers::connectionKey;
MessageHandlers::ConnectionInfo MessageHandlers::connection; MessageHandlers::ConnectionInfo MessageHandlers::connection;
UDPSocket* MessageHandlers::sock; UDPSocket* MessageHandlers::sock;
static sockaddr multicast_address = UDPSocket::GetAddr(MULTICAST_GROUP, MULITCAST_PORT); static sockaddr multicast_address = UDPSocket::GetAddr(MULTICAST_GROUP, MULITCAST_PORT);
// define a static terrain probe handler (do not re-create probe for each query)
XPLMProbeRef Terrain_probe = nullptr;
void MessageHandlers::SetSocket(UDPSocket* socket) void MessageHandlers::SetSocket(UDPSocket* socket)
{ {
@@ -60,12 +63,15 @@ namespace XPC
handlers.insert(std::make_pair("DREF", MessageHandlers::HandleDref)); handlers.insert(std::make_pair("DREF", MessageHandlers::HandleDref));
handlers.insert(std::make_pair("GETD", MessageHandlers::HandleGetD)); handlers.insert(std::make_pair("GETD", MessageHandlers::HandleGetD));
handlers.insert(std::make_pair("POSI", MessageHandlers::HandlePosi)); handlers.insert(std::make_pair("POSI", MessageHandlers::HandlePosi));
handlers.insert(std::make_pair("POST", MessageHandlers::HandlePosT));
handlers.insert(std::make_pair("SIMU", MessageHandlers::HandleSimu)); handlers.insert(std::make_pair("SIMU", MessageHandlers::HandleSimu));
handlers.insert(std::make_pair("TEXT", MessageHandlers::HandleText)); handlers.insert(std::make_pair("TEXT", MessageHandlers::HandleText));
handlers.insert(std::make_pair("WYPT", MessageHandlers::HandleWypt)); handlers.insert(std::make_pair("WYPT", MessageHandlers::HandleWypt));
handlers.insert(std::make_pair("VIEW", MessageHandlers::HandleView)); handlers.insert(std::make_pair("VIEW", MessageHandlers::HandleView));
handlers.insert(std::make_pair("GETC", MessageHandlers::HandleGetC)); handlers.insert(std::make_pair("GETC", MessageHandlers::HandleGetC));
handlers.insert(std::make_pair("GETP", MessageHandlers::HandleGetP)); handlers.insert(std::make_pair("GETP", MessageHandlers::HandleGetP));
handlers.insert(std::make_pair("COMM", MessageHandlers::HandleComm));
handlers.insert(std::make_pair("GETT", MessageHandlers::HandleGetT));
// X-Plane data messages // X-Plane data messages
handlers.insert(std::make_pair("DSEL", MessageHandlers::HandleXPlaneData)); handlers.insert(std::make_pair("DSEL", MessageHandlers::HandleXPlaneData));
handlers.insert(std::make_pair("USEL", MessageHandlers::HandleXPlaneData)); handlers.insert(std::make_pair("USEL", MessageHandlers::HandleXPlaneData));
@@ -136,11 +142,11 @@ namespace XPC
MessageHandlers::HandleUnknown(msg); MessageHandlers::HandleUnknown(msg);
} }
} }
void MessageHandlers::SendBeacon(const std::string& pluginVersion, unsigned short pluginReceivePort, int xplaneVersion) { void MessageHandlers::SendBeacon(const std::string& pluginVersion, unsigned short pluginReceivePort, int xplaneVersion) {
unsigned char response[128] = "BECN"; unsigned char response[128] = "BECN";
std::size_t cur = 5; std::size_t cur = 5;
// 2 bytes plugin port // 2 bytes plugin port
@@ -150,12 +156,12 @@ namespace XPC
// 4 bytes xplane version // 4 bytes xplane version
*((uint32_t*)(response + cur)) = xplaneVersion; *((uint32_t*)(response + cur)) = xplaneVersion;
cur += sizeof(uint32_t); cur += sizeof(uint32_t);
// plugin version // plugin version
int len = pluginVersion.length(); int len = pluginVersion.length();
memcpy(response + cur, pluginVersion.c_str(), len); memcpy(response + cur, pluginVersion.c_str(), len);
cur += strlen(pluginVersion.c_str()) + len; cur += strlen(pluginVersion.c_str()) + len;
sock->SendTo(response, cur, &multicast_address); sock->SendTo(response, cur, &multicast_address);
} }
@@ -554,21 +560,20 @@ namespace XPC
unsigned char aircraft = buffer[5]; unsigned char aircraft = buffer[5];
Log::FormatLine(LOG_TRACE, "GPOS", "Getting position information for aircraft %u", aircraft); 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); response[5] = (char)DataManager::GetInt(DREF_GearHandle, aircraft);
// TODO change lat/lon/h to double? *((double*)(response + 6)) = DataManager::GetDouble(DREF_Latitude, aircraft);
*((float*)(response + 6)) = (float)DataManager::GetDouble(DREF_Latitude, aircraft); *((double*)(response + 14)) = DataManager::GetDouble(DREF_Longitude, aircraft);
*((float*)(response + 10)) = (float)DataManager::GetDouble(DREF_Longitude, aircraft); *((double*)(response + 22)) = DataManager::GetDouble(DREF_Elevation, aircraft);
*((float*)(response + 14)) = (float)DataManager::GetDouble(DREF_Elevation, aircraft); *((float*)(response + 30)) = DataManager::GetFloat(DREF_Pitch, aircraft);
*((float*)(response + 18)) = DataManager::GetFloat(DREF_Pitch, aircraft); *((float*)(response + 34)) = DataManager::GetFloat(DREF_Roll, aircraft);
*((float*)(response + 22)) = DataManager::GetFloat(DREF_Roll, aircraft); *((float*)(response + 38)) = DataManager::GetFloat(DREF_HeadingTrue, aircraft);
*((float*)(response + 26)) = DataManager::GetFloat(DREF_HeadingTrue, aircraft);
float gear[10]; float gear[10];
DataManager::GetFloatArray(DREF_GearDeploy, gear, 10, aircraft); 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) void MessageHandlers::HandlePosi(const Message& msg)
@@ -580,21 +585,26 @@ namespace XPC
const std::size_t size = msg.GetSize(); const std::size_t size = msg.GetSize();
char aircraftNumber = buffer[5]; char aircraftNumber = buffer[5];
float gear = *((float*)(buffer + 42)); float gear;
double posd[3]; double posd[3];
float orient[3]; float orient[3];
if (size == 34) /* lat/lon/h as 32-bit float */ if (size == 34) /* lat/lon/h as 32-bit float */
{ {
posd[0] = *((float*)&buffer[6]); float posd_32[3];
posd[1] = *((float*)&buffer[10]); memcpy(posd_32, buffer + 6, 12);
posd[2] = *((float*)&buffer[14]); /* convert float to double */
posd[0] = posd_32[0];
posd[1] = posd_32[1];
posd[2] = posd_32[2];
memcpy(orient, buffer + 18, 12); memcpy(orient, buffer + 18, 12);
memcpy(&gear, buffer + 30, 4);
} }
else if (size == 46) /* lat/lon/h as 64-bit double */ else if (size == 46) /* lat/lon/h as 64-bit double */
{ {
memcpy(posd, buffer + 6, 3*8); memcpy(posd, buffer + 6, 24);
memcpy(orient, buffer + 30, 12); memcpy(orient, buffer + 30, 12);
memcpy(&gear, buffer + 42, 4);
} }
else else
{ {
@@ -602,7 +612,6 @@ namespace XPC
return; return;
} }
/* convert float to double */
DataManager::SetPosition(posd, aircraftNumber); DataManager::SetPosition(posd, aircraftNumber);
DataManager::SetOrientation(orient, aircraftNumber); DataManager::SetOrientation(orient, aircraftNumber);
if (gear >= 0) if (gear >= 0)
@@ -623,6 +632,135 @@ namespace XPC
} }
} }
void MessageHandlers::HandlePosT(const Message& msg)
{
MessageHandlers::HandlePosi(msg);
const unsigned char* buffer = msg.GetBuffer();
char aircraftNumber = buffer[5];
Log::FormatLine(LOG_TRACE, "POST", "Getting terrain information for aircraft %u", aircraftNumber);
double pos[3];
pos[0] = DataManager::GetDouble(DREF_Latitude, aircraftNumber);
pos[1] = DataManager::GetDouble(DREF_Longitude, aircraftNumber);
pos[2] = 0.0;
MessageHandlers::SendTerr(pos, aircraftNumber);
}
void MessageHandlers::HandleGetT(const Message& msg)
{
const unsigned char* buffer = msg.GetBuffer();
std::size_t size = msg.GetSize();
if (size != 30)
{
Log::FormatLine(LOG_ERROR, "GETT", "Unexpected message length: %u", size);
return;
}
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);
if(pos[0] == -998 || pos[1] == -998 || pos[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;
}
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;
probe_data.structSize = sizeof(XPLMProbeInfo_t);
if(Terrain_probe == nullptr)
{
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 lat/lon/0 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);
Terrain_probe = nullptr;
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 original 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, "TERR", "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);
}
// keep probe for next query
// XPLMDestroyProbe(Terrain_probe);
// Assemble response message
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 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 + 54, &probe_data.is_wet, 4);
// probe status
memcpy(response + 58, &rc, 4);
sock->SendTo(response, 62, &connection.addr);
}
void MessageHandlers::HandleSimu(const Message& msg) void MessageHandlers::HandleSimu(const Message& msg)
{ {
// Update log // Update log
@@ -717,112 +855,92 @@ namespace XPC
Log::WriteLine(LOG_INFO, "TEXT", "[TEXT] Text set"); Log::WriteLine(LOG_INFO, "TEXT", "[TEXT] Text set");
} }
} }
void MessageHandlers::HandleView(const Message& msg) void MessageHandlers::HandleView(const Message& msg)
{ {
// Update Log // Update Log
Log::FormatLine(LOG_TRACE, "VIEW", "Message Received(Conn %i)", connection.id); Log::FormatLine(LOG_TRACE, "VIEW", "Message Received(Conn %i)", connection.id);
int enable_camera_location = 0; bool enable_advanced_camera = false;
const std::size_t size = msg.GetSize(); const std::size_t size = msg.GetSize();
if (size == 9) if (size == 9)
{ {
// default view switcher as before // default view switcher as before
} }
else if (size == 37) else if (size == 49)
{ {
// Allow camera location control // Allow camera location control
enable_camera_location = 1; enable_advanced_camera = true;
} }
else else
{ {
Log::FormatLine(LOG_ERROR, "VIEW", "Error: Unexpected length. Message was %d bytes, expected 9 or 37.", size); Log::FormatLine(LOG_ERROR, "VIEW", "Error: Unexpected length. Message was %d bytes, expected 9 or 49.", size);
return; return;
} }
// get msg data
const unsigned char* buffer = msg.GetBuffer(); const unsigned char* buffer = msg.GetBuffer();
int type = *((int*)(buffer + 5));
XPLMCommandKeyStroke(type);
if(type == 79 && enable_camera_location == 1) // runway camera view // get view type
int view_type;
memcpy(&view_type, buffer + 5, 4);
// set view by calling the corresponding key stroke
XPLMCommandKeyStroke(view_type);
VIEW_TYPE viewRunway = VIEW_TYPE::XPC_VIEW_RUNWAY;
VIEW_TYPE viewChase = VIEW_TYPE::XPC_VIEW_CHASE;
// advanced runway camera view
if(view_type == static_cast<int>(viewRunway) && enable_advanced_camera == true)
{ {
static struct CameraProperties campos; static struct CameraProperties campos; // static variable for continuous callback access
campos.loc[0] = *(double*)(buffer+9);
campos.loc[1] = *(double*)(buffer+17);
campos.loc[2] = *(double*)(buffer+25);
campos.direction[0] = -998;
campos.direction[1] = -998;
campos.direction[2] = -998;
campos.zoom = *(float*)(buffer+33);
Log::FormatLine(LOG_TRACE, "VIEW", "Cam pos %f %f %f zoom %f", campos.loc[0], campos.loc[1], campos.loc[2],campos.zoom); memcpy(&campos, buffer+9 , sizeof(struct CameraProperties));
XPLMControlCamera(xplm_ControlCameraUntilViewChanges, CamFunc, &campos); Log::FormatLine(LOG_TRACE, "VIEW", "Cam pos %f %f %f zoom %f", campos.loc[0], campos.loc[1], campos.loc[2], campos.zoom);
XPLMControlCamera(xplm_ControlCameraUntilViewChanges, CamCallback_RunwayCam, &campos);
}
// advanced chase camera view
else if(view_type == static_cast<int>(viewChase) && enable_advanced_camera == true)
{
static struct CameraProperties campos; // static variable for continuous callback access
memcpy(&campos, buffer+9 , sizeof(struct CameraProperties));
Log::FormatLine(LOG_TRACE, "VIEW", "Cam pos %f %f %f zoom %f", campos.loc[0], campos.loc[1], campos.loc[2], campos.zoom);
XPLMControlCamera(xplm_ControlCameraUntilViewChanges, CamCallback_ChaseCam, &campos);
} }
} }
int MessageHandlers::CamFunc( XPLMCameraPosition_t * outCameraPosition, int inIsLosingControl, void *inRefcon) void MessageHandlers::HandleComm(const Message& msg)
{ {
if (outCameraPosition && !inIsLosingControl) Log::FormatLine(LOG_TRACE, "COMM", "Request to execute COMM command received (Conn %i)", connection.id);
{ const unsigned char* buffer = msg.GetBuffer();
struct CameraProperties* campos = (struct CameraProperties*)inRefcon; std::size_t size = msg.GetSize();
std::size_t pos = 5;
// camera position while (pos < size)
double clat = campos->loc[0]; {
double clon = campos->loc[1]; unsigned char len = buffer[pos++];
double calt = campos->loc[2]; if (pos + len > size)
{
double cX, cY, cZ; break;
XPLMWorldToLocal(clat, clon, calt, &cX, &cY, &cZ); }
std::string comm = std::string((char*)buffer + pos, len);
outCameraPosition->x = cX; pos += len;
outCameraPosition->y = cY;
outCameraPosition->z = cZ; DataManager::Execute(comm);
Log::FormatLine(LOG_DEBUG, "COMM", "Execute command %s", comm.c_str());
// Log::FormatLine(LOG_TRACE, "CAM", "Cam pos %f %f %f", clat, clon, calt); }
if (pos != size)
if(campos->direction[0] == -998) // calculate camera direction {
{ Log::WriteLine(LOG_ERROR, "COMM", "ERROR: Command did not terminate at the expected position.");
// aircraft position }
double x = XPC::DataManager::GetDouble(XPC::DREF_LocalX, 0); }
double y = XPC::DataManager::GetDouble(XPC::DREF_LocalY, 0);
double z = XPC::DataManager::GetDouble(XPC::DREF_LocalZ, 0);
// relative position vector cam to plane
double dx = x - cX;
double dy = y - cY;
double dz = z - cZ;
// Log::FormatLine(LOG_TRACE, "CAM", "Cam vect %f %f %f", dx, dy, dz);
double pi = 3.141592653589793;
// horizontal distance
double dist = sqrt(dx*dx + dz*dz);
outCameraPosition->pitch = atan2(dy, dist) * 180.0/pi;
double angle = atan2(dz, dx) * 180.0/pi; // rel to pos right (pos X)
outCameraPosition->heading = 90 + angle; // rel to north
// Log::FormatLine(LOG_TRACE, "CAM", "Cam p %f hdg %f ", outCameraPosition->pitch, outCameraPosition->heading);
outCameraPosition->roll = 0;
}
else
{
outCameraPosition->roll = campos->direction[0];
outCameraPosition->pitch = campos->direction[1];
outCameraPosition->heading = campos->direction[2];
}
outCameraPosition->zoom = campos->zoom;
}
return 1;
}
void MessageHandlers::HandleWypt(const Message& msg) void MessageHandlers::HandleWypt(const Message& msg)
{ {

View File

@@ -14,6 +14,23 @@ namespace XPC
{ {
/// A function that handles a message. /// A function that handles a message.
typedef void(*MessageHandler)(const Message&); typedef void(*MessageHandler)(const Message&);
enum class VIEW_TYPE
{
XPC_VIEW_FORWARDS = 73,
XPC_VIEW_DOWN,
XPC_VIEW_LEFT,
XPC_VIEW_RIGHT,
XPC_VIEW_BACK,
XPC_VIEW_TOWER,
XPC_VIEW_RUNWAY,
XPC_VIEW_CHASE,
XPC_VIEW_FOLLOW,
XPC_VIEW_FOLLOWWITHPANEL,
XPC_VIEW_SPOT,
XPC_VIEW_FULLSCREENWITHHUD,
XPC_VIEW_FULLSCREENNOHUD,
};
/// Handles incoming messages and manages connections. /// Handles incoming messages and manages connections.
/// ///
@@ -40,6 +57,8 @@ namespace XPC
static void SetSocket(UDPSocket* socket); static void SetSocket(UDPSocket* socket);
static void SendBeacon(const std::string& pluginVersion, unsigned short pluginReceivePort, int xplaneVersion); static void SendBeacon(const std::string& pluginVersion, unsigned short pluginReceivePort, int xplaneVersion);
static void SendTerr(double pos[3], char aircraft);
private: private:
// One handler per message type. Message types are descripbed on the // One handler per message type. Message types are descripbed on the
@@ -51,16 +70,20 @@ namespace XPC
static void HandleGetC(const Message& msg); static void HandleGetC(const Message& msg);
static void HandleGetD(const Message& msg); static void HandleGetD(const Message& msg);
static void HandleGetP(const Message& msg); static void HandleGetP(const Message& msg);
static void HandleGetT(const Message& msg);
static void HandlePosi(const Message& msg); static void HandlePosi(const Message& msg);
static void HandlePosT(const Message& msg);
static void HandleSimu(const Message& msg); static void HandleSimu(const Message& msg);
static void HandleText(const Message& msg); static void HandleText(const Message& msg);
static void HandleWypt(const Message& msg); static void HandleWypt(const Message& msg);
static void HandleView(const Message& msg); static void HandleView(const Message& msg);
static void HandleComm(const Message& msg);
static void HandleXPlaneData(const Message& msg); static void HandleXPlaneData(const Message& msg);
static void HandleUnknown(const Message& msg); static void HandleUnknown(const Message& msg);
static int CamFunc( XPLMCameraPosition_t * outCameraPosition, int inIsLosingControl, void *inRefcon); static int CamCallback_RunwayCam( XPLMCameraPosition_t * outCameraPosition, int inIsLosingControl, void *inRefcon);
static int CamCallback_ChaseCam( XPLMCameraPosition_t * outCameraPosition, int inIsLosingControl, void *inRefcon);
struct CameraProperties{ struct CameraProperties{
double loc[3]; double loc[3];

View File

@@ -56,22 +56,25 @@ namespace XPC
return; return;
} }
// Set Timout // Set timeout period for SendTo to 1 millisecond
int usTimeOut = 500; // Without this, playback may become choppy due to process blocking
#ifdef _WIN32 #ifdef _WIN32
DWORD msTimeOutWin = 1; // Minimum socket timeout in Windows is 1ms // Minimum socket timeout in Windows is 1 millisecond (0 makes it blocking)
if(setsockopt(this->sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&msTimeOutWin, sizeof(msTimeOutWin)) != 0) DWORD timeout = 1;
#else
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 1000;
#endif
if (setsockopt(this->sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)) < 0)
{ {
#ifdef _WIN32
int err = WSAGetLastError(); int err = WSAGetLastError();
Log::FormatLine(LOG_ERROR, tag, "ERROR: Failed to set timeout. (Error code %i)", err); Log::FormatLine(LOG_ERROR, tag, "ERROR: Failed to set timeout. (Error code %i)", err);
}
#else #else
struct timeval tv; Log::WriteLine(LOG_ERROR, tag, "ERROR: Failed to set timeout.");
tv.tv_sec = 0;
tv.tv_usec = usTimeOut;
setsockopt(this->sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval));
#endif #endif
}
} }
UDPSocket::~UDPSocket() UDPSocket::~UDPSocket()
@@ -87,43 +90,54 @@ namespace XPC
int UDPSocket::Read(unsigned char* dst, int maxLen, sockaddr* recvAddr) const int UDPSocket::Read(unsigned char* dst, int maxLen, sockaddr* recvAddr) const
{ {
socklen_t recvaddrlen = sizeof(*recvAddr); socklen_t recvaddrlen = sizeof(*recvAddr);
int status = 0;
#ifdef _WIN32 // For Read, use the select command - minimum timeout of 0 makes it polling.
// Windows readUDP needs the select command- minimum timeout is 1ms. // Without this, playback may become choppy due to process blocking
// Without this playback becomes choppy
// Definitions // Definitions
FD_SET stReadFDS; fd_set stReadFDS;
FD_SET stExceptFDS; fd_set stExceptFDS;
timeval tv; struct timeval timeout;
// Setup for Select // Setup for Select
FD_ZERO(&stReadFDS); FD_ZERO(&stReadFDS);
FD_SET(sock, &stReadFDS); FD_SET(sock, &stReadFDS);
FD_ZERO(&stExceptFDS); FD_ZERO(&stExceptFDS);
FD_SET(sock, &stExceptFDS); FD_SET(sock, &stExceptFDS);
tv.tv_sec = 0;
tv.tv_usec = 250; // Set timeout period for select to 0 to poll the socket
timeout.tv_sec = 0;
timeout.tv_usec = 0;
// Select Command // Select Command
int result = select(-1, &stReadFDS, (FD_SET *)0, &stExceptFDS, &tv); int status = select(sock+1, &stReadFDS, NULL, &stExceptFDS, &timeout);
if (result == SOCKET_ERROR) if (status < 0)
{ {
#ifdef _WIN32
int err = WSAGetLastError(); int err = WSAGetLastError();
Log::FormatLine(LOG_ERROR, tag, "ERROR: Select failed. (Error code %i)", err); Log::FormatLine(LOG_ERROR, tag, "ERROR: Select failed. (Error code %i)", err);
#else
Log::WriteLine(LOG_ERROR, tag, "ERROR: Select failed.");
#endif
return -1;
} }
if (result <= 0) // No Data or error if (status == 0)
{ {
// No data
return -1; return -1;
} }
// If no error: Read Data // If no error: Read Data
status = recvfrom(sock, (char*)dst, maxLen, 0, recvAddr, &recvaddrlen); status = recvfrom(sock, (char*)dst, maxLen, 0, recvAddr, &recvaddrlen);
if (status < 0)
{
#ifdef _WIN32
int err = WSAGetLastError();
Log::FormatLine(LOG_ERROR, tag, "ERROR: Receive failed. (Error code %i)", err);
#else #else
// For apple or linux-just read - will timeout in 0.5 ms Log::WriteLine(LOG_ERROR, tag, "ERROR: Receive failed.");
status = (int)recvfrom(sock, dst, 5000, 0, recvAddr, &recvaddrlen);
#endif #endif
}
return status; return status;
} }

View File

@@ -13,6 +13,8 @@
#include <sys/socket.h> #include <sys/socket.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#endif #endif

View File

@@ -8,6 +8,7 @@
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
3D0F44CE21C6D3E7008A0655 /* Timer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D0F44CD21C6D3E7008A0655 /* Timer.cpp */; }; 3D0F44CE21C6D3E7008A0655 /* Timer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D0F44CD21C6D3E7008A0655 /* Timer.cpp */; };
5B36040D23731E4A003ACE12 /* CameraCallbacks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5B36040C23731E4A003ACE12 /* CameraCallbacks.cpp */; };
BE37D960187C8B0F0033B082 /* XPCPlugin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE37D95E187C8B0F0033B082 /* XPCPlugin.cpp */; }; BE37D960187C8B0F0033B082 /* XPCPlugin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE37D95E187C8B0F0033B082 /* XPCPlugin.cpp */; };
BE8361EF18C5591C00E9C923 /* mac.xpl in CopyFiles */ = {isa = PBXBuildFile; fileRef = D607B19909A556E400699BC3 /* mac.xpl */; }; BE8361EF18C5591C00E9C923 /* mac.xpl in CopyFiles */ = {isa = PBXBuildFile; fileRef = D607B19909A556E400699BC3 /* mac.xpl */; };
BEABAD371AE041A3007BA7DA /* DataManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEABAD2B1AE041A3007BA7DA /* DataManager.cpp */; }; BEABAD371AE041A3007BA7DA /* DataManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEABAD2B1AE041A3007BA7DA /* DataManager.cpp */; };
@@ -39,6 +40,7 @@
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
3D0F44CC21C6D3E7008A0655 /* Timer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Timer.h; sourceTree = "<group>"; }; 3D0F44CC21C6D3E7008A0655 /* Timer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Timer.h; sourceTree = "<group>"; };
3D0F44CD21C6D3E7008A0655 /* Timer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Timer.cpp; sourceTree = "<group>"; }; 3D0F44CD21C6D3E7008A0655 /* Timer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Timer.cpp; sourceTree = "<group>"; };
5B36040C23731E4A003ACE12 /* CameraCallbacks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CameraCallbacks.cpp; sourceTree = "<group>"; };
BE37D95E187C8B0F0033B082 /* XPCPlugin.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = XPCPlugin.cpp; sourceTree = SOURCE_ROOT; usesTabs = 1; }; BE37D95E187C8B0F0033B082 /* XPCPlugin.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = XPCPlugin.cpp; sourceTree = SOURCE_ROOT; usesTabs = 1; };
BEABAD2B1AE041A3007BA7DA /* DataManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DataManager.cpp; sourceTree = "<group>"; }; BEABAD2B1AE041A3007BA7DA /* DataManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DataManager.cpp; sourceTree = "<group>"; };
BEABAD2C1AE041A3007BA7DA /* DataManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DataManager.h; sourceTree = "<group>"; }; BEABAD2C1AE041A3007BA7DA /* DataManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DataManager.h; sourceTree = "<group>"; };
@@ -53,7 +55,6 @@
BEABAD3D1AE0498D007BA7DA /* UDPSocket.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UDPSocket.cpp; sourceTree = "<group>"; }; BEABAD3D1AE0498D007BA7DA /* UDPSocket.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UDPSocket.cpp; sourceTree = "<group>"; };
BEABAD3E1AE0498D007BA7DA /* UDPSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UDPSocket.h; sourceTree = "<group>"; }; BEABAD3E1AE0498D007BA7DA /* UDPSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UDPSocket.h; sourceTree = "<group>"; };
BEDC620218EDF1A7005DB364 /* xplaneConnect.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = xplaneConnect.c; path = ../C/src/xplaneConnect.c; sourceTree = "<group>"; }; BEDC620218EDF1A7005DB364 /* xplaneConnect.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = xplaneConnect.c; path = ../C/src/xplaneConnect.c; sourceTree = "<group>"; };
BEDC620318EDF1A7005DB364 /* xplaneConnect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = xplaneConnect.h; path = ../C/src/xplaneConnect.h; sourceTree = "<group>"; };
D607B19909A556E400699BC3 /* mac.xpl */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = mac.xpl; sourceTree = BUILT_PRODUCTS_DIR; }; D607B19909A556E400699BC3 /* mac.xpl */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = mac.xpl; sourceTree = BUILT_PRODUCTS_DIR; };
D6A7BDA916A1DEA200D1426A /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; D6A7BDA916A1DEA200D1426A /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; };
D6A7BDC016A1DEC000D1426A /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; D6A7BDC016A1DEC000D1426A /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; };
@@ -79,6 +80,7 @@
AC4E46B809C2E0B3006B7E1B /* src */ = { AC4E46B809C2E0B3006B7E1B /* src */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
5B36040C23731E4A003ACE12 /* CameraCallbacks.cpp */,
3D0F44CD21C6D3E7008A0655 /* Timer.cpp */, 3D0F44CD21C6D3E7008A0655 /* Timer.cpp */,
BE37D95E187C8B0F0033B082 /* XPCPlugin.cpp */, BE37D95E187C8B0F0033B082 /* XPCPlugin.cpp */,
BEDC620218EDF1A7005DB364 /* xplaneConnect.c */, BEDC620218EDF1A7005DB364 /* xplaneConnect.c */,
@@ -96,7 +98,6 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
3D0F44CC21C6D3E7008A0655 /* Timer.h */, 3D0F44CC21C6D3E7008A0655 /* Timer.h */,
BEDC620318EDF1A7005DB364 /* xplaneConnect.h */,
BEABAD2C1AE041A3007BA7DA /* DataManager.h */, BEABAD2C1AE041A3007BA7DA /* DataManager.h */,
BEABAD301AE041A3007BA7DA /* Drawing.h */, BEABAD301AE041A3007BA7DA /* Drawing.h */,
BEABAD321AE041A3007BA7DA /* Log.h */, BEABAD321AE041A3007BA7DA /* Log.h */,
@@ -191,6 +192,7 @@
files = ( files = (
BEABAD3A1AE041A3007BA7DA /* Log.cpp in Sources */, BEABAD3A1AE041A3007BA7DA /* Log.cpp in Sources */,
BEABAD3B1AE041A3007BA7DA /* Message.cpp in Sources */, BEABAD3B1AE041A3007BA7DA /* Message.cpp in Sources */,
5B36040D23731E4A003ACE12 /* CameraCallbacks.cpp in Sources */,
BEABAD3C1AE041A3007BA7DA /* MessageHandlers.cpp in Sources */, BEABAD3C1AE041A3007BA7DA /* MessageHandlers.cpp in Sources */,
BEDC620418EDF1A7005DB364 /* xplaneConnect.c in Sources */, BEDC620418EDF1A7005DB364 /* xplaneConnect.c in Sources */,
BEABAD371AE041A3007BA7DA /* DataManager.cpp in Sources */, BEABAD371AE041A3007BA7DA /* DataManager.cpp in Sources */,
@@ -219,6 +221,7 @@
"APL=1", "APL=1",
"IBM=0", "IBM=0",
"LIN=0", "LIN=0",
XPLM200,
); );
GCC_SYMBOLS_PRIVATE_EXTERN = YES; GCC_SYMBOLS_PRIVATE_EXTERN = YES;
GCC_VERSION = ""; GCC_VERSION = "";
@@ -230,6 +233,10 @@
MACH_O_TYPE = mh_bundle; MACH_O_TYPE = mh_bundle;
MACOSX_DEPLOYMENT_TARGET = 10.7; MACOSX_DEPLOYMENT_TARGET = 10.7;
ONLY_ACTIVE_ARCH = YES; ONLY_ACTIVE_ARCH = YES;
OTHER_CPLUSPLUSFLAGS = (
"$(OTHER_CFLAGS)",
"-DXPLM200",
);
OTHER_LDFLAGS = ( OTHER_LDFLAGS = (
"$(OTHER_LDFLAGS)", "$(OTHER_LDFLAGS)",
"-Wl,-exported_symbol", "-Wl,-exported_symbol",
@@ -268,6 +275,7 @@
"APL=1", "APL=1",
"IBM=0", "IBM=0",
"LIN=0", "LIN=0",
XPLM200,
); );
GCC_SYMBOLS_PRIVATE_EXTERN = YES; GCC_SYMBOLS_PRIVATE_EXTERN = YES;
GCC_VERSION = ""; GCC_VERSION = "";
@@ -278,6 +286,10 @@
); );
MACH_O_TYPE = mh_bundle; MACH_O_TYPE = mh_bundle;
MACOSX_DEPLOYMENT_TARGET = 10.7; MACOSX_DEPLOYMENT_TARGET = 10.7;
OTHER_CPLUSPLUSFLAGS = (
"$(OTHER_CFLAGS)",
"-DXPLM200",
);
OTHER_LDFLAGS = ( OTHER_LDFLAGS = (
"$(OTHER_LDFLAGS)", "$(OTHER_LDFLAGS)",
"-Wl,-exported_symbol", "-Wl,-exported_symbol",

View File

@@ -1,231 +1,232 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations"> <ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32"> <ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration> <Configuration>Debug</Configuration>
<Platform>Win32</Platform> <Platform>Win32</Platform>
</ProjectConfiguration> </ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64"> <ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration> <Configuration>Debug</Configuration>
<Platform>x64</Platform> <Platform>x64</Platform>
</ProjectConfiguration> </ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32"> <ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration> <Configuration>Release</Configuration>
<Platform>Win32</Platform> <Platform>Win32</Platform>
</ProjectConfiguration> </ProjectConfiguration>
<ProjectConfiguration Include="Release|x64"> <ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration> <Configuration>Release</Configuration>
<Platform>x64</Platform> <Platform>x64</Platform>
</ProjectConfiguration> </ProjectConfiguration>
</ItemGroup> </ItemGroup>
<PropertyGroup Label="Globals"> <PropertyGroup Label="Globals">
<ProjectGuid>{6AEF5D28-2701-44FF-AE10-1DEF07C5CAEA}</ProjectGuid> <ProjectGuid>{6AEF5D28-2701-44FF-AE10-1DEF07C5CAEA}</ProjectGuid>
<Keyword>Win32Proj</Keyword> <Keyword>Win32Proj</Keyword>
<RootNamespace>xpcPlugin</RootNamespace> <RootNamespace>xpcPlugin</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> <WindowsTargetPlatformVersion>10.0.17134.0</WindowsTargetPlatformVersion>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType> <ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet> <CharacterSet>MultiByte</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType> <ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet> <CharacterSet>MultiByte</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType> <ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet> <CharacterSet>MultiByte</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType> <ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset> <PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet> <CharacterSet>MultiByte</CharacterSet>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings"> <ImportGroup Label="ExtensionSettings">
</ImportGroup> </ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup> </ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets"> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup> </ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets"> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup> </ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets"> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup> </ImportGroup>
<PropertyGroup Label="UserMacros" /> <PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental> <LinkIncremental>true</LinkIncremental>
<OutDir>..\XPlaneConnect\</OutDir> <OutDir>..\XPlaneConnect\</OutDir>
<TargetExt>.xpl</TargetExt> <TargetExt>.xpl</TargetExt>
<IncludePath>..\SDK\CHeaders\XPLM;$(IncludePath)</IncludePath> <IncludePath>..\SDK\CHeaders\XPLM;$(IncludePath)</IncludePath>
<LibraryPath>..\xpcPlugin\SDK\Libraries\Win;$(LibraryPath)</LibraryPath> <LibraryPath>..\xpcPlugin\SDK\Libraries\Win;$(LibraryPath)</LibraryPath>
<TargetName>win</TargetName> <TargetName>win</TargetName>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>true</LinkIncremental> <LinkIncremental>true</LinkIncremental>
<OutDir>..\XPlaneConnect\</OutDir> <OutDir>..\XPlaneConnect\</OutDir>
<TargetExt>.xpl</TargetExt> <TargetExt>.xpl</TargetExt>
<IncludePath>..\SDK\CHeaders\XPLM;$(IncludePath)</IncludePath> <IncludePath>..\SDK\CHeaders\XPLM;$(IncludePath)</IncludePath>
<LibraryPath>..\xpcPlugin\SDK\Libraries\Win;$(LibraryPath)</LibraryPath> <LibraryPath>..\xpcPlugin\SDK\Libraries\Win;$(LibraryPath)</LibraryPath>
<TargetName>win</TargetName> <TargetName>win</TargetName>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<TargetExt>.xpl</TargetExt> <TargetExt>.xpl</TargetExt>
<IncludePath>..\xpcPlugin\SDK\CHeaders\XPLM;..\SDK\CHeaders\XPLM;..\..\C\src;$(IncludePath)</IncludePath> <IncludePath>..\xpcPlugin\SDK\CHeaders\XPLM;..\SDK\CHeaders\XPLM;..\..\C\src;$(IncludePath)</IncludePath>
<LibraryPath>..\xpcPlugin\SDK\Libraries\Win;$(LibraryPath)</LibraryPath> <LibraryPath>..\xpcPlugin\SDK\Libraries\Win;$(LibraryPath)</LibraryPath>
<TargetName>win</TargetName> <TargetName>win</TargetName>
<LinkIncremental>true</LinkIncremental> <LinkIncremental>true</LinkIncremental>
<OutDir>..\XPlaneConnect\64\</OutDir> <OutDir>..\XPlaneConnect\64\</OutDir>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<TargetExt>.xpl</TargetExt> <TargetExt>.xpl</TargetExt>
<IncludePath>..\xpcPlugin\SDK\CHeaders\XPLM;..\SDK\CHeaders\XPLM;..\..\C\src;$(IncludePath)</IncludePath> <IncludePath>..\xpcPlugin\SDK\CHeaders\XPLM;..\SDK\CHeaders\XPLM;..\..\C\src;$(IncludePath)</IncludePath>
<LibraryPath>..\xpcPlugin\SDK\Libraries\Win;$(LibraryPath)</LibraryPath> <LibraryPath>..\xpcPlugin\SDK\Libraries\Win;$(LibraryPath)</LibraryPath>
<TargetName>win</TargetName> <TargetName>win</TargetName>
<LinkIncremental>true</LinkIncremental> <LinkIncremental>true</LinkIncremental>
<OutDir>..\XPlaneConnect\64\</OutDir> <OutDir>..\XPlaneConnect\64\</OutDir>
</PropertyGroup> </PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile> <ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader> <PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel> <WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<PreprocessorDefinitions>IBM=1;XPLM200;_DEBUG;_WINDOWS;_USRDLL;XPCPLUGIN_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>IBM=1;XPLM200;_DEBUG;_WINDOWS;_USRDLL;XPCPLUGIN_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DebugInformationFormat>OldStyle</DebugInformationFormat> <DebugInformationFormat>OldStyle</DebugInformationFormat>
<MultiProcessorCompilation>true</MultiProcessorCompilation> <MultiProcessorCompilation>true</MultiProcessorCompilation>
<OmitFramePointers /> <OmitFramePointers />
<FunctionLevelLinking>false</FunctionLevelLinking> <FunctionLevelLinking>false</FunctionLevelLinking>
<DisableSpecificWarnings> <DisableSpecificWarnings>
</DisableSpecificWarnings> </DisableSpecificWarnings>
<MinimalRebuild>false</MinimalRebuild> <MinimalRebuild>false</MinimalRebuild>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Windows</SubSystem> <SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>Opengl32.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>Opengl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile> <ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader> <PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel> <WarningLevel>Level3</WarningLevel>
<Optimization>Full</Optimization> <Optimization>Full</Optimization>
<PreprocessorDefinitions>IBM=1;XPLM200;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>IBM=1;XPLM200;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DebugInformationFormat>OldStyle</DebugInformationFormat> <DebugInformationFormat>OldStyle</DebugInformationFormat>
<MultiProcessorCompilation>true</MultiProcessorCompilation> <MultiProcessorCompilation>true</MultiProcessorCompilation>
<OmitFramePointers> <OmitFramePointers>
</OmitFramePointers> </OmitFramePointers>
<FunctionLevelLinking>false</FunctionLevelLinking> <FunctionLevelLinking>false</FunctionLevelLinking>
<DisableSpecificWarnings> <DisableSpecificWarnings>
</DisableSpecificWarnings> </DisableSpecificWarnings>
<MinimalRebuild>false</MinimalRebuild> <MinimalRebuild>false</MinimalRebuild>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary> <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BasicRuntimeChecks>Default</BasicRuntimeChecks> <BasicRuntimeChecks>Default</BasicRuntimeChecks>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<ExceptionHandling>false</ExceptionHandling> <ExceptionHandling>false</ExceptionHandling>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Windows</SubSystem> <SubSystem>Windows</SubSystem>
<GenerateDebugInformation>false</GenerateDebugInformation> <GenerateDebugInformation>false</GenerateDebugInformation>
<AdditionalDependencies>Opengl32.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>Opengl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration> <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile> <ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader> <PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel> <WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<PreprocessorDefinitions>IBM=1;XPLM200;_DEBUG;_WINDOWS;_USRDLL;XPCPLUGIN_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>IBM=1;XPLM200;_DEBUG;_WINDOWS;_USRDLL;XPCPLUGIN_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck> <SDLCheck>
</SDLCheck> </SDLCheck>
<DebugInformationFormat>OldStyle</DebugInformationFormat> <DebugInformationFormat>OldStyle</DebugInformationFormat>
<MultiProcessorCompilation>true</MultiProcessorCompilation> <MultiProcessorCompilation>true</MultiProcessorCompilation>
<OmitFramePointers> <OmitFramePointers>
</OmitFramePointers> </OmitFramePointers>
<FunctionLevelLinking>false</FunctionLevelLinking> <FunctionLevelLinking>false</FunctionLevelLinking>
<DisableSpecificWarnings>4996</DisableSpecificWarnings> <DisableSpecificWarnings>4996</DisableSpecificWarnings>
<MinimalRebuild>false</MinimalRebuild> <MinimalRebuild>false</MinimalRebuild>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Windows</SubSystem> <SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>OpenGL32.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>OpenGL32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile> <ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader> <PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel> <WarningLevel>Level3</WarningLevel>
<Optimization>Full</Optimization> <Optimization>Full</Optimization>
<PreprocessorDefinitions>IBM=1;XPLM200;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>IBM=1;XPLM200;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck> <SDLCheck>
</SDLCheck> </SDLCheck>
<DebugInformationFormat>OldStyle</DebugInformationFormat> <DebugInformationFormat>OldStyle</DebugInformationFormat>
<MultiProcessorCompilation>true</MultiProcessorCompilation> <MultiProcessorCompilation>true</MultiProcessorCompilation>
<OmitFramePointers> <OmitFramePointers>
</OmitFramePointers> </OmitFramePointers>
<FunctionLevelLinking>false</FunctionLevelLinking> <FunctionLevelLinking>false</FunctionLevelLinking>
<DisableSpecificWarnings> <DisableSpecificWarnings>
</DisableSpecificWarnings> </DisableSpecificWarnings>
<MinimalRebuild>false</MinimalRebuild> <MinimalRebuild>false</MinimalRebuild>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary> <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BasicRuntimeChecks>Default</BasicRuntimeChecks> <BasicRuntimeChecks>Default</BasicRuntimeChecks>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<InlineFunctionExpansion /> <InlineFunctionExpansion />
<ExceptionHandling>false</ExceptionHandling> <ExceptionHandling>false</ExceptionHandling>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Windows</SubSystem> <SubSystem>Windows</SubSystem>
<GenerateDebugInformation>false</GenerateDebugInformation> <GenerateDebugInformation>false</GenerateDebugInformation>
<AdditionalDependencies>OpenGL32.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>OpenGL32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration> <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
<GenerateMapFile> <GenerateMapFile>
</GenerateMapFile> </GenerateMapFile>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\DataManager.h" /> <ClInclude Include="..\DataManager.h" />
<ClInclude Include="..\Drawing.h" /> <ClInclude Include="..\Drawing.h" />
<ClInclude Include="..\Log.h" /> <ClInclude Include="..\Log.h" />
<ClInclude Include="..\Message.h" /> <ClInclude Include="..\Message.h" />
<ClInclude Include="..\MessageHandlers.h" /> <ClInclude Include="..\MessageHandlers.h" />
<ClInclude Include="..\Timer.h" /> <ClInclude Include="..\Timer.h" />
<ClInclude Include="..\UDPSocket.h" /> <ClInclude Include="..\UDPSocket.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="..\DataManager.cpp" /> <ClCompile Include="..\CameraCallbacks.cpp" />
<ClCompile Include="..\Drawing.cpp" /> <ClCompile Include="..\DataManager.cpp" />
<ClCompile Include="..\Log.cpp" /> <ClCompile Include="..\Drawing.cpp" />
<ClCompile Include="..\Message.cpp" /> <ClCompile Include="..\Log.cpp" />
<ClCompile Include="..\MessageHandlers.cpp" /> <ClCompile Include="..\Message.cpp" />
<ClCompile Include="..\Timer.cpp" /> <ClCompile Include="..\MessageHandlers.cpp" />
<ClCompile Include="..\UDPSocket.cpp" /> <ClCompile Include="..\Timer.cpp" />
<ClCompile Include="..\XPCPlugin.cpp" /> <ClCompile Include="..\UDPSocket.cpp" />
</ItemGroup> <ClCompile Include="..\XPCPlugin.cpp" />
<ItemGroup> </ItemGroup>
<Library Include="..\SDK\Libraries\Win\XPLM.lib" /> <ItemGroup>
<Library Include="..\SDK\Libraries\Win\XPLM_64.lib" /> <Library Include="..\SDK\Libraries\Win\XPLM.lib" />
<Library Include="..\SDK\Libraries\Win\XPWidgets.lib" /> <Library Include="..\SDK\Libraries\Win\XPLM_64.lib" />
<Library Include="..\SDK\Libraries\Win\XPWidgets_64.lib" /> <Library Include="..\SDK\Libraries\Win\XPWidgets.lib" />
</ItemGroup> <Library Include="..\SDK\Libraries\Win\XPWidgets_64.lib" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> </ItemGroup>
<ImportGroup Label="ExtensionTargets"> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</ImportGroup> <ImportGroup Label="ExtensionTargets">
</Project> </ImportGroup>
</Project>

View File

@@ -1,74 +1,83 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup> <ItemGroup>
<Filter Include="Source Files"> <Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter> </Filter>
<Filter Include="Header Files"> <Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions> <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter> </Filter>
<Filter Include="Resource Files"> <Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter> </Filter>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\Log.h"> <ClInclude Include="..\Log.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\Drawing.h"> <ClInclude Include="..\Drawing.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\UDPSocket.h"> <ClInclude Include="..\UDPSocket.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\Message.h"> <ClInclude Include="..\Message.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\DataManager.h"> <ClInclude Include="..\DataManager.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\MessageHandlers.h"> <ClInclude Include="..\MessageHandlers.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
</ItemGroup> <ClInclude Include="..\Timer.h">
<ItemGroup> <Filter>Header Files</Filter>
<ClCompile Include="..\XPCPlugin.cpp"> </ClInclude>
<Filter>Source Files</Filter> </ItemGroup>
</ClCompile> <ItemGroup>
<ClCompile Include="..\Log.cpp"> <ClCompile Include="..\XPCPlugin.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\Drawing.cpp"> <ClCompile Include="..\Log.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\UDPSocket.cpp"> <ClCompile Include="..\Drawing.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\Message.cpp"> <ClCompile Include="..\UDPSocket.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\DataManager.cpp"> <ClCompile Include="..\Message.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\MessageHandlers.cpp"> <ClCompile Include="..\DataManager.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
</ItemGroup> <ClCompile Include="..\MessageHandlers.cpp">
<ItemGroup> <Filter>Source Files</Filter>
<Library Include="..\SDK\Libraries\Win\XPLM.lib"> </ClCompile>
<Filter>Resource Files</Filter> <ClCompile Include="..\Timer.cpp">
</Library> <Filter>Source Files</Filter>
<Library Include="..\SDK\Libraries\Win\XPLM_64.lib"> </ClCompile>
<Filter>Resource Files</Filter> <ClCompile Include="..\CameraCallbacks.cpp">
</Library> <Filter>Source Files</Filter>
<Library Include="..\SDK\Libraries\Win\XPWidgets.lib"> </ClCompile>
<Filter>Resource Files</Filter> </ItemGroup>
</Library> <ItemGroup>
<Library Include="..\SDK\Libraries\Win\XPWidgets_64.lib"> <Library Include="..\SDK\Libraries\Win\XPLM.lib">
<Filter>Resource Files</Filter> <Filter>Resource Files</Filter>
</Library> </Library>
</ItemGroup> <Library Include="..\SDK\Libraries\Win\XPLM_64.lib">
<Filter>Resource Files</Filter>
</Library>
<Library Include="..\SDK\Libraries\Win\XPWidgets.lib">
<Filter>Resource Files</Filter>
</Library>
<Library Include="..\SDK\Libraries\Win\XPWidgets_64.lib">
<Filter>Resource Files</Filter>
</Library>
</ItemGroup>
</Project> </Project>