1
.gitignore
vendored
1
.gitignore
vendored
@@ -93,3 +93,4 @@ out/
|
|||||||
# Internal Docs #
|
# Internal Docs #
|
||||||
#################
|
#################
|
||||||
Docs/~$Capability Matrix.xlsx
|
Docs/~$Capability Matrix.xlsx
|
||||||
|
*.xpl
|
||||||
|
|||||||
@@ -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
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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 ****/
|
||||||
|
/*****************************************************************************/
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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"
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
434
TestScripts/Python3 Tests/Tests.py
Normal file
434
TestScripts/Python3 Tests/Tests.py
Normal 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()
|
||||||
45
TestScripts/Python3 Tests/Tests.pyproj
Normal file
45
TestScripts/Python3 Tests/Tests.pyproj
Normal 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>
|
||||||
@@ -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
|
||||||
|
|||||||
173
xpcPlugin/CameraCallbacks.cpp
Normal file
173
xpcPlugin/CameraCallbacks.cpp
Normal 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;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -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 ";
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -42,6 +42,9 @@ namespace XPC
|
|||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
Log::WriteLine(LOG_TRACE, "MSGH", "Setting socket");
|
Log::WriteLine(LOG_TRACE, "MSGH", "Setting 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));
|
||||||
@@ -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
|
||||||
@@ -723,106 +861,86 @@ namespace XPC
|
|||||||
// 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);
|
memcpy(&campos, buffer+9 , sizeof(struct CameraProperties));
|
||||||
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);
|
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, CamFunc, &campos);
|
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;
|
||||||
|
while (pos < size)
|
||||||
|
{
|
||||||
|
unsigned char len = buffer[pos++];
|
||||||
|
if (pos + len > size)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
std::string comm = std::string((char*)buffer + pos, len);
|
||||||
|
pos += len;
|
||||||
|
|
||||||
// camera position
|
DataManager::Execute(comm);
|
||||||
double clat = campos->loc[0];
|
Log::FormatLine(LOG_DEBUG, "COMM", "Execute command %s", comm.c_str());
|
||||||
double clon = campos->loc[1];
|
}
|
||||||
double calt = campos->loc[2];
|
if (pos != size)
|
||||||
|
{
|
||||||
double cX, cY, cZ;
|
Log::WriteLine(LOG_ERROR, "COMM", "ERROR: Command did not terminate at the expected position.");
|
||||||
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);
|
|
||||||
|
|
||||||
if(campos->direction[0] == -998) // calculate camera direction
|
|
||||||
{
|
|
||||||
// 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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -15,6 +15,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.
|
||||||
///
|
///
|
||||||
/// \author Jason Watkins
|
/// \author Jason Watkins
|
||||||
@@ -41,6 +58,8 @@ namespace XPC
|
|||||||
|
|
||||||
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
|
||||||
// wiki at https://github.com/nasa/XPlaneConnect/wiki/Network-Information
|
// wiki at https://github.com/nasa/XPlaneConnect/wiki/Network-Information
|
||||||
@@ -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];
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
<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">
|
||||||
@@ -210,6 +210,7 @@
|
|||||||
<ClInclude Include="..\UDPSocket.h" />
|
<ClInclude Include="..\UDPSocket.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClCompile Include="..\CameraCallbacks.cpp" />
|
||||||
<ClCompile Include="..\DataManager.cpp" />
|
<ClCompile Include="..\DataManager.cpp" />
|
||||||
<ClCompile Include="..\Drawing.cpp" />
|
<ClCompile Include="..\Drawing.cpp" />
|
||||||
<ClCompile Include="..\Log.cpp" />
|
<ClCompile Include="..\Log.cpp" />
|
||||||
|
|||||||
@@ -33,6 +33,9 @@
|
|||||||
<ClInclude Include="..\MessageHandlers.h">
|
<ClInclude Include="..\MessageHandlers.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\Timer.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="..\XPCPlugin.cpp">
|
<ClCompile Include="..\XPCPlugin.cpp">
|
||||||
@@ -56,6 +59,12 @@
|
|||||||
<ClCompile Include="..\MessageHandlers.cpp">
|
<ClCompile Include="..\MessageHandlers.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\Timer.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\CameraCallbacks.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Library Include="..\SDK\Libraries\Win\XPLM.lib">
|
<Library Include="..\SDK\Libraries\Win\XPLM.lib">
|
||||||
|
|||||||
Reference in New Issue
Block a user