1
.gitignore
vendored
1
.gitignore
vendored
@@ -6,6 +6,7 @@
|
||||
*.exe
|
||||
*.o
|
||||
*.so
|
||||
*.pyc
|
||||
|
||||
# Logs and databases #
|
||||
######################
|
||||
|
||||
@@ -52,7 +52,6 @@ int sendUDP(XPCSocket sock, char buffer[], int len);
|
||||
int readUDP(XPCSocket sock, char buffer[], int len);
|
||||
int sendDREFRequest(XPCSocket sock, const char* drefs[], unsigned char count);
|
||||
int getDREFResponse(XPCSocket sock, float* values[], unsigned char count, int sizes[]);
|
||||
|
||||
void printError(char *functionName, char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
@@ -266,9 +265,17 @@ int setCONN(XPCSocket* sock, unsigned short port)
|
||||
|
||||
int pauseSim(XPCSocket sock, char pause)
|
||||
{
|
||||
// Validte input
|
||||
if (pause < 0 || pause > 2)
|
||||
{
|
||||
printError("pauseSim", "Invalid argument: %i", pause);
|
||||
return -2;
|
||||
}
|
||||
|
||||
// Setup command
|
||||
char buffer[6] = "SIMU";
|
||||
buffer[5] = pause == 0 ? 0 : 1;
|
||||
buffer[5] = pause;
|
||||
|
||||
// Send command
|
||||
if (sendUDP(sock, buffer, 6) < 0)
|
||||
{
|
||||
@@ -360,32 +367,46 @@ int readDATA(XPCSocket sock, float data[][9], int rows)
|
||||
/*****************************************************************************/
|
||||
int sendDREF(XPCSocket sock, const char* dref, float value[], int size)
|
||||
{
|
||||
// Setup command
|
||||
// 5 byte header + max 255 char dref name + max 255 values * 4 bytes per value = 1279
|
||||
unsigned char buffer[1279] = "DREF";
|
||||
int drefLen = strnlen(dref, 256);
|
||||
if (drefLen > 255)
|
||||
{
|
||||
printError("setDREF", "dref length is too long. Must be less than 256 characters.");
|
||||
return -1;
|
||||
}
|
||||
if (size > 255)
|
||||
{
|
||||
printError("setDREF", "size is too big. Must be less than 256.");
|
||||
return -2;
|
||||
}
|
||||
int len = 7 + drefLen + size * sizeof(float);
|
||||
|
||||
// Copy dref to buffer
|
||||
buffer[5] = (unsigned char)drefLen;
|
||||
memcpy(buffer + 6, dref, drefLen);
|
||||
return sendDREFs(sock, &dref, &value, &size, 1);
|
||||
}
|
||||
|
||||
// Copy values to buffer
|
||||
buffer[6 + drefLen] = (unsigned char)size;
|
||||
memcpy(buffer + 7 + drefLen, value, size * sizeof(float));
|
||||
int sendDREFs(XPCSocket sock, const char* drefs[], float* values[], int sizes[], int count)
|
||||
{
|
||||
// Setup command
|
||||
// Max size is technically unlimited.
|
||||
unsigned char buffer[65536] = "DREF";
|
||||
int pos = 5;
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
int drefLen = strnlen(drefs[i], 256);
|
||||
if (pos + drefLen + sizes[i] * 4 + 2 > 65536)
|
||||
{
|
||||
printError("sendDREF", "About to overrun the send buffer!");
|
||||
return -4;
|
||||
}
|
||||
if (drefLen > 255)
|
||||
{
|
||||
printError("sendDREF", "dref %d is too long. Must be less than 256 characters.", i);
|
||||
return -1;
|
||||
}
|
||||
if (sizes[i] > 255)
|
||||
{
|
||||
printError("sendDREF", "size %d is too big. Must be less than 256.", i);
|
||||
return -2;
|
||||
}
|
||||
// Copy dref to buffer
|
||||
buffer[pos++] = (unsigned char)drefLen;
|
||||
memcpy(buffer + pos, drefs[i], drefLen);
|
||||
pos += drefLen;
|
||||
|
||||
// Copy values to buffer
|
||||
buffer[pos++] = (unsigned char)sizes[i];
|
||||
memcpy(buffer + pos, values[i], sizes[i] * sizeof(float));
|
||||
pos += sizes[i] * sizeof(float);
|
||||
}
|
||||
|
||||
// Send command
|
||||
if (sendUDP(sock, buffer, len) < 0)
|
||||
if (sendUDP(sock, buffer, pos) < 0)
|
||||
{
|
||||
printError("setDREF", "Failed to send command");
|
||||
return -3;
|
||||
@@ -554,13 +575,13 @@ int sendCTRL(XPCSocket sock, float values[], int size, char ac)
|
||||
}
|
||||
if (size < 1 || size > 7)
|
||||
{
|
||||
printError("sendCTRL", "size should be a value between 1 and 6.");
|
||||
printError("sendCTRL", "size should be a value between 1 and 7.");
|
||||
return -2;
|
||||
}
|
||||
|
||||
// Setup Command
|
||||
// 5 byte header + 5 float values * 4 + 2 byte values
|
||||
unsigned char buffer[27] = "CTRL";
|
||||
unsigned char buffer[31] = "CTRL";
|
||||
int cur = 5;
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
@@ -581,9 +602,10 @@ int sendCTRL(XPCSocket sock, float values[], int size, char ac)
|
||||
}
|
||||
}
|
||||
buffer[26] = ac;
|
||||
*((float*)(buffer + 27)) = size == 7 ? values[6]: -998;
|
||||
|
||||
// Send Command
|
||||
if (sendUDP(sock, buffer, 27) < 0)
|
||||
if (sendUDP(sock, buffer, 31) < 0)
|
||||
{
|
||||
printError("sendCTRL", "Failed to send command");
|
||||
return -3;
|
||||
@@ -663,7 +685,7 @@ int sendWYPT(XPCSocket sock, WYPT_OP op, float points[], int count)
|
||||
memcpy(buffer + 7, points, ptLen);
|
||||
|
||||
// Send Command
|
||||
if (sendUDP(sock, buffer, 40) < 0)
|
||||
if (sendUDP(sock, buffer, 7 + 12 * count) < 0)
|
||||
{
|
||||
printError("sendWYPT", "Failed to send command");
|
||||
return -2;
|
||||
@@ -673,3 +695,31 @@ int sendWYPT(XPCSocket sock, WYPT_OP op, float points[], int count)
|
||||
/*****************************************************************************/
|
||||
/**** End Drawing functions ****/
|
||||
/*****************************************************************************/
|
||||
|
||||
/*****************************************************************************/
|
||||
/**** View functions ****/
|
||||
/*****************************************************************************/
|
||||
int sendVIEW(XPCSocket sock, VIEW_TYPE view)
|
||||
{
|
||||
// Validate Input
|
||||
if (view < XPC_VIEW_FORWARDS || view > XPC_VIEW_FULLSCREENNOHUD)
|
||||
{
|
||||
printError("sendVIEW", "Unrecognized view");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Setup Command
|
||||
char buffer[9] = "VIEW";
|
||||
*((int*)(buffer + 5)) = view;
|
||||
|
||||
// Send Command
|
||||
if (sendUDP(sock, buffer, 9) < 0)
|
||||
{
|
||||
printError("sendVIEW", "Failed to send command");
|
||||
return -2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*****************************************************************************/
|
||||
/**** End View functions ****/
|
||||
/*****************************************************************************/
|
||||
@@ -61,6 +61,23 @@ typedef enum
|
||||
XPC_WYPT_DEL = 2,
|
||||
XPC_WYPT_CLR = 3
|
||||
} WYPT_OP;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
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,
|
||||
} VIEW_TYPE;
|
||||
|
||||
// Low Level UDP Functions
|
||||
|
||||
@@ -127,13 +144,27 @@ int sendDATA(XPCSocket sock, float data[][9], int rows);
|
||||
/// 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 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 dref The name of the dataref to set.
|
||||
/// \param values An array of values representing the data to set.
|
||||
/// \param size The number of elements in values.
|
||||
/// \returns 0 if successful, otherwise a negative value.
|
||||
/// \param sock The socket to use to send the command.
|
||||
/// \param dref The name of the dataref to set.
|
||||
/// \param value An array of values representing the data to set.
|
||||
/// \param size The number of elements in values.
|
||||
/// \returns 0 if successful, otherwise a negative value.
|
||||
int sendDREF(XPCSocket sock, const char* dref, float value[], int size);
|
||||
|
||||
/// Sets the specified datarefs to the specified values.
|
||||
///
|
||||
/// \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
|
||||
/// 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.
|
||||
/// \param sock The socket to use to send the command.
|
||||
/// \param drefs The names of the datarefs to set.
|
||||
/// \param values A multidimensional array containing the values for each dataref to set.
|
||||
/// \param sizes The number of elements in each array in values
|
||||
/// \param count The number of datarefs being set.
|
||||
/// \returns 0 if successful, otherwise a negative value.
|
||||
int sendDREFs(XPCSocket sock, const char* drefs[], float* values[], int sizes[], int count);
|
||||
|
||||
/// Gets the value of the specified dataref.
|
||||
///
|
||||
/// \details dref names and their associated data types can be found on the XPSDK wiki at
|
||||
@@ -182,8 +213,8 @@ int sendPOSI(XPCSocket sock, float values[], int size, char ac);
|
||||
///
|
||||
/// \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
|
||||
/// [Elevator, Aileron, Rudder, Throttle, Gear, Flaps]. If less than 6 values are
|
||||
/// specified, the unspecified values will be left unchanged.
|
||||
/// [Elevator, Aileron, Rudder, Throttle, Gear, Flaps, Speed Brakes]. If less than
|
||||
/// 6 values are specified, the unspecified values will be left unchanged.
|
||||
/// \param size The number of elements in values.
|
||||
/// \param ac The aircraft number to set the control surfaces of. 0 for the player aircraft.
|
||||
/// \returns 0 if successful, otherwise a negative value.
|
||||
@@ -200,6 +231,13 @@ int sendCTRL(XPCSocket sock, float values[], int size, char ac);
|
||||
/// \returns 0 if successful, otherwise a negative value.
|
||||
int sendTEXT(XPCSocket sock, char* msg, int x, int y);
|
||||
|
||||
/// Sets the camera view in X-Plane.
|
||||
///
|
||||
/// \param sock The socket to use to send the command.
|
||||
/// \param view The view to use.
|
||||
/// \returns 0 if successful, otherwise a negative value.
|
||||
int sendVIEW(XPCSocket sock, VIEW_TYPE view);
|
||||
|
||||
/// Adds, removes, or clears a set of waypoints. If the command is clear, the points are ignored
|
||||
/// and all points are removed.
|
||||
///
|
||||
|
||||
@@ -23,6 +23,13 @@ int main()
|
||||
// Open Socket
|
||||
const char* IP = "127.0.0.1"; //IP Address of computer running X-Plane
|
||||
XPCSocket sock = openUDP(IP);
|
||||
float tVal[1];
|
||||
int tSize;
|
||||
if (getDREF(sock, "sim/test/test_float", tVal, &tSize) < 0)
|
||||
{
|
||||
printf("Error establishing connecting. Unable to read data from X-Plane.");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Set Location/Orientation (sendPOSI)
|
||||
// Set Up Position Array
|
||||
|
||||
Binary file not shown.
Binary file not shown.
BIN
Docs/PBS.pdf
BIN
Docs/PBS.pdf
Binary file not shown.
@@ -21,8 +21,8 @@ public class Main
|
||||
System.out.println("Setting up simulation...");
|
||||
try(XPlaneConnect xpc = new XPlaneConnect())
|
||||
{
|
||||
System.out.println("Setting inbound port");
|
||||
xpc.setCONN(49055);
|
||||
// Ensure connection established.
|
||||
xpc.getDREF("sim/test/test_float");
|
||||
|
||||
System.out.println("Setting player aircraft position");
|
||||
float[] posi = new float[] {37.524F, -122.06899F, 2500, 0, 0, 0, 1};
|
||||
|
||||
60
Java/src/ViewType.java
Normal file
60
Java/src/ViewType.java
Normal file
@@ -0,0 +1,60 @@
|
||||
//NOTICES:
|
||||
// Copyright <20> 2013-2015 United States Government as represented by the Administrator of the
|
||||
// National Aeronautics and Space Administration. All Rights Reserved.
|
||||
//
|
||||
// DISCLAIMERS
|
||||
// No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY KIND,
|
||||
// EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY THAT THE
|
||||
// SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT
|
||||
// SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO
|
||||
// THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN ENDORSEMENT BY
|
||||
// GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, RESULTING DESIGNS, HARDWARE,
|
||||
// SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS RESULTING FROM USE OF THE SUBJECT SOFTWARE.
|
||||
// FURTHER, GOVERNMENT AGENCY DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING THIRD-PARTY
|
||||
// SOFTWARE, IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS."
|
||||
//
|
||||
// Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST THE UNITED STATES
|
||||
// GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY PRIOR RECIPIENT. IF
|
||||
// RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS IN ANY LIABILITIES, DEMANDS, DAMAGES,
|
||||
// EXPENSES OR LOSSES ARISING FROM SUCH USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR
|
||||
// RESULTING FROM, RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD
|
||||
// HARMLESS THE UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY
|
||||
// PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY LAW. RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER
|
||||
// SHALL BE THE IMMEDIATE, UNILATERAL TERMINATION OF THIS AGREEMENT.
|
||||
package gov.nasa.xpc;
|
||||
|
||||
/**
|
||||
* Represents a camera view in X-Plane
|
||||
*
|
||||
* @author Jason Watkins
|
||||
* @version 1.1
|
||||
* @since 2015-05-08
|
||||
*/
|
||||
public enum ViewType
|
||||
{
|
||||
Forwards(73),
|
||||
Down(74),
|
||||
Left(75),
|
||||
Right(76),
|
||||
Back(77),
|
||||
Tower(78),
|
||||
Runway(79),
|
||||
Chase(80),
|
||||
Follow(81),
|
||||
FollowWithPanel(82),
|
||||
Spot(83),
|
||||
FullscreenWithHud(84),
|
||||
FullscreenNoHud(85);
|
||||
|
||||
private final int value;
|
||||
private ViewType(int value)
|
||||
{
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int getValue()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -175,7 +175,7 @@ public class XPlaneConnect implements AutoCloseable
|
||||
*/
|
||||
private byte[] readUDP() throws IOException
|
||||
{
|
||||
byte[] buffer = new byte[2048];
|
||||
byte[] buffer = new byte[65536];
|
||||
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
|
||||
try
|
||||
{
|
||||
@@ -214,6 +214,26 @@ public class XPlaneConnect implements AutoCloseable
|
||||
sendUDP(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pauses, unpauses, or switches the pause state of X-Plane.
|
||||
*
|
||||
* @param pause {@code 1} to pause the simulator, {@code 0} to unpause, or {@code 2} to switch.
|
||||
* @throws IllegalArgumentException If the values of {@code pause} is not a valid command.
|
||||
* @throws IOException If the command cannot be sent.
|
||||
*/
|
||||
public void pauseSim(int pause) throws IOException
|
||||
{
|
||||
if(pause < 0 || pause > 2)
|
||||
{
|
||||
throw new IllegalArgumentException("pause must be a value in the range [0, 2].");
|
||||
}
|
||||
|
||||
// S I M U LEN VAL
|
||||
byte[] msg = {0x53, 0x49, 0x4D, 0x55, 0x00, 0x00};
|
||||
msg[5] = (byte)pause;
|
||||
sendUDP(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests a single dref value from X-Plane.
|
||||
*
|
||||
@@ -273,37 +293,29 @@ public class XPlaneConnect implements AutoCloseable
|
||||
sendUDP(os.toByteArray());
|
||||
|
||||
//Read response
|
||||
for(int i = 0; i < 40; ++i)
|
||||
byte[] data = readUDP();
|
||||
if(data.length == 0)
|
||||
{
|
||||
byte[] data = readUDP();
|
||||
if(data.length == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if(data.length < 6)
|
||||
{
|
||||
throw new Error("Response too short"); //TODO: Make custom error type
|
||||
}
|
||||
if(data[5] != drefs.length)
|
||||
{
|
||||
throw new Error("Unexpected response length"); //TODO: Make custom error type
|
||||
}
|
||||
float[][] result = new float[drefs.length][];
|
||||
ByteBuffer bb = ByteBuffer.wrap(data);
|
||||
bb.order(ByteOrder.LITTLE_ENDIAN);
|
||||
int cur = 6;
|
||||
for(int j = 0; j < result.length; ++j)
|
||||
{
|
||||
result[j] = new float[data[cur++]];
|
||||
for(int k = 0; k < result[j].length; ++k) //TODO: There must be a better way to do this
|
||||
{
|
||||
result[j][k] = bb.getFloat(cur);
|
||||
cur += 4;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
throw new IOException("No response received.");
|
||||
}
|
||||
throw new IOException("No response received.");
|
||||
if(data.length < 6)
|
||||
{
|
||||
throw new IOException("Response too short");
|
||||
}
|
||||
float[][] result = new float[drefs.length][];
|
||||
ByteBuffer bb = ByteBuffer.wrap(data);
|
||||
bb.order(ByteOrder.LITTLE_ENDIAN);
|
||||
int cur = 6;
|
||||
for(int j = 0; j < result.length; ++j)
|
||||
{
|
||||
result[j] = new float[data[cur++]];
|
||||
for(int k = 0; k < result[j].length; ++k) //TODO: There must be a better way to do this
|
||||
{
|
||||
result[j][k] = bb.getFloat(cur);
|
||||
cur += 4;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void sendDREF(String dref, float value) throws IOException
|
||||
@@ -319,43 +331,70 @@ public class XPlaneConnect implements AutoCloseable
|
||||
* @throws IOException If the command cannot be sent.
|
||||
*/
|
||||
public void sendDREF(String dref, float[] value) throws IOException
|
||||
{
|
||||
sendDREFs(new String[] {dref}, new float[][] {value});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a command to X-Plane that sets the given DREF.
|
||||
*
|
||||
* @param drefs The names of the X-Plane datarefs to set.
|
||||
* @param values A sequence of arrays of floating point values whose structure depends on the drefs specified.
|
||||
* @throws IOException If the command cannot be sent.
|
||||
*/
|
||||
public void sendDREFs(String[] drefs, float[][] values) throws IOException
|
||||
{
|
||||
//Preconditions
|
||||
if(dref == null)
|
||||
if(drefs == null || drefs.length == 0)
|
||||
{
|
||||
throw new IllegalArgumentException("dref must be a valid string.");
|
||||
throw new IllegalArgumentException(("drefs must be non-empty."));
|
||||
}
|
||||
if(value == null || value.length == 0)
|
||||
if(values == null || values.length != drefs.length)
|
||||
{
|
||||
throw new IllegalArgumentException("value must be non-null and should contain at least one value.");
|
||||
throw new IllegalArgumentException("values must be of the same size as drefs.");
|
||||
}
|
||||
|
||||
//Convert drefs to bytes.
|
||||
byte[] drefBytes = dref.getBytes(StandardCharsets.UTF_8);
|
||||
if(drefBytes.length == 0)
|
||||
{
|
||||
throw new IllegalArgumentException("DREF is an empty string!");
|
||||
}
|
||||
if(drefBytes.length > 255)
|
||||
{
|
||||
throw new IllegalArgumentException("dref must be less than 255 bytes in UTF-8. Are you sure this is a valid dref?");
|
||||
}
|
||||
|
||||
ByteBuffer bb = ByteBuffer.allocate(4 * value.length);
|
||||
bb.order(ByteOrder.LITTLE_ENDIAN);
|
||||
for(int i = 0; i < value.length; ++i)
|
||||
{
|
||||
bb.putFloat(i * 4, value[i]);
|
||||
}
|
||||
|
||||
//Build and send message
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
os.write("DREF".getBytes(StandardCharsets.UTF_8));
|
||||
os.write(0xFF); //Placeholder for message length
|
||||
os.write(drefBytes.length);
|
||||
os.write(drefBytes, 0, drefBytes.length);
|
||||
os.write(value.length);
|
||||
os.write(bb.array());
|
||||
for(int i = 0; i < drefs.length; ++i)
|
||||
{
|
||||
String dref = drefs[i];
|
||||
float[] value = values[i];
|
||||
|
||||
if (dref == null)
|
||||
{
|
||||
throw new IllegalArgumentException("dref must be a valid string.");
|
||||
}
|
||||
if (value == null || value.length == 0)
|
||||
{
|
||||
throw new IllegalArgumentException("value must be non-null and should contain at least one value.");
|
||||
}
|
||||
|
||||
//Convert drefs to bytes.
|
||||
byte[] drefBytes = dref.getBytes(StandardCharsets.UTF_8);
|
||||
if (drefBytes.length == 0)
|
||||
{
|
||||
throw new IllegalArgumentException("DREF is an empty string!");
|
||||
}
|
||||
if (drefBytes.length > 255)
|
||||
{
|
||||
throw new IllegalArgumentException("dref must be less than 255 bytes in UTF-8. Are you sure this is a valid dref?");
|
||||
}
|
||||
|
||||
ByteBuffer bb = ByteBuffer.allocate(4 * value.length);
|
||||
bb.order(ByteOrder.LITTLE_ENDIAN);
|
||||
for (int j = 0; j < value.length; ++j)
|
||||
{
|
||||
bb.putFloat(j * 4, value[j]);
|
||||
}
|
||||
|
||||
//Build and send message
|
||||
os.write(drefBytes.length);
|
||||
os.write(drefBytes, 0, drefBytes.length);
|
||||
os.write(value.length);
|
||||
os.write(bb.array());
|
||||
}
|
||||
sendUDP(os.toByteArray());
|
||||
}
|
||||
|
||||
@@ -410,9 +449,9 @@ public class XPlaneConnect implements AutoCloseable
|
||||
{
|
||||
throw new IllegalArgumentException("ctrl must no be null.");
|
||||
}
|
||||
if(values.length > 6)
|
||||
if(values.length > 7)
|
||||
{
|
||||
throw new IllegalArgumentException("ctrl must have 6 or fewer elements.");
|
||||
throw new IllegalArgumentException("ctrl must have 7 or fewer elements.");
|
||||
}
|
||||
if(ac < 0 || ac > 9)
|
||||
{
|
||||
@@ -422,35 +461,28 @@ public class XPlaneConnect implements AutoCloseable
|
||||
//Pad command values and convert to bytes
|
||||
int i;
|
||||
int cur = 0;
|
||||
ByteBuffer bb = ByteBuffer.allocate(22);
|
||||
ByteBuffer bb = ByteBuffer.allocate(26);
|
||||
bb.order(ByteOrder.LITTLE_ENDIAN);
|
||||
for(i = 0; i < values.length; ++i)
|
||||
for(i = 0; i < 6; ++i)
|
||||
{
|
||||
if(i == 4)
|
||||
{
|
||||
bb.put(cur, (byte) values[i]);
|
||||
cur += 1;
|
||||
}
|
||||
else if (i >= values.length)
|
||||
{
|
||||
bb.putFloat(cur, -998);
|
||||
cur+= 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
bb.putFloat(cur, values[i]);
|
||||
cur += 4;
|
||||
}
|
||||
}
|
||||
for(; i < 6; ++i)
|
||||
{
|
||||
if(i == 4)
|
||||
{
|
||||
bb.put(cur, (byte) 0);
|
||||
cur += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
bb.putFloat(cur, -998);
|
||||
cur += 4;
|
||||
}
|
||||
}
|
||||
bb.put(cur, (byte) ac);
|
||||
bb.put(cur++, (byte) ac);
|
||||
bb.putFloat(cur, values.length == 7 ? values[6] : -998);
|
||||
|
||||
//Build and send message
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
@@ -688,6 +720,26 @@ public class XPlaneConnect implements AutoCloseable
|
||||
sendUDP(os.toByteArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the camera view in X-Plane.
|
||||
*
|
||||
* @param view The view to use.
|
||||
* @throws IOException If the command cannot be sent.
|
||||
*/
|
||||
public void sendVIEW(ViewType view) throws IOException
|
||||
{
|
||||
ByteBuffer bb = ByteBuffer.allocate(4);
|
||||
bb.order(ByteOrder.LITTLE_ENDIAN);
|
||||
bb.putInt(view.getValue());
|
||||
|
||||
//Build and send message
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
os.write("VIEW".getBytes(StandardCharsets.UTF_8));
|
||||
os.write(0xFF); //Placeholder for message length
|
||||
os.write(bb.array());
|
||||
sendUDP(os.toByteArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds, removes, or clears a set of waypoints. If the command is clear, the points are ignored
|
||||
* and all points are removed.
|
||||
|
||||
Binary file not shown.
@@ -29,7 +29,7 @@ if ~exist('socket', 'var')
|
||||
end
|
||||
|
||||
%% Validate input
|
||||
pause = logical(pause);
|
||||
pause = int32(pause);
|
||||
|
||||
%% Send command
|
||||
socket.pauseSim(pause);
|
||||
|
||||
@@ -9,6 +9,7 @@ function sendCTRL( values, ac, socket )
|
||||
% 4. Throttle [-1, 1]
|
||||
% 5. Gear (0=up, 1=down)
|
||||
% 6. Flaps [0, 1]
|
||||
% 7. Speed Brakes [-0.5, 1.5]
|
||||
% ac (optional): The aircraft to set. 0 for the player aircraft.
|
||||
% socket (optional): The client to use when sending the command.
|
||||
%
|
||||
|
||||
@@ -1,17 +1,8 @@
|
||||
function sendDREF( dref, value, socket )
|
||||
% sendDREF Sends a command to X-Plane that sets the given DREF.
|
||||
% sendDREFs Sends a command to X-Plane that sets the given DREF. This
|
||||
% function is now an alias to sendDREFs. It is kept only for backwards
|
||||
% compatibility.
|
||||
%
|
||||
% Inputs
|
||||
% dref: The name of the X-Plane dataref to set.
|
||||
% Value: An array of floating point values whose structure depends on the dref specified.
|
||||
% socket (optional): The client to use when sending the command.
|
||||
%
|
||||
% Use
|
||||
% 1. import XPlaneConnect.*
|
||||
% 2. dataRef = 'sim/aircraft/parts/acf_gear_deploy'; // Landing Gear
|
||||
% 3. Value = 0;
|
||||
% 4. status = setDREF(dataRef, Value);
|
||||
%
|
||||
% Contributors
|
||||
% [CT] Christopher Teubert (SGT, Inc.)
|
||||
% christopher.a.teubert@nasa.gov
|
||||
@@ -20,19 +11,8 @@ function sendDREF( dref, value, socket )
|
||||
|
||||
import XPlaneConnect.*
|
||||
|
||||
%% Get client
|
||||
global clients;
|
||||
if ~exist('socket', 'var')
|
||||
assert(isequal(length(clients) < 2, 1), '[setDREF] ERROR: Multiple clients open. You must specify which client to use.');
|
||||
if isempty(clients)
|
||||
socket = openUDP();
|
||||
else
|
||||
socket = clients(1);
|
||||
end
|
||||
end
|
||||
|
||||
%% Validate input
|
||||
value = single(value);
|
||||
|
||||
%%Send command
|
||||
socket.sendDREF(dref, value);
|
||||
sendDREFs(dref, value)
|
||||
else
|
||||
sendDREFs(dref, value, socket)
|
||||
end
|
||||
37
MATLAB/+XPlaneConnect/sendDREFs.m
Normal file
37
MATLAB/+XPlaneConnect/sendDREFs.m
Normal file
@@ -0,0 +1,37 @@
|
||||
function sendDREFs( drefs, values, socket )
|
||||
% sendDREFs Sends a command to X-Plane that sets the given DREF(s).
|
||||
%
|
||||
% Inputs
|
||||
% dref: The name or names of the X-Plane dataref(s) to set.
|
||||
% Value: An array or an multidimensional array of floating point values
|
||||
% whose structure depends on the dref specified.
|
||||
% socket (optional): The client to use when sending the command.
|
||||
%
|
||||
% Use
|
||||
% 1. import XPlaneConnect.*
|
||||
% 2. dataRef = 'sim/aircraft/parts/acf_gear_deploy'; // Landing Gear
|
||||
% 3. Value = 0;
|
||||
% 4. status = setDREF(dataRef, Value);
|
||||
%
|
||||
% Contributors
|
||||
% [JW] Jason Watkins
|
||||
% jason.w.watkins@nasa.gov
|
||||
|
||||
import XPlaneConnect.*
|
||||
|
||||
%% Get client
|
||||
global clients;
|
||||
if ~exist('socket', 'var')
|
||||
assert(isequal(length(clients) < 2, 1), '[setDREF] ERROR: Multiple clients open. You must specify which client to use.');
|
||||
if isempty(clients)
|
||||
socket = openUDP();
|
||||
else
|
||||
socket = clients(1);
|
||||
end
|
||||
end
|
||||
|
||||
%% Validate input
|
||||
values = single(values);
|
||||
|
||||
%%Send command
|
||||
socket.sendDREFs(drefs, values);
|
||||
35
MATLAB/+XPlaneConnect/sendVIEW.m
Normal file
35
MATLAB/+XPlaneConnect/sendVIEW.m
Normal file
@@ -0,0 +1,35 @@
|
||||
function sendVIEW(view, socket)
|
||||
% sendVIEW Sets the camera
|
||||
%
|
||||
%Inputs
|
||||
% view: The view to use.
|
||||
% socket (optional): The client to use when sending the command.
|
||||
%
|
||||
%Use
|
||||
% 1. import XPlaneConnect.*;
|
||||
% 2. sendView(Forwards);
|
||||
%
|
||||
% Contributors
|
||||
% [JW] Jason Watkins <jason.w.watkins@nasa.gov>
|
||||
|
||||
import XPlaneConnect.*
|
||||
|
||||
%% Get client
|
||||
global clients;
|
||||
if ~exist('socket', 'var')
|
||||
assert(isequal(length(clients) < 2, 1), '[pauseSim] ERROR: Multiple clients open. You must specify which client to use.');
|
||||
if isempty(clients)
|
||||
socket = openUDP();
|
||||
else
|
||||
socket = clients(1);
|
||||
end
|
||||
end
|
||||
|
||||
%% Validate input
|
||||
|
||||
|
||||
%% Send command
|
||||
socket.sendVIEW(view)
|
||||
|
||||
end
|
||||
|
||||
@@ -11,6 +11,10 @@ import XPlaneConnect.*
|
||||
disp('xplaneconnect Example Script-');
|
||||
disp('Setting up Simulation');
|
||||
Socket = openUDP(49005);
|
||||
|
||||
%% Ensure connected
|
||||
getDREFs('sim/test/test_float')
|
||||
|
||||
%% Set position of the player aircraft
|
||||
disp('Setting position');
|
||||
pauseSim(1);
|
||||
|
||||
72
Python/src/example.py
Normal file
72
Python/src/example.py
Normal file
@@ -0,0 +1,72 @@
|
||||
from time import sleep
|
||||
import xpc
|
||||
|
||||
def ex():
|
||||
print "X-Plane Connect example script"
|
||||
print "Setting up simulation"
|
||||
with xpc.XPlaneConnect() as client:
|
||||
# Verify connection
|
||||
try:
|
||||
# If X-Plane does not respond to the request, a timeout error
|
||||
# will be raised.
|
||||
client.getDREF("sim/test/test_float")
|
||||
except:
|
||||
print "Error establishing connection to X-Plane."
|
||||
print "Exiting..."
|
||||
return
|
||||
|
||||
# Set position of the player aircraft
|
||||
print "Setting position"
|
||||
# Lat Lon Alt Pitch Roll Yaw Gear
|
||||
posi = [37.524, -122.06899, 2500, 0, 0, 0, 1]
|
||||
client.sendPOSI(posi)
|
||||
|
||||
# Set position of a non-player aircraft
|
||||
print "Setting NPC position"
|
||||
# Lat Lon Alt Pitch Roll Yaw Gear
|
||||
posi = [37.52465, -122.06899, 2500, 0, 20, 0, 1]
|
||||
client.sendPOSI(posi, 1)
|
||||
|
||||
# Set angle of attack, velocity, and orientation using the DATA command
|
||||
print "Setting orientation"
|
||||
data = [\
|
||||
[18, 0, -998, 0, -998, -998, -998, -998, -998],\
|
||||
[ 3, 130, 130, 130, 130, -998, -998, -998, -998],\
|
||||
[16, 0, 0, 0, -998, -998, -998, -998, -998]\
|
||||
]
|
||||
client.sendDATA(data)
|
||||
|
||||
# Set control surfaces and throttle of the player aircraft using sendCTRL
|
||||
print "Setting controls"
|
||||
ctrl = [0.0, 0.0, 0.0, 0.8]
|
||||
client.sendCTRL(ctrl)
|
||||
|
||||
# Pause the sim
|
||||
print "Pausing"
|
||||
client.pauseSim(True)
|
||||
sleep(2)
|
||||
|
||||
# Toggle pause state to resume
|
||||
print "Resuming"
|
||||
client.pauseSim(False)
|
||||
|
||||
# Stow landing gear using a dataref
|
||||
print "Stowing gear"
|
||||
gear_dref = "sim/cockpit/switches/gear_handle_status"
|
||||
client.sendDREF(gear_dref, 0)
|
||||
|
||||
# Let the sim run for a bit.
|
||||
sleep(4)
|
||||
|
||||
# Make sure gear was stowed successfully
|
||||
gear_status = client.getDREF(gear_dref)
|
||||
if gear_status[0] == 0:
|
||||
print "Gear stowed"
|
||||
else:
|
||||
print "Error stowing gear"
|
||||
|
||||
print "End of Python client example"
|
||||
raw_input("Press any key to exit...")
|
||||
|
||||
if __name__ == "__main__":
|
||||
ex()
|
||||
384
Python/src/xpc.py
Normal file
384
Python/src/xpc.py
Normal file
@@ -0,0 +1,384 @@
|
||||
import socket
|
||||
import struct
|
||||
|
||||
class XPlaneConnect(object):
|
||||
'''XPlaneConnect (XPC) facilitates communication to and from the XPCPlugin.'''
|
||||
socket = None
|
||||
|
||||
# Basic Functions
|
||||
def __init__(self, xpHost = 'localhost', xpPort = 49009, port = 0, timeout = 100):
|
||||
'''Sets up a new connection to an X-Plane Connect plugin running in X-Plane.
|
||||
|
||||
Args:
|
||||
xpHost: The hostname of the machine running X-Plane.
|
||||
xpPort: The port on which the XPC plugin is listening. Usually 49007.
|
||||
port: The port which will be used to send and receive data.
|
||||
timeout: The period (in milliseconds) after which read attempts will fail.
|
||||
'''
|
||||
|
||||
# Validate parameters
|
||||
xpIP = None
|
||||
try:
|
||||
xpIP = socket.gethostbyname(xpHost)
|
||||
except:
|
||||
raise ValueError("Unable to resolve xpHost.")
|
||||
|
||||
if xpPort < 0 or xpPort > 65535:
|
||||
raise ValueError("The specified X-Plane port is not a valid port number.")
|
||||
if port < 0 or port > 65535:
|
||||
raise ValueError("The specified port is not a valid port number.")
|
||||
if timeout < 0:
|
||||
raise ValueError("timeout must be non-negative.")
|
||||
|
||||
# Setup XPlane IP and port
|
||||
self.xpDst = (xpIP, xpPort)
|
||||
|
||||
# Create and bind socket
|
||||
clientAddr = ("0.0.0.0", port)
|
||||
self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
|
||||
self.socket.bind(clientAddr)
|
||||
timeout /= 1000.0
|
||||
self.socket.settimeout(timeout)
|
||||
|
||||
def __del__(self):
|
||||
self.close()
|
||||
|
||||
# Define __enter__ and __exit__ to support the `with` construct.
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
self.close()
|
||||
|
||||
def close(self):
|
||||
'''Closes the specified connection and releases resources associated with it.'''
|
||||
if self.socket is not None:
|
||||
self.socket.close()
|
||||
self.socket = None
|
||||
|
||||
def sendUDP(self, buffer):
|
||||
'''Sends a message over the underlying UDP socket.'''
|
||||
# Preconditions
|
||||
if(len(buffer) == 0):
|
||||
raise ValueError("sendUDP: buffer is empty.")
|
||||
|
||||
self.socket.sendto(buffer, 0, self.xpDst)
|
||||
|
||||
def readUDP(self):
|
||||
'''Reads a message from the underlying UDP socket.'''
|
||||
return self.socket.recv(16384)
|
||||
|
||||
# Configuration
|
||||
def setCONN(self, port):
|
||||
'''Sets the port on which the client sends and receives data.
|
||||
|
||||
Args:
|
||||
port: The new port to use.
|
||||
'''
|
||||
#Validate parameters
|
||||
if port < 0 or port > 65535:
|
||||
raise ValueError("The specified port is not a valid port number.")
|
||||
|
||||
#Send command
|
||||
buffer = struct.pack("<4sxH", "CONN", port)
|
||||
self.sendUDP(buffer)
|
||||
|
||||
#Rebind socket
|
||||
clientAddr = ("0.0.0.0", port)
|
||||
timeout = self.socket.gettimeout();
|
||||
self.socket.close();
|
||||
self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
|
||||
self.socket.bind(clientAddr)
|
||||
self.socket.settimeout(timeout)
|
||||
|
||||
#Read response
|
||||
buffer = self.socket.recv(1024)
|
||||
|
||||
def pauseSim(self, pause):
|
||||
'''Pauses or un-pauses the physics simulation engine in X-Plane.
|
||||
|
||||
Args:
|
||||
pause: True to pause the simulation; False to resume.
|
||||
'''
|
||||
pause = int(pause)
|
||||
if pause < 0 or pause > 2:
|
||||
raise ValueError("Invalid argument for pause command.")
|
||||
|
||||
buffer = struct.pack("<4sxB", "SIMU", pause)
|
||||
self.sendUDP(buffer)
|
||||
|
||||
# X-Plane UDP Data
|
||||
def readDATA(self):
|
||||
'''Reads X-Plane data.
|
||||
|
||||
Returns: A 2 dimensional array containing 0 or more rows of data. Each array
|
||||
in the result will have 9 elements, the first of which is the row number which
|
||||
that array represents data for, and the rest of which are the data elements in
|
||||
that row.
|
||||
'''
|
||||
buffer = self.readUDP();
|
||||
if len(buffer) < 6:
|
||||
return None
|
||||
rows = (len(buffer) - 5) / 36
|
||||
data = []
|
||||
for i in range(rows):
|
||||
data.append(struct.unpack_from("9f", buffer, 5 + 36*i))
|
||||
return data
|
||||
|
||||
def sendDATA(self, data):
|
||||
'''Sends X-Plane data over the underlying UDP socket.
|
||||
|
||||
Args:
|
||||
data: An array of values representing data rows to be set. Each array in `data`
|
||||
should have 9 elements, the first of which is a row number in the range (0-134),
|
||||
and the rest of which are the values to set for that data row.
|
||||
'''
|
||||
if len(data) > 134:
|
||||
raise ValueError("Too many rows in data.")
|
||||
|
||||
buffer = struct.pack("<4sx", "DATA")
|
||||
for row in data:
|
||||
if len(row) != 9:
|
||||
raise ValueError("Row does not contain exactly 9 values. <" + str(row) + ">")
|
||||
buffer += struct.pack("<I8f", *row)
|
||||
self.sendUDP(buffer)
|
||||
|
||||
# Position
|
||||
def sendPOSI(self, values, ac = 0):
|
||||
'''Sets position information on the specified aircraft.
|
||||
|
||||
Args:
|
||||
values: The position values to set. `values` is a array containing up to
|
||||
7 elements. If less than 7 elements are specified or any elment is set to `-998`,
|
||||
those values will not be changed. The elements in `values` corespond to the
|
||||
following:
|
||||
* Latitude (deg)
|
||||
* Longitude (deg)
|
||||
* Altitude (m above MSL)
|
||||
* Roll (deg)
|
||||
* Pitch (deg)
|
||||
* True Heading (deg)
|
||||
* Gear (0=up, 1=down)
|
||||
ac: The aircraft to set the control surfaces of. 0 is the main/player aircraft.
|
||||
'''
|
||||
# Preconditions
|
||||
if len(values) < 1 or len(values) > 7:
|
||||
raise ValueError("Must have between 0 and 7 items in values.")
|
||||
if ac < 0 or ac > 20:
|
||||
raise ValueError("Aircraft number must be between 0 and 20.")
|
||||
|
||||
# Pack message
|
||||
buffer = struct.pack("<4sxB", "POSI", ac)
|
||||
for i in range(7):
|
||||
val = -998
|
||||
if i < len(values):
|
||||
val = values[i]
|
||||
buffer += struct.pack("<f", val)
|
||||
|
||||
# Send
|
||||
self.sendUDP(buffer)
|
||||
|
||||
# Controls
|
||||
def sendCTRL(self, values, ac = 0):
|
||||
'''Sets control surface information on the specified aircraft.
|
||||
|
||||
Args:
|
||||
values: The control surface values to set. `values` is a array containing up to
|
||||
6 elements. If less than 6 elements are specified or any elment is set to `-998`,
|
||||
those values will not be changed. The elements in `values` corespond to the
|
||||
following:
|
||||
* Latitudinal Stick [-1,1]
|
||||
* Longitudinal Stick [-1,1]
|
||||
* Rudder Pedals [-1, 1]
|
||||
* Throttle [-1, 1]
|
||||
* Gear (0=up, 1=down)
|
||||
* Flaps [0, 1]
|
||||
* Speedbrakes [-0.5, 1.5]
|
||||
ac: The aircraft to set the control surfaces of. 0 is the main/player aircraft.
|
||||
'''
|
||||
# Preconditions
|
||||
if len(values) < 1 or len(values) > 7:
|
||||
raise ValueError("Must have between 0 and 6 items in values.")
|
||||
if ac < 0 or ac > 20:
|
||||
raise ValueError("Aircraft number must be between 0 and 20.")
|
||||
|
||||
# Pack message
|
||||
buffer = struct.pack("<4sx", "CTRL")
|
||||
for i in range(6):
|
||||
val = -998
|
||||
if i < len(values):
|
||||
val = values[i]
|
||||
if i == 4:
|
||||
val = -1 if (abs(val + 998) < 1e-4) else val
|
||||
buffer += struct.pack("b", val)
|
||||
else:
|
||||
buffer += struct.pack("<f", val)
|
||||
buffer += struct.pack("B", ac)
|
||||
if len(values) == 7:
|
||||
buffer += struct.pack("<f", values[6])
|
||||
|
||||
# Send
|
||||
self.sendUDP(buffer)
|
||||
|
||||
# DREF Manipulation
|
||||
def sendDREF(self, dref, values):
|
||||
'''Sets the specified dataref to the specified value.
|
||||
|
||||
Args:
|
||||
dref: The name of the datarefs to set.
|
||||
values: Either a scalar value or a sequence of values.
|
||||
'''
|
||||
self.sendDREFs([dref], [values])
|
||||
|
||||
def sendDREFs(self, drefs, values):
|
||||
'''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 len(drefs) != len(values):
|
||||
raise ValueError("drefs and values must have the same number of elements.")
|
||||
|
||||
buffer = struct.pack("<4sx", "DREF")
|
||||
for i in range(len(drefs)):
|
||||
dref = drefs[i]
|
||||
value = values[i]
|
||||
# Preconditions
|
||||
if len(dref) == 0 or len(dref) > 255:
|
||||
raise ValueError("dref must be a non-empty string less than 256 characters.")
|
||||
if value == None:
|
||||
raise ValueError("value must be a scalar or sequence of floats.")
|
||||
|
||||
# Pack message
|
||||
if hasattr(value, "__len__"):
|
||||
if len(value) > 255:
|
||||
raise ValueError("value must have less than 256 items.")
|
||||
fmt = "<B{0:d}sB{1:d}f".format(len(dref), len(value))
|
||||
buffer += struct.pack(fmt, len(dref), dref, len(value), value)
|
||||
else:
|
||||
fmt = "<B{0:d}sBf".format(len(dref))
|
||||
buffer += struct.pack(fmt, len(dref), dref, 1, value)
|
||||
|
||||
# Send
|
||||
self.sendUDP(buffer)
|
||||
|
||||
def getDREF(self, dref):
|
||||
'''Gets the value of an X-Plane dataref.
|
||||
|
||||
Args:
|
||||
dref: The name of the dataref to get.
|
||||
|
||||
Returns: A sequence of data representing the values of the requested dataref.
|
||||
'''
|
||||
return self.getDREFs([dref])[0]
|
||||
|
||||
def getDREFs(self, drefs):
|
||||
'''Gets the value of one or more X-Plane datarefs.
|
||||
|
||||
Args:
|
||||
drefs: The names of the datarefs to get.
|
||||
|
||||
Returns: A multidimensional sequence of data representing the values of the requested
|
||||
datarefs.
|
||||
'''
|
||||
# Send request
|
||||
buffer = struct.pack("<4sxB", "GETD", len(drefs))
|
||||
for dref in drefs:
|
||||
fmt = "<B{0:d}s".format(len(dref))
|
||||
buffer += struct.pack(fmt, len(dref), dref)
|
||||
self.sendUDP(buffer)
|
||||
|
||||
# Read and parse response
|
||||
buffer = self.readUDP()
|
||||
resultCount = struct.unpack_from("B", buffer, 5)[0]
|
||||
offset = 6
|
||||
result = []
|
||||
for i in range(resultCount):
|
||||
rowLen = struct.unpack_from("B", buffer, offset)[0]
|
||||
offset += 1
|
||||
fmt = "<{0:d}f".format(rowLen)
|
||||
row = struct.unpack_from(fmt, buffer, offset)
|
||||
result.append(row)
|
||||
offset += rowLen * 4
|
||||
return result
|
||||
|
||||
# Drawing
|
||||
def sendTEXT(self, msg, x = -1, y = -1):
|
||||
'''Sets a message that X-Plane will display on the screen.
|
||||
|
||||
Args:
|
||||
msg: The string to display on the screen
|
||||
x: The distance in pixels from the left edge of the screen to display the
|
||||
message. A value of -1 indicates that the default horizontal position should
|
||||
be used.
|
||||
y: The distance in pixels from the bottom edge of the screen to display the
|
||||
message. A value of -1 indicates that the default vertical position should be
|
||||
used.
|
||||
'''
|
||||
if y < -1:
|
||||
raise ValueError("y must be greater than or equal to -1.")
|
||||
|
||||
if msg == None:
|
||||
msg = ""
|
||||
|
||||
msgLen = len(msg)
|
||||
buffer = struct.pack("<4sxiiB" + str(msgLen) + "s", "TEXT", x, y, msgLen, msg)
|
||||
self.sendUDP(buffer)
|
||||
|
||||
def sendVIEW(self, view):
|
||||
'''Sets the camera view in X-Plane
|
||||
|
||||
Args:
|
||||
view: The view to use. The ViewType class provides named constants
|
||||
for known views.
|
||||
'''
|
||||
# Preconditions
|
||||
if view < ViewType.Forwards or view > ViewType.FullscreenNoHud:
|
||||
raise ValueError("Unknown view command.")
|
||||
|
||||
# Pack buffer
|
||||
buffer = struct.pack("<4sxi", "VIEW", view)
|
||||
|
||||
# Send message
|
||||
self.sendUDP(buffer)
|
||||
|
||||
def sendWYPT(self, op, points):
|
||||
'''Adds, removes, or clears waypoints. Waypoints are three dimensional points on or
|
||||
above the Earth's surface that are represented visually in the simulator. Each
|
||||
point consists of a latitude and longitude expressed in fractional degrees and
|
||||
an altitude expressed as meters above sea level.
|
||||
|
||||
Args:
|
||||
op: The operation to perform. Pass `1` to add waypoints,
|
||||
`2` to remove waypoints, and `3` to clear all waypoints.
|
||||
points: A sequence of floating point values representing latitude, longitude, and
|
||||
altitude triples. The length of this array should always be divisible by 3.
|
||||
'''
|
||||
if op < 1 or op > 3:
|
||||
raise ValueError("Invalid operation specified.")
|
||||
if len(points) % 3 != 0:
|
||||
raise ValueError("Invalid points. Points should be divisible by 3.")
|
||||
if len(points) / 3 > 255:
|
||||
raise ValueError("Too many points. You can only send 255 points at a time.")
|
||||
|
||||
if op == 3:
|
||||
buffer = struct.pack("<4sxBB", "WYPT", 3, 0)
|
||||
else:
|
||||
buffer = struct.pack("<4sxBB" + str(len(points)) + "f", "WYPT", op, len(points), *points)
|
||||
self.sendUDP(buffer)
|
||||
|
||||
class ViewType(object):
|
||||
Forwards = 73
|
||||
Down = 74
|
||||
Left = 75
|
||||
Right = 76
|
||||
Back = 77
|
||||
Tower = 78
|
||||
Runway = 79
|
||||
Chase = 80
|
||||
Follow = 81
|
||||
FollowWithPanel = 82
|
||||
Spot = 83
|
||||
FullscreenWithHud = 84
|
||||
FullscreenNoHud = 85
|
||||
52
Python/xplaneConnect.pyproj
Normal file
52
Python/xplaneConnect.pyproj
Normal file
@@ -0,0 +1,52 @@
|
||||
<?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>3c7a940d-17c8-4e91-882f-9bc8b1d2f54b</ProjectGuid>
|
||||
<ProjectHome>.</ProjectHome>
|
||||
<StartupFile>src\example.py</StartupFile>
|
||||
<SearchPath>
|
||||
</SearchPath>
|
||||
<WorkingDirectory>.</WorkingDirectory>
|
||||
<OutputPath>.</OutputPath>
|
||||
<Name>XPlaneConnect</Name>
|
||||
<RootNamespace>XPlaneConnect</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="src\xpc.py" />
|
||||
<Compile Include="src\example.py">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="src\" />
|
||||
</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>
|
||||
24
Python/xplaneConnect.sln
Normal file
24
Python/xplaneConnect.sln
Normal file
@@ -0,0 +1,24 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 2013
|
||||
VisualStudioVersion = 12.0.31101.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{888888A0-9F3D-457C-B088-3A5042F75D52}") = "XPlaneConnect", "XPlaneConnect.pyproj", "{3C7A940D-17C8-4E91-882F-9BC8B1D2F54B}"
|
||||
EndProject
|
||||
Project("{888888A0-9F3D-457C-B088-3A5042F75D52}") = "Tests", "..\TestScripts\Python Tests\Tests.pyproj", "{6931EBB2-4E01-4C5A-86B6-668C0E75051B}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{3C7A940D-17C8-4E91-882F-9BC8B1D2F54B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3C7A940D-17C8-4E91-882F-9BC8B1D2F54B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6931EBB2-4E01-4C5A-86B6-668C0E75051B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6931EBB2-4E01-4C5A-86B6-668C0E75051B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -21,9 +21,20 @@
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\C\src\xplaneConnect.c" />
|
||||
<ClCompile Include="..\C Tests\main.c" />
|
||||
<ClCompile Include="..\C Tests\Test.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\C\src\xplaneConnect.h" />
|
||||
<ClInclude Include="..\C Tests\CtrlTests.h" />
|
||||
<ClInclude Include="..\C Tests\DataTests.h" />
|
||||
<ClInclude Include="..\C Tests\DrefTests.h" />
|
||||
<ClInclude Include="..\C Tests\PosiTests.h" />
|
||||
<ClInclude Include="..\C Tests\SimuTests.h" />
|
||||
<ClInclude Include="..\C Tests\Test.h" />
|
||||
<ClInclude Include="..\C Tests\TextTests.h" />
|
||||
<ClInclude Include="..\C Tests\UDPTests.h" />
|
||||
<ClInclude Include="..\C Tests\ViewTests.h" />
|
||||
<ClInclude Include="..\C Tests\WyptTests.h" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{BC701AF4-552C-4C9D-82A1-B352542783A4}</ProjectGuid>
|
||||
|
||||
@@ -21,10 +21,40 @@
|
||||
<ClCompile Include="..\..\C\src\xplaneConnect.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\C Tests\Test.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\C\src\xplaneConnect.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\C Tests\UDPTests.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\C Tests\DrefTests.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\C Tests\TextTests.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\C Tests\SimuTests.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\C Tests\CtrlTests.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\C Tests\DataTests.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\C Tests\PosiTests.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\C Tests\WyptTests.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\C Tests\Test.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -7,6 +7,7 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
BE7CF6311B0CFA34008B1E07 /* Test.c in Sources */ = {isa = PBXBuildFile; fileRef = BE7CF62B1B0CFA34008B1E07 /* Test.c */; };
|
||||
BEB0F5071A28F9A3001975A6 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = BEB0F5061A28F9A3001975A6 /* main.c */; };
|
||||
BEB0F5091A28F9A3001975A6 /* C_Tests.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BEB0F5081A28F9A3001975A6 /* C_Tests.1 */; };
|
||||
BEB0F5111A28F9D5001975A6 /* xplaneConnect.c in Sources */ = {isa = PBXBuildFile; fileRef = BEB0F50F1A28F9D5001975A6 /* xplaneConnect.c */; };
|
||||
@@ -27,6 +28,17 @@
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
BE7CF6261B0CFA34008B1E07 /* CtrlTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CtrlTests.h; sourceTree = "<group>"; };
|
||||
BE7CF6271B0CFA34008B1E07 /* DataTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DataTests.h; sourceTree = "<group>"; };
|
||||
BE7CF6281B0CFA34008B1E07 /* DrefTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DrefTests.h; sourceTree = "<group>"; };
|
||||
BE7CF6291B0CFA34008B1E07 /* PosiTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PosiTests.h; sourceTree = "<group>"; };
|
||||
BE7CF62A1B0CFA34008B1E07 /* SimuTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SimuTests.h; sourceTree = "<group>"; };
|
||||
BE7CF62B1B0CFA34008B1E07 /* Test.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = Test.c; sourceTree = "<group>"; };
|
||||
BE7CF62C1B0CFA34008B1E07 /* Test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Test.h; sourceTree = "<group>"; };
|
||||
BE7CF62D1B0CFA34008B1E07 /* TextTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TextTests.h; sourceTree = "<group>"; };
|
||||
BE7CF62E1B0CFA34008B1E07 /* UDPTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UDPTests.h; sourceTree = "<group>"; };
|
||||
BE7CF62F1B0CFA34008B1E07 /* ViewTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewTests.h; sourceTree = "<group>"; };
|
||||
BE7CF6301B0CFA34008B1E07 /* WyptTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WyptTests.h; sourceTree = "<group>"; };
|
||||
BEB0F5031A28F9A3001975A6 /* C Tests */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "C Tests"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
BEB0F5061A28F9A3001975A6 /* main.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = "<group>"; };
|
||||
BEB0F5081A28F9A3001975A6 /* C_Tests.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = C_Tests.1; sourceTree = "<group>"; };
|
||||
@@ -66,6 +78,17 @@
|
||||
BEB0F5051A28F9A3001975A6 /* C Tests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
BE7CF6261B0CFA34008B1E07 /* CtrlTests.h */,
|
||||
BE7CF6271B0CFA34008B1E07 /* DataTests.h */,
|
||||
BE7CF6281B0CFA34008B1E07 /* DrefTests.h */,
|
||||
BE7CF6291B0CFA34008B1E07 /* PosiTests.h */,
|
||||
BE7CF62A1B0CFA34008B1E07 /* SimuTests.h */,
|
||||
BE7CF62B1B0CFA34008B1E07 /* Test.c */,
|
||||
BE7CF62C1B0CFA34008B1E07 /* Test.h */,
|
||||
BE7CF62D1B0CFA34008B1E07 /* TextTests.h */,
|
||||
BE7CF62E1B0CFA34008B1E07 /* UDPTests.h */,
|
||||
BE7CF62F1B0CFA34008B1E07 /* ViewTests.h */,
|
||||
BE7CF6301B0CFA34008B1E07 /* WyptTests.h */,
|
||||
BEB0F5061A28F9A3001975A6 /* main.c */,
|
||||
BEB0F5081A28F9A3001975A6 /* C_Tests.1 */,
|
||||
);
|
||||
@@ -126,6 +149,7 @@
|
||||
BEB0F5111A28F9D5001975A6 /* xplaneConnect.c in Sources */,
|
||||
BEB0F5121A28F9D5001975A6 /* xplaneConnect.h in Sources */,
|
||||
BEB0F5071A28F9A3001975A6 /* main.c in Sources */,
|
||||
BE7CF6311B0CFA34008B1E07 /* Test.c in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
||||
149
TestScripts/C Tests/CtrlTests.h
Normal file
149
TestScripts/C Tests/CtrlTests.h
Normal file
@@ -0,0 +1,149 @@
|
||||
//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
//National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#ifndef CTRLTESTS_H
|
||||
#define CTRLTESTS_H
|
||||
|
||||
#include "Test.h"
|
||||
#include "xplaneConnect.h"
|
||||
|
||||
int doCTRLTest(char* drefs[7], float values[], int size, int ac, float expected[7])
|
||||
{
|
||||
float* data[7];
|
||||
int sizes[7];
|
||||
for (int i = 0; i < 7; ++i)
|
||||
{
|
||||
data[i] = (float*)malloc(sizeof(float) * 16);
|
||||
sizes[i] = 16;
|
||||
}
|
||||
|
||||
// Execute command
|
||||
XPCSocket sock = openUDP(IP);
|
||||
int result = sendCTRL(sock, values, size, ac);
|
||||
if (result >= 0)
|
||||
{
|
||||
result = getDREFs(sock, drefs, data, 7, sizes);
|
||||
}
|
||||
closeUDP(sock);
|
||||
if (result < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Test values
|
||||
float actual[7];
|
||||
for (int i = 0; i < 7; ++i)
|
||||
{
|
||||
actual[i] = data[i][0];
|
||||
}
|
||||
return compareArray(expected, actual, 7);
|
||||
}
|
||||
|
||||
int basicCTRLTest(char** drefs, int ac)
|
||||
{
|
||||
// Set control surfaces to known state.
|
||||
float CTRL[6] = { 0.0F, 0.0F, 0.0F, 0.8F, 1.0F, 0.5F };
|
||||
float expected[7] = { 0.0F, 0.0F, 0.0F, NAN, NAN, NAN, NAN };
|
||||
int result = doCTRLTest(drefs, CTRL, 3, ac, expected);
|
||||
if (result < 0)
|
||||
{
|
||||
return -10000 + result;
|
||||
}
|
||||
|
||||
// Test control surfaces and set other values to known state.
|
||||
expected[0] = CTRL[0] = 0.2F;
|
||||
expected[1] = CTRL[1] = 0.1F;
|
||||
expected[2] = CTRL[2] = 0.1F;
|
||||
expected[3] = 0.8F;
|
||||
expected[4] = 1.0F;
|
||||
expected[5] = 0.5F;
|
||||
result = doCTRLTest(drefs, CTRL, 6, ac, expected);
|
||||
if (result < 0)
|
||||
{
|
||||
return -20000 + result;
|
||||
}
|
||||
|
||||
// Test other values and verify control surfaces unchanged.
|
||||
CTRL[0] = -998;
|
||||
CTRL[1] = -998;
|
||||
CTRL[2] = -998;
|
||||
expected[3] = CTRL[3] = 0.9F;
|
||||
expected[4] = CTRL[4] = 0.0F;
|
||||
expected[5] = CTRL[5] = 0.75F;
|
||||
result = doCTRLTest(drefs, CTRL, 6, ac, expected);
|
||||
if (result < 0)
|
||||
{
|
||||
return -30000 + result;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int testCTRL_Player()
|
||||
{
|
||||
char* 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",
|
||||
"sim/flightmodel/controls/sbrkrqst"
|
||||
};
|
||||
return basicCTRLTest(drefs, 0);
|
||||
}
|
||||
|
||||
int testCTRL_NonPlayer()
|
||||
{
|
||||
char* drefs[] =
|
||||
{
|
||||
"sim/multiplayer/position/plane1_yolk_pitch",
|
||||
"sim/multiplayer/position/plane1_yolk_roll",
|
||||
"sim/multiplayer/position/plane1_yolk_yaw",
|
||||
"sim/multiplayer/position/plane1_throttle",
|
||||
"sim/multiplayer/position/plane1_gear_deploy",
|
||||
"sim/multiplayer/position/plane1_flap_ratio",
|
||||
"sim/multiplayer/position/plane1_sbrkrqst"
|
||||
};
|
||||
return basicCTRLTest(drefs, 1);
|
||||
}
|
||||
|
||||
int testCTRL_Speedbrakes()
|
||||
{
|
||||
char* 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",
|
||||
"sim/flightmodel/controls/sbrkrqst"
|
||||
};
|
||||
|
||||
// Arm
|
||||
float CTRL[7] = { -998, -998, -998, -998, -998, -998, -0.5F };
|
||||
float expected[7] = { NAN, NAN, NAN, NAN, NAN, NAN, -0.5F };
|
||||
int result = doCTRLTest(drefs, CTRL, 7, 0, expected);
|
||||
if (result < 0)
|
||||
{
|
||||
return -10000 + result;
|
||||
}
|
||||
|
||||
// Set to full
|
||||
expected[6] = CTRL[6] = 1.5F;
|
||||
result = doCTRLTest(drefs, CTRL, 7, 0, expected);
|
||||
if (result < 0)
|
||||
{
|
||||
return -20000 + result;
|
||||
}
|
||||
|
||||
// Retract
|
||||
expected[6] = CTRL[6] = 0.0F;
|
||||
result = doCTRLTest(drefs, CTRL, 7, 0, expected);
|
||||
if (result < 0)
|
||||
{
|
||||
return -30000 + result;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
62
TestScripts/C Tests/DataTests.h
Normal file
62
TestScripts/C Tests/DataTests.h
Normal file
@@ -0,0 +1,62 @@
|
||||
//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
//National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#ifndef DATATESTS_H
|
||||
#define DATATESTS_H
|
||||
|
||||
#include "Test.h"
|
||||
#include "xplaneConnect.h"
|
||||
|
||||
int testDATA()
|
||||
{
|
||||
// Initialize
|
||||
int i, j; // Iterator
|
||||
char* drefs[100] =
|
||||
{
|
||||
"sim/aircraft/parts/acf_gear_deploy"
|
||||
};
|
||||
float* data[100]; // array for result of getDREFs
|
||||
int sizes[100];
|
||||
float DATA[4][9]; // Array for sendDATA
|
||||
XPCSocket sock = openUDP(IP);
|
||||
|
||||
// Setup
|
||||
for (int i = 0; i < 100; ++i)
|
||||
{
|
||||
data[i] = (float*)malloc(40 * sizeof(float));
|
||||
sizes[i] = 40;
|
||||
}
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
for (j = 0; j < 9; j++)
|
||||
{
|
||||
data[i][j] = -998;
|
||||
}
|
||||
}
|
||||
DATA[0][0] = 14; // Gear
|
||||
DATA[0][1] = 1;
|
||||
DATA[0][2] = 0;
|
||||
|
||||
// Execution
|
||||
sendDATA(sock, DATA, 1);
|
||||
int result = getDREFs(sock, drefs, data, 1, sizes);
|
||||
|
||||
// Close
|
||||
closeUDP(sock);
|
||||
|
||||
// Tests
|
||||
if (result < 0)// Request 1 value
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (sizes[0] != 10)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
if (*data[0] != data[0][1])
|
||||
{
|
||||
return -3;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
247
TestScripts/C Tests/DrefTests.h
Normal file
247
TestScripts/C Tests/DrefTests.h
Normal file
@@ -0,0 +1,247 @@
|
||||
//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
//National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#ifndef DREFTESTS_H
|
||||
#define DREFTESTS_H
|
||||
|
||||
#include "Test.h"
|
||||
#include "xplaneConnect.h"
|
||||
|
||||
int doGETDTest(char* drefs[], float* expected[], int count, int sizes[])
|
||||
{
|
||||
// Setup memory
|
||||
int* asizes = (int*)malloc(sizeof(int) * count);
|
||||
float** actual = (float**)malloc(sizeof(float*) * count);
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
asizes[i] = sizes[i];
|
||||
actual[i] = (float*)malloc(sizeof(float) * sizes[i]);
|
||||
}
|
||||
|
||||
// Execute command
|
||||
XPCSocket sock = openUDP(IP);
|
||||
int result = getDREFs(sock, drefs, actual, count, asizes);
|
||||
closeUDP(sock);
|
||||
if (result < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Test sizes and values
|
||||
result = compareArrays(expected, sizes, actual, asizes, count);
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
free(actual[i]);
|
||||
}
|
||||
free(actual);
|
||||
free(asizes);
|
||||
return result;
|
||||
}
|
||||
|
||||
int doDREFTest(char* drefs[], float* values[], float* expected[], int count, int sizes[])
|
||||
{
|
||||
// Setup memory
|
||||
int* asizes = (int*)malloc(sizeof(int) * count);
|
||||
float** actual = (float**)malloc(sizeof(float*) * count);
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
asizes[i] = sizes[i];
|
||||
actual[i] = (float*)malloc(sizeof(float) * sizes[i]);
|
||||
}
|
||||
|
||||
// Execute command
|
||||
XPCSocket sock = openUDP(IP);
|
||||
int result = sendDREFs(sock, drefs, values, sizes, count);
|
||||
if (result >= 0)
|
||||
{
|
||||
result = getDREFs(sock, drefs, actual, count, asizes);
|
||||
}
|
||||
closeUDP(sock);
|
||||
if (result < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Test sizes and values
|
||||
result = compareArrays(expected, sizes, actual, asizes, count);
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
free(actual[i]);
|
||||
}
|
||||
free(actual);
|
||||
free(asizes);
|
||||
return result;
|
||||
}
|
||||
|
||||
int testGETD_Basic()
|
||||
{
|
||||
char* drefs[] =
|
||||
{
|
||||
"sim/cockpit/switches/gear_handle_status", //int
|
||||
"sim/cockpit/autopilot/altitude", //float
|
||||
"sim/aircraft/prop/acf_prop_type", //int[8]
|
||||
"sim/cockpit2/switches/panel_brightness_ratio", //float[4]
|
||||
"sim/aircraft/view/acf_tailnum", //byte[40]
|
||||
"sim/flightmodel/position/elevation" //double
|
||||
};
|
||||
int sizes[] = { 1, 1, 8, 4, 40, 1 };
|
||||
float* expected[6];
|
||||
for (int i = 0; i < 6; ++i)
|
||||
{
|
||||
expected[i] = (float*)malloc(sizeof(float) * sizes[i]);
|
||||
for (int j = 0; j < sizes[i]; ++j)
|
||||
{
|
||||
expected[i][j] = NAN;
|
||||
}
|
||||
}
|
||||
|
||||
return doGETDTest(drefs, expected, 6, sizes);
|
||||
}
|
||||
|
||||
int testGETD_TestFloat()
|
||||
{
|
||||
char* dref = "sim/test/test_float";
|
||||
int size = 1;
|
||||
float* expected[1];
|
||||
expected[0] = (float*)malloc(sizeof(float));
|
||||
expected[0][0] = 0.0F;
|
||||
|
||||
int result = doGETDTest(&dref, &expected, 1, &size);
|
||||
free(expected[0]);
|
||||
return result;
|
||||
}
|
||||
|
||||
int testGETD_Types()
|
||||
{
|
||||
char* drefs[] =
|
||||
{
|
||||
"sim/cockpit/switches/gear_handle_status", //int
|
||||
"sim/cockpit/autopilot/altitude", //float
|
||||
"sim/aircraft/prop/acf_prop_type", //int[8]
|
||||
"sim/cockpit2/switches/panel_brightness_ratio", //float[4]
|
||||
"sim/aircraft/view/acf_tailnum", //byte[40]
|
||||
"sim/flightmodel/position/elevation" //double
|
||||
};
|
||||
int sizes[] = { 1, 1, 8, 4, 40, 1 };
|
||||
float* data[6];
|
||||
for (int i = 0; i < 6; ++i)
|
||||
{
|
||||
data[i] = (float*)malloc(sizeof(float) * sizes[i]);
|
||||
}
|
||||
|
||||
// Execute command
|
||||
XPCSocket sock = openUDP(IP);
|
||||
int result = getDREFs(sock, drefs, data, 6, sizes);
|
||||
closeUDP(sock);
|
||||
|
||||
// Tests
|
||||
if (result < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
// Verify sizes
|
||||
if (sizes[0] != 1 || sizes[1] != 1 || sizes[2] != 8
|
||||
|| sizes[3] != 4 || sizes[4] != 40 || sizes[5] != 1)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
// Verify integer drefs are integers
|
||||
if ((float)((int)data[0][0]) != data[0][0])
|
||||
{
|
||||
return -3;
|
||||
}
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
if ((float)((int)data[2][i]) != data[2][i])
|
||||
{
|
||||
return -3;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 40; ++i)
|
||||
{
|
||||
if ((float)((char)data[4][i]) != data[4][i])
|
||||
{
|
||||
return -3;
|
||||
}
|
||||
}
|
||||
// Verify tail number has at least one valid character
|
||||
if (data[4][0] <= 0 || data[4][0] > 127)
|
||||
{
|
||||
return -4;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int testDREF()
|
||||
{
|
||||
char* drefs[] =
|
||||
{
|
||||
"sim/cockpit/switches/gear_handle_status", //int
|
||||
"sim/cockpit/autopilot/altitude", //float
|
||||
"sim/aircraft/prop/acf_prop_type", //int[8]
|
||||
"sim/cockpit2/switches/panel_brightness_ratio", //float[4]
|
||||
"sim/aircraft/view/acf_tailnum", //byte[40]
|
||||
"sim/flightmodel/position/elevation" //double - Read only
|
||||
};
|
||||
float* values[6];
|
||||
float* expected[6];
|
||||
int sizes[6];
|
||||
|
||||
// Setup
|
||||
sizes[0] = 1;
|
||||
values[0] = (float*)malloc(sizes[0] * sizeof(float));
|
||||
expected[0] = values[0];
|
||||
values[0][0] = 1;
|
||||
|
||||
sizes[1] = 1;
|
||||
values[1] = (float*)malloc(sizes[1] * sizeof(float));
|
||||
expected[1] = values[1];
|
||||
values[1][0] = 4000.0F;
|
||||
|
||||
sizes[2] = 8;
|
||||
values[2] = (float*)malloc(sizes[2] * sizeof(float));
|
||||
expected[2] = values[2];
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
values[2][i] = 0;
|
||||
}
|
||||
|
||||
sizes[3] = 4;
|
||||
values[3] = (float*)malloc(sizes[3] * sizeof(float));
|
||||
expected[3] = values[3];
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
values[3][i] = 0.25F;
|
||||
}
|
||||
|
||||
sizes[4] = 40;
|
||||
values[4] = (float*)malloc(sizes[4] * sizeof(float));
|
||||
expected[4] = (float*)malloc(sizes[4] * sizeof(float));
|
||||
memset(values[4], 0, sizes[4] * sizeof(float));
|
||||
values[4][0] = 78.0F; //N
|
||||
values[4][1] = 55.0F; //7
|
||||
values[4][2] = 52.0F; //4
|
||||
values[4][3] = 56.0F; //8
|
||||
values[4][4] = 53.0F; //5
|
||||
values[4][5] = 89.0F; //Y
|
||||
|
||||
expected[4][0] = 78.0F; //N
|
||||
expected[4][1] = 55.0F; //7
|
||||
expected[4][2] = 52.0F; //4
|
||||
expected[4][3] = 56.0F; //8
|
||||
expected[4][4] = 53.0F; //5
|
||||
expected[4][5] = 89.0F; //Y
|
||||
for (int i = 6; i < sizes[4]; ++i)
|
||||
{
|
||||
expected[4][i] = NAN;
|
||||
}
|
||||
|
||||
sizes[5] = 1;
|
||||
values[5] = (float*)malloc(sizes[5] * sizeof(float));
|
||||
expected[5] = (float*)malloc(sizes[5] * sizeof(float));
|
||||
values[5][0] = 5000.0F;
|
||||
expected[5][0] = NAN;
|
||||
|
||||
return doDREFTest(drefs, values, expected, 6, sizes);
|
||||
}
|
||||
|
||||
#endif
|
||||
121
TestScripts/C Tests/PosiTests.h
Normal file
121
TestScripts/C Tests/PosiTests.h
Normal file
@@ -0,0 +1,121 @@
|
||||
//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
//National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#ifndef POSITESTS_H
|
||||
#define POSITESTS_H
|
||||
|
||||
#include "Test.h"
|
||||
#include "xplaneConnect.h"
|
||||
|
||||
int doPOSITest(char* drefs[7], float values[], int size, int ac, float expected[7])
|
||||
{
|
||||
float* data[7];
|
||||
int sizes[7];
|
||||
for (int i = 0; i < 7; ++i)
|
||||
{
|
||||
data[i] = (float*)malloc(sizeof(float) * 10);
|
||||
sizes[i] = 10;
|
||||
}
|
||||
|
||||
// Execute command
|
||||
XPCSocket sock = openUDP(IP);
|
||||
pauseSim(sock, 1);
|
||||
int result = sendPOSI(sock, values, size, ac);
|
||||
if (result >= 0)
|
||||
{
|
||||
result = getDREFs(sock, drefs, data, 7, sizes);
|
||||
}
|
||||
pauseSim(sock, 0);
|
||||
closeUDP(sock);
|
||||
if (result < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Test values
|
||||
float actual[7];
|
||||
for (int i = 0; i < 7; ++i)
|
||||
{
|
||||
actual[i] = data[i][0];
|
||||
}
|
||||
return compareArray(expected, actual, 7);
|
||||
}
|
||||
|
||||
int basicPOSITest(char** drefs, int ac)
|
||||
{
|
||||
// Set psoition and initial orientation
|
||||
float POSI[7] = { 37.524F, -122.06899F, 2500, 0, 0, 0, 1 };
|
||||
float expected[7] = { 37.524F, -122.06899F, 2500, 0, 0, 0, 1 };
|
||||
int result = doPOSITest(drefs, POSI, 7, ac, expected);
|
||||
if (result < 0)
|
||||
{
|
||||
return -10000 + result;
|
||||
}
|
||||
|
||||
// Set orientation
|
||||
POSI[0] = -998.0F;
|
||||
POSI[1] = -998.0F;
|
||||
POSI[2] = -998.0F;
|
||||
POSI[3] = 5.0F;
|
||||
POSI[4] = -5.0F;
|
||||
POSI[5] = 10.0F;
|
||||
POSI[6] = 0;
|
||||
|
||||
float *loc[3];
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
loc[i] = (float*)malloc(sizeof(float));
|
||||
}
|
||||
int sizes[3] = { 1, 1, 1 };
|
||||
XPCSocket sock = openUDP(IP);
|
||||
pauseSim(sock, 1);
|
||||
getDREFs(sock, drefs, loc, 3, sizes);
|
||||
closeUDP(sock);
|
||||
|
||||
expected[0] = loc[0][0];
|
||||
expected[1] = loc[1][0];
|
||||
expected[2] = loc[2][0];
|
||||
expected[3] = 5.0F;
|
||||
expected[4] = -5.0F;
|
||||
expected[5] = 10.0F;
|
||||
expected[6] = 0.0F;
|
||||
result = doPOSITest(drefs, POSI, 7, ac, expected);
|
||||
if (result < 0)
|
||||
{
|
||||
return -20000 + result;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int testPOSI_Player()
|
||||
{
|
||||
char* 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"
|
||||
};
|
||||
return basicPOSITest(drefs, 0);
|
||||
}
|
||||
|
||||
int testPOSI_NonPlayer()
|
||||
{
|
||||
char* drefs[] =
|
||||
{
|
||||
"sim/multiplayer/position/plane1_lat",
|
||||
"sim/multiplayer/position/plane1_lon",
|
||||
"sim/multiplayer/position/plane1_el",
|
||||
"sim/multiplayer/position/plane1_the",
|
||||
"sim/multiplayer/position/plane1_phi",
|
||||
"sim/multiplayer/position/plane1_psi",
|
||||
"sim/multiplayer/position/plane1_gear_deploy"
|
||||
};
|
||||
return basicPOSITest(drefs, 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
81
TestScripts/C Tests/SimuTests.h
Normal file
81
TestScripts/C Tests/SimuTests.h
Normal file
@@ -0,0 +1,81 @@
|
||||
//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
//National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#ifndef SIMUTESTS_H
|
||||
#define SIMIUTESTS_H
|
||||
|
||||
#include "Test.h"
|
||||
#include "xplaneConnect.h"
|
||||
|
||||
int doSIMUTest(int value, float expected)
|
||||
{
|
||||
int size = 20;
|
||||
float actual[20];
|
||||
char* dref = "sim/operation/override/override_planepath";
|
||||
|
||||
XPCSocket sock = openUDP(IP);
|
||||
int result = pauseSim(sock, value);
|
||||
if (result >= 0)
|
||||
{
|
||||
result = getDREF(sock, dref, &actual, &size);
|
||||
}
|
||||
closeUDP(sock);
|
||||
if (result < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 20; ++i)
|
||||
{
|
||||
if (!feq(actual[i], expected) && !isnan(expected))
|
||||
{
|
||||
return -100 - i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int testSIMU_Basic()
|
||||
{
|
||||
int result = doSIMUTest(0, 0);
|
||||
if (result < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
result = doSIMUTest(1, 1);
|
||||
if (result < 0)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
result = doSIMUTest(0, 0);
|
||||
if (result < 0)
|
||||
{
|
||||
return -3;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int testSIMU_Toggle()
|
||||
{
|
||||
int result = doSIMUTest(0, 0);
|
||||
if (result < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
result = doSIMUTest(2, 1);
|
||||
if (result < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
result = doSIMUTest(2, 0);
|
||||
if (result < 0)
|
||||
{
|
||||
return -3;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
51
TestScripts/C Tests/Test.c
Normal file
51
TestScripts/C Tests/Test.c
Normal file
@@ -0,0 +1,51 @@
|
||||
//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
//National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#include "Test.h"
|
||||
|
||||
int testFailed = 0;
|
||||
int testPassed = 0;
|
||||
|
||||
void runTest(int(*test)(), char* name)
|
||||
{
|
||||
printf("Running test %s... ", name);
|
||||
int result = test(); // Run Test
|
||||
if (result == 0)
|
||||
{
|
||||
printf("PASSED\n");
|
||||
testPassed++;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Test %s - FAILED\n\tError: %i\n", name, result);
|
||||
testFailed++;
|
||||
}
|
||||
}
|
||||
|
||||
int compareFloat(float expected, float actual)
|
||||
{
|
||||
return feq(expected, actual) || isnan(expected) ? 0 : -1;
|
||||
}
|
||||
|
||||
int compareArray(float expected[], float actual[], int size)
|
||||
{
|
||||
return compareArrays(&expected, &size, &actual, &size, 1);
|
||||
}
|
||||
|
||||
int compareArrays(float* expected[], int esizes[], float* actual[], int asizes[], int count)
|
||||
{
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
if (esizes[i] != asizes[i])
|
||||
{
|
||||
return -100 - i;
|
||||
}
|
||||
for (int j = 0; j < esizes[i]; ++j)
|
||||
{
|
||||
if (!feq(actual[i][j], expected[i][j]) && !isnan(expected[i][j]))
|
||||
{
|
||||
return -1000 - i * 100 - j;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
25
TestScripts/C Tests/Test.h
Normal file
25
TestScripts/C Tests/Test.h
Normal file
@@ -0,0 +1,25 @@
|
||||
//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
//National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#ifndef TESTRUNNER_H
|
||||
#define TESTRUNNER_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#define feq(x, y) (fabs(x - y) < 1e-4)
|
||||
|
||||
#define IP "127.0.0.1"
|
||||
|
||||
extern int testFailed;
|
||||
extern int testPassed;
|
||||
|
||||
void runTest(int(*test)(), char* name);
|
||||
|
||||
int compareFloat(float expected, float actual);
|
||||
int compareArray(float expected[], float actual[], int size);
|
||||
int compareArrays(float* expected[], int esizes[], float* actual[], int asizes[], int count);
|
||||
|
||||
#endif
|
||||
32
TestScripts/C Tests/TextTests.h
Normal file
32
TestScripts/C Tests/TextTests.h
Normal file
@@ -0,0 +1,32 @@
|
||||
//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
//National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#ifndef TEXTTESTS_H
|
||||
#define TEXTTESTS_H
|
||||
|
||||
#include "Test.h"
|
||||
#include "xplaneConnect.h"
|
||||
|
||||
int testTEXT()
|
||||
{
|
||||
// Setup
|
||||
XPCSocket sendPort = openUDP(IP);
|
||||
int x = 100;
|
||||
int y = 700;
|
||||
char* msg = "This is an X-Plane Connect test message.\nThis should be a new line.\r\nThat will be parsed as two line breaks.";
|
||||
|
||||
// Test
|
||||
sendTEXT(sendPort, msg, x, y);
|
||||
// NOTE: Manually verify that msg appears on the screen in X-Plane!
|
||||
|
||||
sendTEXT(sendPort, "Another test message", x, y);
|
||||
// NOTE: Manually verify that msg appears on the screen and that no part of the previous
|
||||
// message is visible.
|
||||
|
||||
sendTEXT(sendPort, NULL, -1, -1);
|
||||
|
||||
// Cleanup
|
||||
closeUDP(sendPort);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
55
TestScripts/C Tests/UDPTests.h
Normal file
55
TestScripts/C Tests/UDPTests.h
Normal file
@@ -0,0 +1,55 @@
|
||||
//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
//National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#ifndef UDPTESTS_H
|
||||
#define UDPTESTS_H
|
||||
|
||||
#include "Test.h"
|
||||
#include "xplaneConnect.h"
|
||||
|
||||
int testOpen()
|
||||
{
|
||||
XPCSocket sock = openUDP("localhost");
|
||||
int result = strncmp(sock.xpIP, "127.0.0.1", 16);
|
||||
closeUDP(sock);
|
||||
return result;
|
||||
}
|
||||
|
||||
int testClose()
|
||||
{
|
||||
XPCSocket sendPort = aopenUDP(IP, 49009, 49063);
|
||||
closeUDP(sendPort);
|
||||
sendPort = aopenUDP(IP, 49009, 49063);
|
||||
closeUDP(sendPort);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int testCONN()
|
||||
{
|
||||
// Initialize
|
||||
char* drefs[] =
|
||||
{
|
||||
"sim/cockpit/switches/gear_handle_status"
|
||||
};
|
||||
float data[1];
|
||||
int size = 1;
|
||||
XPCSocket sock = openUDP(IP);
|
||||
#if (__APPLE__ || __linux)
|
||||
usleep(0);
|
||||
#endif
|
||||
|
||||
// Execution
|
||||
setCONN(&sock, 49055);
|
||||
int result = getDREF(sock, drefs[0], data, &size);
|
||||
|
||||
// Close
|
||||
closeUDP(sock);
|
||||
|
||||
// Test
|
||||
if (result < 0)// No data received
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
73
TestScripts/C Tests/ViewTests.h
Normal file
73
TestScripts/C Tests/ViewTests.h
Normal file
@@ -0,0 +1,73 @@
|
||||
//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
//National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#ifndef VIEWTESTS_H
|
||||
#define VIEWTESTS_H
|
||||
|
||||
#include "Test.h"
|
||||
#include "xplaneConnect.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
XPC_VDREF_FORWARDS = 1000,
|
||||
XPC_VDREF_DOWN4 = 1001,
|
||||
XPC_VDREF_DOWN8 = 1002,
|
||||
XPC_VDREF_LEFT45 = 1004,
|
||||
XPC_VDREF_RIGHT45 = 1005,
|
||||
XPC_VDREF_LEFT90 = 1006,
|
||||
XPC_VDREF_RIGHT90 = 1007,
|
||||
XPC_VDREF_LEFT135 = 1008,
|
||||
XPC_VDREF_RIGHT135 = 1009,
|
||||
XPC_VDREF_BACKWARD = 1010,
|
||||
XPC_VDREF_LEFTUP = 1011,
|
||||
XPC_VDREF_RIGHTUP = 1012,
|
||||
XPC_VDREF_AIRPORTBEACONTOWER = 1014,
|
||||
XPC_VDREF_ONRUNWAY = 1015,
|
||||
XPC_VDREF_CHASE = 1017,
|
||||
XPC_VDREF_FOLLOW = 1018,
|
||||
XPC_VDREF_FOLLOWWITHPANEL = 1019,
|
||||
XPC_VDREF_SPOT = 1020,
|
||||
XPC_VDREF_SPOTMOVING = 1021,
|
||||
XPC_VDREF_FULLSCREENWITHHUD = 1023,
|
||||
XPC_VDREF_FULLSCREENNOHUD = 1024,
|
||||
XPC_VDREF_STRAIGHTDOWN = 1025,
|
||||
XPC_VDREF_3DCOCKPIT = 1026
|
||||
} VIEW_DREF;
|
||||
|
||||
int doViewTest(VIEW_TYPE viewCommand, VIEW_DREF viewResult)
|
||||
{
|
||||
// Setup
|
||||
char* dref = "sim/graphics/view/view_type";
|
||||
float value;
|
||||
int size = 1;
|
||||
|
||||
// Execute command
|
||||
XPCSocket sock = openUDP(IP);
|
||||
int result = sendVIEW(sock, viewCommand);
|
||||
if (result >= 0)
|
||||
{
|
||||
result = getDREF(sock, dref, &value, &size);
|
||||
}
|
||||
closeUDP(sock);
|
||||
if (result < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((int)value != viewResult)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int testView()
|
||||
{
|
||||
int result = doViewTest(XPC_VIEW_FORWARDS, XPC_VDREF_FORWARDS);
|
||||
if (result < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return doViewTest(XPC_VIEW_CHASE, XPC_VDREF_CHASE);
|
||||
}
|
||||
#endif
|
||||
42
TestScripts/C Tests/WyptTests.h
Normal file
42
TestScripts/C Tests/WyptTests.h
Normal file
@@ -0,0 +1,42 @@
|
||||
//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
//National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#ifndef WYPTTESTS_H
|
||||
#define WYPTTESTS_H
|
||||
|
||||
#include "Test.h"
|
||||
#include "xplaneConnect.h"
|
||||
|
||||
int testWYPT()
|
||||
{
|
||||
// Setup
|
||||
XPCSocket sock = openUDP(IP);
|
||||
float points[] =
|
||||
{
|
||||
37.5245F, -122.06899F, 2500,
|
||||
37.455397F, -122.050037F, 2500,
|
||||
37.469567F, -122.051411F, 2500,
|
||||
37.479376F, -122.060509F, 2300,
|
||||
37.482237F, -122.076130F, 2100,
|
||||
37.474881F, -122.087288F, 1900,
|
||||
37.467660F, -122.079391F, 1700,
|
||||
37.466298F, -122.090549F, 1500,
|
||||
37.362562F, -122.039223F, 1000,
|
||||
37.361448F, -122.034416F, 1000,
|
||||
37.361994F, -122.026348F, 1000,
|
||||
37.365541F, -122.022572F, 1000,
|
||||
37.373727F, -122.024803F, 1000,
|
||||
37.403869F, -122.041283F, 50,
|
||||
37.418544F, -122.049222F, 6
|
||||
};
|
||||
|
||||
// Test
|
||||
sendWYPT(sock, XPC_WYPT_CLR, NULL, 0);
|
||||
sendWYPT(sock, XPC_WYPT_ADD, points, 15);
|
||||
// NOTE: Visually ensure waypoints are added in the sim
|
||||
|
||||
// Cleanup
|
||||
closeUDP(sock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,930 +1,15 @@
|
||||
//
|
||||
// main.cpp
|
||||
// XPC Tests
|
||||
//
|
||||
// Created by Chris Teubert on 11/25/14.
|
||||
// Copyright (c) 2014 Chris Teubert. All rights reserved.
|
||||
//
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "xplaneConnect.h"
|
||||
|
||||
#define IP "127.0.0.1"
|
||||
|
||||
int testFailed = 0;
|
||||
int testPassed = 0;
|
||||
|
||||
void runTest(int (*test)(), char* name)
|
||||
{
|
||||
int result = test(); // Run Test
|
||||
printf("Test %i: %s - ", testPassed + testFailed + 1, name);
|
||||
if (result == 0)
|
||||
{
|
||||
printf("PASSED\n");
|
||||
testPassed++;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("FAILED\n\tError: %i\n", result);
|
||||
testFailed++;
|
||||
}
|
||||
}
|
||||
|
||||
int openTest() // openUDP Test
|
||||
{
|
||||
XPCSocket sock = openUDP("localhost");
|
||||
int result = strncmp(sock.xpIP, "127.0.0.1", 16);
|
||||
closeUDP(sock);
|
||||
return result;
|
||||
}
|
||||
|
||||
int closeTest() // closeUDP test
|
||||
{
|
||||
XPCSocket sendPort = aopenUDP(IP, 49009, 49063);
|
||||
closeUDP(sendPort);
|
||||
sendPort = aopenUDP(IP, 49009, 49063);
|
||||
closeUDP(sendPort);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sendTEXTTest()
|
||||
{
|
||||
// Setup
|
||||
XPCSocket sendPort = openUDP(IP);
|
||||
int x = 100;
|
||||
int y = 700;
|
||||
char* msg = "This is an X-Plane Connect test message.\nThis should be a new line.\r\nThat will be parsed as two line breaks.";
|
||||
|
||||
// Test
|
||||
sendTEXT(sendPort, msg, x, y);
|
||||
// NOTE: Manually verify that msg appears on the screen in X-Plane!
|
||||
|
||||
sendTEXT(sendPort, "Another test message", x, y);
|
||||
// NOTE: Manually verify that msg appears on the screen and that no part of the previous
|
||||
// message is visible.
|
||||
|
||||
sendTEXT(sendPort, NULL, -1, -1);
|
||||
|
||||
// Cleanup
|
||||
closeUDP(sendPort);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getDREFTest() // Request DREF Test (Required for next tests)
|
||||
{
|
||||
// Initialization
|
||||
// Get one DREF of each type (int, float, int[], float[], double, byte[])
|
||||
#define GETD_COUNT 6
|
||||
char* drefs[GETD_COUNT] =
|
||||
{
|
||||
"sim/cockpit/switches/gear_handle_status", //int
|
||||
"sim/cockpit/autopilot/altitude", //float
|
||||
"sim/aircraft/prop/acf_prop_type", //int[8]
|
||||
"sim/cockpit2/switches/panel_brightness_ratio", //float[4]
|
||||
"sim/aircraft/view/acf_tailnum", //byte[40]
|
||||
"sim/flightmodel/position/elevation" //double
|
||||
};
|
||||
float* data[GETD_COUNT];
|
||||
int sizes[GETD_COUNT];
|
||||
XPCSocket sock = openUDP(IP);
|
||||
|
||||
// Setup
|
||||
for (int i = 0; i < GETD_COUNT; ++i)
|
||||
{
|
||||
data[i] = (float*)malloc(256 * sizeof(float));
|
||||
sizes[i] = 256;
|
||||
}
|
||||
|
||||
// Execution
|
||||
int result = getDREFs(sock, drefs, data, GETD_COUNT, sizes);
|
||||
|
||||
// Close
|
||||
closeUDP(sock);
|
||||
|
||||
// Tests
|
||||
if (result < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
// Verify sizes
|
||||
if (sizes[0] != 1 || sizes[1] != 1 || sizes[2] != 8
|
||||
|| sizes[3] != 4 || sizes[4] != 40 || sizes[5] != 1)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
// Verify integer drefs are integers
|
||||
if ((float)((int)data[0][0]) != data[0][0])
|
||||
{
|
||||
return -3;
|
||||
}
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
if ((float)((int)data[2][i]) != data[2][i])
|
||||
{
|
||||
return -3;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 40; ++i)
|
||||
{
|
||||
if ((float)((char)data[4][i]) != data[4][i])
|
||||
{
|
||||
return -3;
|
||||
}
|
||||
}
|
||||
// Verify tail number has at least one valid character
|
||||
if (data[4][0] <= 0 || data[4][0] > 127)
|
||||
{
|
||||
return -4;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sendDREFTest() // sendDREF test
|
||||
{
|
||||
// Initialization
|
||||
// Set one DREF of each type (int, float, int[], float[], double, byte[])
|
||||
// Also set one read-only to make sure it fails
|
||||
#define DREF_COUNT 6
|
||||
char* drefs[DREF_COUNT] =
|
||||
{
|
||||
"sim/cockpit/switches/gear_handle_status", //int
|
||||
"sim/cockpit/autopilot/altitude", //float
|
||||
"sim/aircraft/prop/acf_prop_type", //int[8]
|
||||
"sim/cockpit2/switches/panel_brightness_ratio", //float[4]
|
||||
"sim/aircraft/view/acf_tailnum", //byte[40]
|
||||
"sim/flightmodel/position/elevation" //double - Read only
|
||||
};
|
||||
float* data[DREF_COUNT];
|
||||
int sizes[DREF_COUNT];
|
||||
float* values[DREF_COUNT];
|
||||
XPCSocket sock = openUDP(IP);
|
||||
|
||||
// Setup
|
||||
sizes[0] = 1;
|
||||
values[0] = (float*)malloc(sizes[0] * sizeof(float));
|
||||
values[0][0] = 1;
|
||||
|
||||
sizes[1] = 1;
|
||||
values[1] = (float*)malloc(sizes[1] * sizeof(float));
|
||||
values[1][0] = 4000.0F;
|
||||
|
||||
sizes[2] = 8;
|
||||
values[2] = (float*)malloc(sizes[2] * sizeof(float));
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
values[2][i] = 0;
|
||||
}
|
||||
|
||||
sizes[3] = 4;
|
||||
values[3] = (float*)malloc(sizes[3] * sizeof(float));
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
values[3][i] = 0.25F;
|
||||
}
|
||||
|
||||
sizes[4] = 40;
|
||||
values[4] = (float*)malloc(sizes[4] * sizeof(float));
|
||||
memset(values[4], 0, sizes[4] * sizeof(float));
|
||||
values[4][0] = 78.0F; //N
|
||||
values[4][1] = 55.0F; //7
|
||||
values[4][2] = 52.0F; //4
|
||||
values[4][3] = 56.0F; //8
|
||||
values[4][4] = 53.0F; //5
|
||||
values[4][5] = 89.0F; //Y
|
||||
|
||||
sizes[5] = 1;
|
||||
values[5] = (float*)malloc(sizes[5] * sizeof(float));
|
||||
values[5][0] = 5000.0F;
|
||||
|
||||
// Execution
|
||||
for (int i = 0; i < DREF_COUNT; ++i)
|
||||
{
|
||||
sendDREF(sock, drefs[i], values[i], sizes[i]);
|
||||
data[i] = (float*)malloc(256 * sizeof(float));
|
||||
sizes[i] = 256;
|
||||
}
|
||||
int result = getDREFs(sock, drefs, data, DREF_COUNT, sizes);
|
||||
|
||||
// Close
|
||||
closeUDP(sock);
|
||||
|
||||
// Tests
|
||||
if (result < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
// Verify gear handle was set
|
||||
if (sizes[0] != 1 || data[0][0] != 1)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
// Verify autopilot altitude was set
|
||||
if (sizes[1] != 1 || data[1][0] != 4000.0F)
|
||||
{
|
||||
return -3;
|
||||
}
|
||||
// Verify prop type was set
|
||||
if (sizes[2] != 8)
|
||||
{
|
||||
return -4;
|
||||
}
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
if (data[2][i] != values[2][i])
|
||||
{
|
||||
return -4;
|
||||
}
|
||||
}
|
||||
// Verify panel brightness was set
|
||||
if (sizes[3] != 4)
|
||||
{
|
||||
return -5;
|
||||
}
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
if (data[3][i] != values[3][i])
|
||||
{
|
||||
return -5;
|
||||
}
|
||||
}
|
||||
// Verify tail number was set
|
||||
for (int i = 0; i < 6; ++i)
|
||||
{
|
||||
if (data[4][i] != values[4][i])
|
||||
{
|
||||
return -6;
|
||||
}
|
||||
}
|
||||
// Verify aircraft elevation was NOT set
|
||||
if (sizes[5] != 1 || data[5][0] == 5000.0F)
|
||||
{
|
||||
return -7;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sendDATATest() // sendDATA test
|
||||
{
|
||||
// Initialize
|
||||
int i,j; // Iterator
|
||||
char* drefs[100] =
|
||||
{
|
||||
"sim/aircraft/parts/acf_gear_deploy"
|
||||
};
|
||||
float* data[100]; // array for result of getDREFs
|
||||
int sizes[100];
|
||||
float DATA[4][9]; // Array for sendDATA
|
||||
XPCSocket sock = openUDP(IP);
|
||||
|
||||
// Setup
|
||||
for (int i = 0; i < 100; ++i)
|
||||
{
|
||||
data[i] = (float*)malloc(40 * sizeof(float));
|
||||
sizes[i] = 40;
|
||||
}
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
for (j = 0; j < 9; j++)
|
||||
{
|
||||
data[i][j] = -998;
|
||||
}
|
||||
}
|
||||
DATA[0][0] = 14; // Gear
|
||||
DATA[0][1] = 1;
|
||||
DATA[0][2] = 0;
|
||||
|
||||
// Execution
|
||||
sendDATA(sock, DATA, 1);
|
||||
int result = getDREFs(sock, drefs, data, 1, sizes);
|
||||
|
||||
// Close
|
||||
closeUDP(sock);
|
||||
|
||||
// Tests
|
||||
if ( result < 0 )// Request 1 value
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (sizes[0] != 10)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
if (*data[0] != data[0][1])
|
||||
{
|
||||
return -3;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int psendCTRLTest() // sendCTRL test
|
||||
{
|
||||
// Initialize
|
||||
char* drefs[100] =
|
||||
{
|
||||
"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"
|
||||
};
|
||||
float* data[100];
|
||||
int sizes[100];
|
||||
float CTRL[6] = { 0.0F, 0.0F, 0.0F, 0.8F, 1.0F, 0.5F };
|
||||
XPCSocket sock = openUDP(IP);
|
||||
|
||||
// Setup
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
data[i] = (float*)malloc(40 * sizeof(float));
|
||||
sizes[i] = 40;
|
||||
}
|
||||
|
||||
// Execute 1
|
||||
// 0 pitch, roll, yaw
|
||||
sendCTRL(sock, CTRL, 3, 0);
|
||||
int result = getDREFs(sock, drefs, data, 6, sizes);
|
||||
|
||||
// Close socket
|
||||
closeUDP(sock);
|
||||
|
||||
// Tests
|
||||
if (result < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
if (fabs(data[i][0] - CTRL[i]) > 1e-4)
|
||||
{
|
||||
return -i - 11;
|
||||
}
|
||||
}
|
||||
|
||||
sock = openUDP(IP);
|
||||
// Execute 2
|
||||
// Set non-zero pitch, roll, & yaw. Also set throttle, gear, and flaps
|
||||
CTRL[0] = 0.2F;
|
||||
CTRL[1] = 0.1F;
|
||||
CTRL[2] = 0.1F;
|
||||
sendCTRL(sock, CTRL, 6, 0);
|
||||
result = getDREFs(sock, drefs, data, 6, sizes);
|
||||
|
||||
// Close socket
|
||||
closeUDP(sock);
|
||||
|
||||
// Tests
|
||||
if (result < 0)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
if (fabs(data[i][0] - CTRL[i]) > 1e-4)
|
||||
{
|
||||
return -i - 21;
|
||||
}
|
||||
}
|
||||
|
||||
sock = openUDP(IP);
|
||||
// Execute 2
|
||||
// Set non-zero pitch, roll, & yaw. Also set throttle, gear, and flaps
|
||||
CTRL[0] = -998.0F;
|
||||
CTRL[1] = -998.0F;
|
||||
CTRL[2] = -998.0F;
|
||||
sendCTRL(sock, CTRL, 6, 0);
|
||||
result = getDREFs(sock, drefs, data, 6, sizes);
|
||||
|
||||
// Close socket
|
||||
closeUDP(sock);
|
||||
|
||||
// Tests
|
||||
if (result < 0)
|
||||
{
|
||||
return -3;
|
||||
}
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
if (fabs(data[i][0] - CTRL[i]) > 1e-2)
|
||||
{
|
||||
return -i - 31;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sendCTRLTest()
|
||||
{
|
||||
// Initialize
|
||||
char* drefs[100] =
|
||||
{
|
||||
"sim/multiplayer/position/plane1_yolk_pitch",
|
||||
"sim/multiplayer/position/plane1_yolk_roll",
|
||||
"sim/multiplayer/position/plane1_yolk_yaw",
|
||||
"sim/multiplayer/position/plane1_throttle",
|
||||
"sim/multiplayer/position/plane1_gear_deploy",
|
||||
"sim/multiplayer/position/plane1_flap_ratio",
|
||||
};
|
||||
float* data[100];
|
||||
int sizes[100];
|
||||
float CTRL[6] = { 0.0F, 0.0F, 0.0F, 0.8F, 1.0F, 0.5F };
|
||||
XPCSocket sock = openUDP(IP);
|
||||
|
||||
// Setup
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
data[i] = (float*)malloc(40 * sizeof(float));
|
||||
sizes[i] = 40;
|
||||
}
|
||||
|
||||
// Execute 1
|
||||
// 0 pitch, roll, yaw
|
||||
sendCTRL(sock, CTRL, 3, 1);
|
||||
int result = getDREFs(sock, drefs, data, 6, sizes);
|
||||
|
||||
// Close socket
|
||||
closeUDP(sock);
|
||||
|
||||
// Tests
|
||||
if (result < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
if (fabs(data[i][0] - CTRL[i]) > 1e-4)
|
||||
{
|
||||
return -i - 11;
|
||||
}
|
||||
}
|
||||
|
||||
sock = openUDP(IP);
|
||||
// Execute 2
|
||||
// Set non-zero pitch, roll, & yaw. Also set throttle, gear, and flaps
|
||||
CTRL[0] = 0.2F;
|
||||
CTRL[1] = 0.1F;
|
||||
CTRL[2] = 0.1F;
|
||||
sendCTRL(sock, CTRL, 6, 1);
|
||||
result = getDREFs(sock, drefs, data, 6, sizes);
|
||||
|
||||
// Close socket
|
||||
closeUDP(sock);
|
||||
|
||||
// Tests
|
||||
if (result < 0)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
if (fabs(data[i][0] - CTRL[i]) > 1e-4)
|
||||
{
|
||||
return -i - 21;
|
||||
}
|
||||
}
|
||||
|
||||
sock = openUDP(IP);
|
||||
// Execute 2
|
||||
// Set non-zero pitch, roll, & yaw. Also set throttle, gear, and flaps
|
||||
CTRL[0] = -998.0F;
|
||||
CTRL[1] = -998.0F;
|
||||
CTRL[2] = -998.0F;
|
||||
sendCTRL(sock, CTRL, 6, 1);
|
||||
result = getDREFs(sock, drefs, data, 6, sizes);
|
||||
|
||||
// Close socket
|
||||
closeUDP(sock);
|
||||
|
||||
// Tests
|
||||
if (result < 0)
|
||||
{
|
||||
return -3;
|
||||
}
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
if (fabs(data[i][0] - CTRL[i]) > 1e-2)
|
||||
{
|
||||
return -i - 31;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int psendPOSITest() // sendPOSI test
|
||||
{
|
||||
// Initialization
|
||||
int i; // Iterator
|
||||
char* drefs[100] =
|
||||
{
|
||||
"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"
|
||||
};
|
||||
float* data[100];
|
||||
int sizes[100];
|
||||
float POSI[7] = { 37.524F, -122.06899F, 2500, 0, 0, 0, 1 };
|
||||
XPCSocket sock = openUDP(IP);
|
||||
|
||||
// Setup
|
||||
for (i = 0; i < 100; i++)
|
||||
{
|
||||
data[i] = (float*)malloc(40 * sizeof(float));
|
||||
sizes[i] = 40;
|
||||
}
|
||||
|
||||
// Execution 1
|
||||
pauseSim(sock, 1);
|
||||
sendPOSI(sock, POSI, 7, 0);
|
||||
int result = getDREFs(sock, drefs, data, 7, sizes);
|
||||
pauseSim(sock, 0);
|
||||
|
||||
// Close
|
||||
closeUDP(sock);
|
||||
|
||||
// Tests
|
||||
if (result < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
for (i = 0; i < 7; ++i)
|
||||
{
|
||||
if (fabs(data[i][0] - POSI[i]) > 1e-4)
|
||||
{
|
||||
return -i - 11;
|
||||
}
|
||||
}
|
||||
|
||||
// Setup 2
|
||||
sock = openUDP(IP);
|
||||
POSI[0] = -998.0F;
|
||||
POSI[1] = -998.0F;
|
||||
POSI[2] = -998.0F;
|
||||
POSI[3] = 5.0F;
|
||||
POSI[4] = -5.0F;
|
||||
POSI[5] = 10.0F;
|
||||
POSI[6] = 0;
|
||||
|
||||
// Execution 2
|
||||
pauseSim(sock, 1);
|
||||
float *loc[3];
|
||||
for(int i = 0; i < 3; ++i)
|
||||
{
|
||||
loc[i] = (float*)malloc(sizeof(float));
|
||||
}
|
||||
getDREFs(sock, drefs, &loc, 3, sizes);
|
||||
sendPOSI(sock, POSI, 7, 0);
|
||||
result = getDREFs(sock, drefs, data, 7, sizes);
|
||||
pauseSim(sock, 0);
|
||||
|
||||
// Close
|
||||
closeUDP(sock);
|
||||
|
||||
// Tests
|
||||
if (result < 0)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
// Compare position to make sure they weren't set
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
// Note: Because the sim was paused when both of these were read, we really do expect *exactly*
|
||||
// the same value even though we are comparing floats.
|
||||
if (data[i][0] != loc[i][0])
|
||||
{
|
||||
return -i - 21;
|
||||
}
|
||||
}
|
||||
// Compare everything else.
|
||||
for (i = 3; i < 7; ++i)
|
||||
{
|
||||
if (fabs(data[i][0] - POSI[i]) > 1e-4)
|
||||
{
|
||||
return -i - 21;
|
||||
}
|
||||
}
|
||||
|
||||
// Setup 3
|
||||
sock = openUDP(IP);
|
||||
POSI[0] = 37.524F;
|
||||
POSI[1] = -122.06899F;
|
||||
POSI[2] = 20000;
|
||||
POSI[3] = 15.0F;
|
||||
POSI[4] = -25.0F;
|
||||
POSI[5] = -10.0F;
|
||||
POSI[6] = 1;
|
||||
|
||||
// Execution 2
|
||||
pauseSim(sock, 1);
|
||||
sendPOSI(sock, POSI, 3, 0);
|
||||
result = getDREFs(sock, drefs, data, 7, sizes);
|
||||
pauseSim(sock, 0);
|
||||
|
||||
// Close
|
||||
closeUDP(sock);
|
||||
|
||||
// Tests
|
||||
if (result < 0)
|
||||
{
|
||||
return -3;
|
||||
}
|
||||
// Compare position to make sure it was set.
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
if (fabs(data[i][0] - POSI[i]) > 1e-4)
|
||||
{
|
||||
return -i - 31;
|
||||
}
|
||||
}
|
||||
// Compare everything else to make sure it *wasn't*.
|
||||
for (i = 3; i < 7; ++i)
|
||||
{
|
||||
if (fabs(data[i][0] - POSI[i]) < 1)
|
||||
{
|
||||
return -i - 31;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sendPOSITest() // sendPOSI test
|
||||
{
|
||||
// Initialization
|
||||
int i; // Iterator
|
||||
char* drefs[100] =
|
||||
{
|
||||
// TODO: Can't get global position for multiplayer a/c?
|
||||
"sim/multiplayer/position/plane1_lat",
|
||||
"sim/multiplayer/position/plane1_lon",
|
||||
"sim/multiplayer/position/plane1_el",
|
||||
"sim/multiplayer/position/plane1_the",
|
||||
"sim/multiplayer/position/plane1_phi",
|
||||
"sim/multiplayer/position/plane1_psi",
|
||||
"sim/multiplayer/position/plane1_gear_deploy"
|
||||
};
|
||||
float* data[100];
|
||||
int sizes[100];
|
||||
float POSI[7] = { 37.524F, -122.06899F, 2500, 0, 0, 0, 1 };
|
||||
XPCSocket sock = openUDP(IP);
|
||||
|
||||
// Setup
|
||||
for (i = 0; i < 100; i++)
|
||||
{
|
||||
data[i] = (float*)malloc(40 * sizeof(float));
|
||||
sizes[i] = 40;
|
||||
}
|
||||
|
||||
// Execution 1
|
||||
pauseSim(sock, 1);
|
||||
sendPOSI(sock, POSI, 7, 1);
|
||||
int result = getDREFs(sock, drefs, data, 7, sizes);
|
||||
pauseSim(sock, 0);
|
||||
|
||||
// Close
|
||||
closeUDP(sock);
|
||||
|
||||
// Tests
|
||||
if (result < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
for (i = 0; i < 7; ++i)
|
||||
{
|
||||
if (fabs(data[i][0] - POSI[i]) > 1e-4)
|
||||
{
|
||||
return -i - 11;
|
||||
}
|
||||
}
|
||||
|
||||
// Setup 2
|
||||
sock = openUDP(IP);
|
||||
POSI[0] = -998.0F;
|
||||
POSI[1] = -998.0F;
|
||||
POSI[2] = -998.0F;
|
||||
POSI[3] = 5.0F;
|
||||
POSI[4] = -5.0F;
|
||||
POSI[5] = 10.0F;
|
||||
POSI[6] = 0;
|
||||
|
||||
// Execution 2
|
||||
pauseSim(sock, 1);
|
||||
float* loc[3];
|
||||
for(int i = 0; i < 3; ++i)
|
||||
{
|
||||
loc[i] = (float*)malloc(sizeof(float));
|
||||
}
|
||||
getDREFs(sock, drefs, loc, 3, sizes);
|
||||
sendPOSI(sock, POSI, 7, 1);
|
||||
result = getDREFs(sock, drefs, data, 7, sizes);
|
||||
pauseSim(sock, 0);
|
||||
|
||||
// Close
|
||||
closeUDP(sock);
|
||||
|
||||
// Tests
|
||||
if (result < 0)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
// Compare position to make sure they weren't set
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
// Note: Because the sim was paused when both of these were read, we really do expect *exactly*
|
||||
// the same value even though we are comparing floats.
|
||||
if (data[i][0] != loc[i][0])
|
||||
{
|
||||
return -i - 21;
|
||||
}
|
||||
}
|
||||
// Compare everything else.
|
||||
for (i = 3; i < 7; ++i)
|
||||
{
|
||||
if (fabs(data[i][0] - POSI[i]) > 1e-4)
|
||||
{
|
||||
return -i - 21;
|
||||
}
|
||||
}
|
||||
|
||||
// Setup 3
|
||||
sock = openUDP(IP);
|
||||
POSI[0] = 37.524F;
|
||||
POSI[1] = -122.06899;
|
||||
POSI[2] = 20000;
|
||||
POSI[3] = 15.0F;
|
||||
POSI[4] = -25.0F;
|
||||
POSI[5] = -10.0F;
|
||||
POSI[6] = 1;
|
||||
|
||||
// Execution 2
|
||||
pauseSim(sock, 1);
|
||||
sendPOSI(sock, POSI, 3, 1);
|
||||
result = getDREFs(sock, drefs, data, 7, sizes);
|
||||
pauseSim(sock, 0);
|
||||
|
||||
// Close
|
||||
closeUDP(sock);
|
||||
|
||||
// Tests
|
||||
if (result < 0)
|
||||
{
|
||||
return -3;
|
||||
}
|
||||
// Compare position to make sure it was set.
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
if (fabs(data[i][0] - POSI[i]) > 1e-4)
|
||||
{
|
||||
return -i - 31;
|
||||
}
|
||||
}
|
||||
// Compare everything else to make sure it *wasn't*.
|
||||
for (i = 3; i < 7; ++i)
|
||||
{
|
||||
if (fabs(data[i][0] - POSI[i]) < 1)
|
||||
{
|
||||
return -i - 31;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sendWYPTTest()
|
||||
{
|
||||
// Setup
|
||||
XPCSocket sock = openUDP(IP);
|
||||
float points[] =
|
||||
{
|
||||
37.5245F, -122.06899F, 2500,
|
||||
37.455397F, -122.050037F, 2500,
|
||||
37.469567F, -122.051411F, 2500,
|
||||
37.479376F, -122.060509F, 2300,
|
||||
37.482237F, -122.076130F, 2100,
|
||||
37.474881F, -122.087288F, 1900,
|
||||
37.467660F, -122.079391F, 1700,
|
||||
37.466298F, -122.090549F, 1500,
|
||||
37.362562F, -122.039223F, 1000,
|
||||
37.361448F, -122.034416F, 1000,
|
||||
37.361994F, -122.026348F, 1000,
|
||||
37.365541F, -122.022572F, 1000,
|
||||
37.373727F, -122.024803F, 1000,
|
||||
37.403869F, -122.041283F, 50,
|
||||
37.418544F, -122.049222F, 6
|
||||
};
|
||||
|
||||
// Test
|
||||
sendWYPT(sock, XPC_WYPT_CLR, NULL, 0);
|
||||
sendWYPT(sock, XPC_WYPT_ADD, points, 15);
|
||||
// NOTE: Visually ensure waypoints are added in the sim
|
||||
|
||||
// Cleanup
|
||||
closeUDP(sock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pauseTest() // pauseSim test
|
||||
{
|
||||
// Initialize
|
||||
// Note: Always run this test to the end so that the sim ends up unpaused in the
|
||||
// case where commands are working but reading results isn't.
|
||||
int result = 0;
|
||||
char* drefs[100] =
|
||||
{
|
||||
"sim/operation/override/override_planepath"
|
||||
};
|
||||
float* data[100];
|
||||
int sizes[100];
|
||||
XPCSocket sock = openUDP(IP);
|
||||
|
||||
// Setup
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
data[i] = (float*)malloc(40 * sizeof(float));
|
||||
sizes[i] = 40;
|
||||
}
|
||||
|
||||
// Execute
|
||||
pauseSim(sock, 1);
|
||||
result = getDREF(sock, drefs[0], data[0], sizes);
|
||||
|
||||
// Test
|
||||
if (result < 0)
|
||||
{
|
||||
result = -1;
|
||||
}
|
||||
if (data[0][0] != 1)
|
||||
{
|
||||
result = -2;
|
||||
}
|
||||
|
||||
if (result == 0)
|
||||
{
|
||||
// Execute 2
|
||||
pauseSim(sock, 0);
|
||||
result = getDREF(sock, drefs[0], data[0], sizes);
|
||||
|
||||
// Test 2
|
||||
if (result < 0)
|
||||
{
|
||||
result = -3;
|
||||
}
|
||||
if (data[0][0] != 0)
|
||||
{
|
||||
result = -4;
|
||||
}
|
||||
}
|
||||
|
||||
// Close
|
||||
closeUDP(sock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int connTest() // setConn test
|
||||
{
|
||||
// Initialize
|
||||
char* drefs[100] =
|
||||
{
|
||||
"sim/cockpit/switches/gear_handle_status"
|
||||
};
|
||||
float* data[100];
|
||||
int sizes[100];
|
||||
XPCSocket sock = openUDP(IP);
|
||||
#if (__APPLE__ || __linux)
|
||||
usleep(0);
|
||||
#endif
|
||||
|
||||
// Setup
|
||||
for (int i = 0; i < 100; ++i)
|
||||
{
|
||||
data[i] = (float*)malloc(40 * sizeof(float));
|
||||
sizes[i] = 40;
|
||||
}
|
||||
|
||||
// Execution
|
||||
setCONN(&sock, 49055);
|
||||
int result = getDREF(sock, drefs[0], data[0], sizes);
|
||||
|
||||
// Close
|
||||
closeUDP(sock);
|
||||
|
||||
// Test
|
||||
if ( result < 0 )// No data received
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
//National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#include "Test.h"
|
||||
#include "UDPTests.h"
|
||||
#include "DrefTests.h"
|
||||
#include "SimuTests.h"
|
||||
#include "CtrlTests.h"
|
||||
#include "PosiTests.h"
|
||||
#include "DataTests.h"
|
||||
#include "TextTests.h"
|
||||
#include "ViewTests.h"
|
||||
#include "WyptTests.h"
|
||||
|
||||
int main(int argc, const char * argv[])
|
||||
{
|
||||
@@ -936,23 +21,42 @@ int main(int argc, const char * argv[])
|
||||
printf("(Mac) \n");
|
||||
#elif (__linux)
|
||||
printf("(Linux) \n");
|
||||
#else
|
||||
printf("(Unable to determine operating system) \n")
|
||||
#endif
|
||||
|
||||
runTest(openTest, "open");
|
||||
runTest(closeTest, "close");
|
||||
runTest(pauseTest, "SIMU");
|
||||
runTest(getDREFTest, "GETD");
|
||||
runTest(sendDREFTest, "DREF");
|
||||
runTest(sendDATATest, "DATA");
|
||||
runTest(sendCTRLTest, "CTRL");
|
||||
runTest(psendCTRLTest, "CTRL (player)");
|
||||
runTest(sendPOSITest, "POSI");
|
||||
runTest(psendPOSITest, "POSI (player)");
|
||||
runTest(sendWYPTTest, "WYPT");
|
||||
runTest(sendTEXTTest, "TEXT");
|
||||
runTest(connTest, "CONN");
|
||||
// Basic Networking
|
||||
runTest(testOpen, "open");
|
||||
runTest(testClose, "close");
|
||||
// Datarefs
|
||||
runTest(testGETD_Basic, "GETD");
|
||||
runTest(testGETD_Types, "GETD (types)");
|
||||
runTest(testGETD_TestFloat, "GETD (test float)");
|
||||
runTest(testDREF, "DREF");
|
||||
// Pause
|
||||
runTest(testSIMU_Basic, "SIMU");
|
||||
runTest(testSIMU_Toggle, "SIMU (toggle)");
|
||||
// CTRL
|
||||
runTest(testCTRL_Player, "CTRL (player)");
|
||||
runTest(testCTRL_NonPlayer, "CTRL (non-player)");
|
||||
runTest(testCTRL_Speedbrakes, "CTRL (speedbrakes)");
|
||||
// POSI
|
||||
runTest(testPOSI_Player, "POSI (player)");
|
||||
runTest(testPOSI_NonPlayer, "POSI (non-player)");
|
||||
// Data
|
||||
runTest(testDATA, "DATA");
|
||||
// Text
|
||||
runTest(testTEXT, "TEXT");
|
||||
// Waypoints
|
||||
runTest(testWYPT, "WYPT");
|
||||
// View
|
||||
runTest(testView, "VIEW");
|
||||
// setConn
|
||||
runTest(testCONN, "CONN");
|
||||
|
||||
printf( "----------------\nTest Summary\n\tFailed: %i\n\tPassed: %i\n", testFailed, testPassed );
|
||||
printf("Press any key to exit.");
|
||||
getchar();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package gov.nasa.xpc.test;
|
||||
|
||||
import gov.nasa.xpc.ViewType;
|
||||
import gov.nasa.xpc.WaypointOp;
|
||||
import gov.nasa.xpc.XPlaneConnect;
|
||||
|
||||
@@ -208,12 +209,30 @@ public class XPlaneConnectTest
|
||||
{
|
||||
xpc.pauseSim(true);
|
||||
float[] result = xpc.getDREF(dref);
|
||||
//assertEquals(1, result.length); //TODO: Why is this result 20 elements long in Java? (It's only one in MATLAB)
|
||||
assertEquals(20, result.length);
|
||||
assertEquals(1, result[0], 1e-4);
|
||||
|
||||
xpc.pauseSim(false);
|
||||
result = xpc.getDREF(dref);
|
||||
//assertEquals(1, result.length);
|
||||
assertEquals(20, result.length);
|
||||
assertEquals(0, result[0], 1e-4);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPauseSim_Switch() throws IOException
|
||||
{
|
||||
String dref = "sim/operation/override/override_planepath";
|
||||
try(XPlaneConnect xpc = new XPlaneConnect())
|
||||
{
|
||||
xpc.pauseSim(true);
|
||||
float[] result = xpc.getDREF(dref);
|
||||
assertEquals(20, result.length);
|
||||
assertEquals(1, result[0], 1e-4);
|
||||
|
||||
xpc.pauseSim(2);
|
||||
result = xpc.getDREF(dref);
|
||||
assertEquals(20, result.length);
|
||||
assertEquals(0, result[0], 1e-4);
|
||||
}
|
||||
}
|
||||
@@ -315,6 +334,33 @@ public class XPlaneConnectTest
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendDREFs() throws IOException
|
||||
{
|
||||
String[] drefs =
|
||||
{
|
||||
"sim/cockpit/switches/gear_handle_status",
|
||||
"sim/cockpit/autopilot/altitude"
|
||||
};
|
||||
try(XPlaneConnect xpc = new XPlaneConnect())
|
||||
{
|
||||
float[][] values = {{1}, {2000}};
|
||||
xpc.sendDREFs(drefs, values);
|
||||
|
||||
float[][] result = xpc.getDREFs(drefs);
|
||||
assertEquals(values[0][0], result[0][0], 1e-4);
|
||||
assertEquals(values[1][0], result[1][0], 1e-4);
|
||||
|
||||
values[0][0] = 0;
|
||||
values[1][0] = 4000;
|
||||
xpc.sendDREFs(drefs, values);
|
||||
|
||||
result = xpc.getDREFs(drefs);
|
||||
assertEquals(values[0][0], result[0][0], 1e-4);
|
||||
assertEquals(values[1][0], result[1][0], 1e-4);
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testSendDREF_NullDREF() throws IOException
|
||||
{
|
||||
@@ -445,6 +491,34 @@ public class XPlaneConnectTest
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendCTRL_Speedbrakes() throws IOException
|
||||
{
|
||||
String dref = "sim/flightmodel/controls/sbrkrqst";
|
||||
float[] ctrl = new float[] { -998.0F, -998.0F, -998.0F, -998.0F, -998.0F, -998.0F, -0.5F };
|
||||
try(XPlaneConnect xpc = new XPlaneConnect())
|
||||
{
|
||||
// Speedbrakes armed
|
||||
xpc.sendCTRL(ctrl);
|
||||
float[] result = xpc.getDREF(dref);
|
||||
|
||||
assertEquals(-0.5F, result[0], 1e-4);
|
||||
|
||||
ctrl[6] = 1.0F; // Deploy speedbrakes
|
||||
xpc.sendCTRL(ctrl);
|
||||
result = xpc.getDREF(dref);
|
||||
|
||||
assertEquals(1.0F, result[0], 1e-4);
|
||||
|
||||
ctrl[6] = 0.0F; // Retract speedbrakes
|
||||
xpc.sendCTRL(ctrl);
|
||||
result = xpc.getDREF(dref);
|
||||
|
||||
assertEquals(0.0F, result[0], 1e-4);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testSendCTRL_NullCtrl() throws IOException
|
||||
{
|
||||
@@ -457,7 +531,7 @@ public class XPlaneConnectTest
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testSendCTRL_LongCtrl() throws IOException
|
||||
{
|
||||
float[] ctrl = new float[] {0, 0, 1, 0.8F, 0, 1, -998};
|
||||
float[] ctrl = new float[] {0, 0, 1, 0.8F, 0, 1, 0, -998};
|
||||
try(XPlaneConnect xpc = new XPlaneConnect())
|
||||
{
|
||||
xpc.sendCTRL(ctrl);
|
||||
@@ -604,4 +678,24 @@ public class XPlaneConnectTest
|
||||
fail();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendView() throws IOException
|
||||
{
|
||||
String dref = "sim/graphics/view/view_type";
|
||||
float fwd = 1000;
|
||||
float chase = 1017;
|
||||
|
||||
try(XPlaneConnect xpc = new XPlaneConnect())
|
||||
{
|
||||
xpc.sendVIEW(ViewType.Forwards);
|
||||
float result = xpc.getDREF(dref)[0];
|
||||
assertEquals(fwd, result, 1e-4);
|
||||
|
||||
xpc.sendVIEW(ViewType.Chase);
|
||||
result = xpc.getDREF(dref)[0];
|
||||
assertEquals(chase, result, 1e-4);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
26
TestScripts/MATLAB Tests/sendVIEWTest.m
Normal file
26
TestScripts/MATLAB Tests/sendVIEWTest.m
Normal file
@@ -0,0 +1,26 @@
|
||||
function sendVIEWTest()
|
||||
%% Setup
|
||||
addpath('../../MATLAB')
|
||||
import XPlaneConnect.*
|
||||
|
||||
if ~exist('gov.nasa.xpc.ViewType', 'class')
|
||||
[folder, ~, ~] = fileparts(which('XPlaneConnect.openUDP'));
|
||||
javaaddpath(fullfile(folder, 'XPlaneConnect.jar'));
|
||||
end
|
||||
|
||||
dref = 'sim/graphics/view/view_type';
|
||||
fwd = 1000;
|
||||
chase = 1017;
|
||||
|
||||
%% Excecute
|
||||
sendVIEW(gov.nasa.xpc.ViewType.Forwards);
|
||||
result = getDREFs(dref);
|
||||
assert(isequal(result, fwd))
|
||||
|
||||
sendVIEW(gov.nasa.xpc.ViewType.Chase);
|
||||
result = getDREFs(dref);
|
||||
assert(isequal(result, chase))
|
||||
|
||||
|
||||
end
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
addpath('../../MATLAB')
|
||||
import XPlaneConnect.*
|
||||
|
||||
testsPassed=0;
|
||||
testsFailed=0;
|
||||
if ismac()
|
||||
@@ -18,9 +21,11 @@ theTests = {{@openCloseTest, 'Open/Close Test', 0},...
|
||||
{@CTRLTest,'CTRL Test', 0},...
|
||||
{@POSITest,'POSI Test', 0},...
|
||||
{@sendWYPTTest,'WYPT Test', 0},...
|
||||
{@sendVIEWTest,'VIEW Test', 0},...
|
||||
{@pauseTest,'Pause Test', 0},...
|
||||
{@setConnTest, 'setConn Test', 0}};
|
||||
|
||||
socket = openUDP();
|
||||
for i=1:length(theTests)
|
||||
fprintf(['Test ',num2str(i),': ',theTests{i}{2},' - ']);
|
||||
try
|
||||
@@ -35,6 +40,7 @@ for i=1:length(theTests)
|
||||
testsFailed = testsFailed + 1;
|
||||
end
|
||||
end
|
||||
closeUDP(socket);
|
||||
|
||||
disp('Results Summary:');
|
||||
fprintf('Passed: %i\tFailed: %i\n',testsPassed, testsFailed);
|
||||
385
TestScripts/Python Tests/Tests.py
Normal file
385
TestScripts/Python Tests/Tests.py
Normal file
@@ -0,0 +1,385 @@
|
||||
import random
|
||||
import unittest
|
||||
import imp
|
||||
import time
|
||||
|
||||
import xpc
|
||||
|
||||
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)
|
||||
buf = receiver.readUDP()
|
||||
|
||||
# Cleanup
|
||||
sender.close()
|
||||
receiver.close()
|
||||
|
||||
# Tests
|
||||
for a, b in zip(test, buf):
|
||||
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_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_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/Python Tests/Tests.pyproj
Normal file
45
TestScripts/Python 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>
|
||||
@@ -1,26 +1,26 @@
|
||||
//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
//National Aeronautics and Space Administration. All Rights Reserved.
|
||||
// Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
// National Aeronautics and Space Administration. All Rights Reserved.
|
||||
//
|
||||
//X-Plane API
|
||||
//Copyright(c) 2008, Sandy Barbour and Ben Supnik All rights reserved.
|
||||
//Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
//associated documentation files(the "Software"), to deal in the Software without restriction,
|
||||
//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
|
||||
//furnished to do so, subject to the following conditions :
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// * 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
|
||||
// without specific prior written permission from the authors or
|
||||
// Laminar Research, respectively.
|
||||
// X-Plane API
|
||||
// Copyright(c) 2008, Sandy Barbour and Ben Supnik All rights reserved.
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
// associated documentation files(the "Software"), to deal in the Software without restriction,
|
||||
// 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
|
||||
// furnished to do so, subject to the following conditions :
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// * 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
|
||||
// without specific prior written permission from the authors or
|
||||
// Laminar Research, respectively.
|
||||
#include "DataManager.h"
|
||||
#include "DataMaps.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include "XPLMDataAccess.h"
|
||||
#include "XPLMGraphics.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <map>
|
||||
@@ -29,12 +29,17 @@ namespace XPC
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
const size_t PLANE_COUNT = 20;
|
||||
static map<DREF, XPLMDataRef> drefs;
|
||||
static map<DREF, XPLMDataRef> mdrefs[20];
|
||||
static map<DREF, XPLMDataRef> mdrefs[PLANE_COUNT];
|
||||
static map<string, XPLMDataRef> sdrefs;
|
||||
|
||||
DREF XPData[134][8] = { DREF_None };
|
||||
|
||||
void DataManager::Initialize()
|
||||
{
|
||||
Log::WriteLine(LOG_TRACE, "DMAN", "Initializing drefs");
|
||||
|
||||
drefs.insert(make_pair(DREF_None, XPLMFindDataRef("sim/test/test_float")));
|
||||
|
||||
drefs.insert(make_pair(DREF_Pause, XPLMFindDataRef("sim/operation/override/override_planepath")));
|
||||
@@ -68,6 +73,9 @@ namespace XPC
|
||||
drefs.insert(make_pair(DREF_FlapSetting, XPLMFindDataRef("sim/flightmodel/controls/flaprqst")));
|
||||
drefs.insert(make_pair(DREF_FlapActual, XPLMFindDataRef("sim/flightmodel/controls/flaprat")));
|
||||
|
||||
drefs.insert(make_pair(DREF_SpeedBrakeSet, XPLMFindDataRef("sim/flightmodel/controls/sbrkrqst")));
|
||||
drefs.insert(make_pair(DREF_SpeedBrakeActual, XPLMFindDataRef("sim/flightmodel/controls/sbrkrat")));
|
||||
|
||||
drefs.insert(make_pair(DREF_GearDeploy, XPLMFindDataRef("sim/aircraft/parts/acf_gear_deploy")));
|
||||
drefs.insert(make_pair(DREF_GearHandle, XPLMFindDataRef("sim/cockpit/switches/gear_handle_status")));
|
||||
drefs.insert(make_pair(DREF_BrakeParking, XPLMFindDataRef("sim/flightmodel/controls/parkbrakel")));
|
||||
@@ -138,7 +146,7 @@ namespace XPC
|
||||
drefs.insert(make_pair(DREF_MP7Alt, XPLMFindDataRef("sim/multiplayer/position/plane7_el")));
|
||||
|
||||
char multi[256];
|
||||
for (int i = 1; i < 20; i++)
|
||||
for (int i = 1; i < PLANE_COUNT; i++)
|
||||
{
|
||||
sprintf(multi, "sim/multiplayer/position/plane%i_x", i);
|
||||
mdrefs[i][DREF_LocalX] = XPLMFindDataRef(multi);
|
||||
@@ -168,7 +176,7 @@ namespace XPC
|
||||
sprintf(multi, "sim/multiplayer/position/plane%i_spoiler_ratio", i);
|
||||
mdrefs[i][DREF_Spoiler] = XPLMFindDataRef(multi);
|
||||
sprintf(multi, "sim/multiplayer/position/plane%i_speedbrake_ratio", i);
|
||||
mdrefs[i][DREF_BrakeSpeed] = XPLMFindDataRef(multi);
|
||||
mdrefs[i][DREF_SpeedBrakeSet] = XPLMFindDataRef(multi);
|
||||
sprintf(multi, "sim/multiplayer/position/plane%i_slat_ratio", i);
|
||||
mdrefs[i][DREF_Slats] = XPLMFindDataRef(multi);
|
||||
sprintf(multi, "sim/multiplayer/position/plane%i_wing_sweep", i);
|
||||
@@ -295,8 +303,9 @@ namespace XPC
|
||||
XPData[26][0] = DREF_ThrottleActual;
|
||||
}
|
||||
|
||||
int DataManager::Get(string dref, float values[], int size)
|
||||
int DataManager::Get(const string& dref, float values[], int size)
|
||||
{
|
||||
Log::WriteLine(LOG_TRACE, "DMAN", "Entered Get(string, float*, int)");
|
||||
XPLMDataRef& xdref = sdrefs[dref];
|
||||
if (xdref == NULL)
|
||||
{
|
||||
@@ -304,24 +313,18 @@ namespace XPC
|
||||
}
|
||||
if (!xdref) // DREF does not exist
|
||||
{
|
||||
#if LOG_VERBOSITY > 0
|
||||
Log::FormatLine("[DMAN] ERROR: invalid DREF %s", dref.c_str());
|
||||
#endif
|
||||
Log::FormatLine(LOG_ERROR, "DMAN", "ERROR: invalid DREF %s", dref.c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
XPLMDataTypeID dataType = XPLMGetDataRefTypes(xdref);
|
||||
#if LOG_VERBOSITY > 4
|
||||
Log::FormatLine("[DMAN] Get DREF %s (x:%X) Type: %i", dref.c_str(), xdref, dataType);
|
||||
#endif
|
||||
Log::FormatLine(LOG_INFO, "DMAN", "Get DREF %s (x:%X) Type: %i", dref.c_str(), xdref, dataType);
|
||||
// XPLMDataTypeID is a bit flag, so it may contain more than one of the
|
||||
// following types. We prefer types as close to float as possible.
|
||||
if ((dataType & 2) == 2) // Float
|
||||
{
|
||||
values[0] = XPLMGetDataf(xdref);
|
||||
#if LOG_VERBOSITY > 4
|
||||
Log::FormatLine("[DMAN] -- value was %f", values[0]);
|
||||
#endif
|
||||
Log::FormatLine(LOG_INFO, "DMAN", " -- value was %f", values[0]);
|
||||
return 1;
|
||||
}
|
||||
if ((dataType & 8) == 8) // Float array
|
||||
@@ -329,99 +332,80 @@ namespace XPC
|
||||
int drefSize = XPLMGetDatavf(xdref, NULL, 0, 0);
|
||||
if (drefSize > size)
|
||||
{
|
||||
#if LOG_VERBOSITY > 1
|
||||
Log::WriteLine("[DMAN] WARN: dref size is larger than available space");
|
||||
Log::FormatLine(" Actual dref size: %i, Available size: %i", drefSize, size);
|
||||
#endif
|
||||
Log::WriteLine(LOG_WARN, "DMAN", "Warning: dref size is larger than available space");
|
||||
Log::FormatLine(LOG_DEBUG, "DMAN", "Actual dref size : %i, Available size : %i", drefSize, size);
|
||||
drefSize = size;
|
||||
}
|
||||
XPLMGetDatavf(xdref, values, 0, drefSize);
|
||||
#if LOG_VERBOSITY > 4
|
||||
Log::FormatLine("[DMAN] -- value count was %i", drefSize);
|
||||
#endif
|
||||
Log::FormatLine(LOG_INFO, "DMAN", " -- value count was %i", drefSize);
|
||||
return drefSize;
|
||||
}
|
||||
if ((dataType & 4) == 4) // Double
|
||||
{
|
||||
values[0] = (float)XPLMGetDatad(xdref);
|
||||
#if LOG_VERBOSITY > 4
|
||||
Log::FormatLine("[DMAN] -- value was %f", values[0]);
|
||||
#endif
|
||||
Log::FormatLine(LOG_INFO, "DMAN", " -- value was %f", values[0]);
|
||||
return 1;
|
||||
}
|
||||
if ((dataType & 1) == 1) // Integer
|
||||
{
|
||||
values[0] = (float)XPLMGetDatai(xdref);
|
||||
#if LOG_VERBOSITY > 4
|
||||
Log::FormatLine("[DMAN] -- value was %i", (int)values[0]);
|
||||
#endif
|
||||
int iValue = XPLMGetDatai(xdref);
|
||||
values[0] = (float)iValue;
|
||||
Log::FormatLine(LOG_INFO, "DMAN", " -- Real value was %i, cast to %f", iValue, values[0]);
|
||||
return 1;
|
||||
}
|
||||
if ((dataType & 16) == 16) // Integer array
|
||||
{
|
||||
int iValues[200];
|
||||
const std::size_t TMP_SIZE = 200;
|
||||
int iValues[TMP_SIZE];
|
||||
int drefSize = XPLMGetDatavi(xdref, NULL, 0, 0);
|
||||
if (drefSize > size)
|
||||
{
|
||||
#if LOG_VERBOSITY > 1
|
||||
Log::WriteLine("[DMAN] WARN: dref size is larger than available space");
|
||||
Log::FormatLine(" Actual dref size: %i, Available size: %i", drefSize, size);
|
||||
#endif
|
||||
Log::WriteLine(LOG_WARN, "DMAN", "Warning: dref size is larger than available space");
|
||||
Log::FormatLine(LOG_DEBUG, "DMAN", "Actual dref size : %i, Available size : %i", drefSize, size);
|
||||
drefSize = size;
|
||||
}
|
||||
if (drefSize > 200)
|
||||
if (drefSize > TMP_SIZE)
|
||||
{
|
||||
#if LOG_VERBOSITY > 1
|
||||
Log::WriteLine("[DMAN] WARN: dref size is larger than temp buffer");
|
||||
Log::FormatLine(" Actual dref size: %i, Temp buffer size: 200", drefSize);
|
||||
#endif
|
||||
drefSize = 200;
|
||||
Log::WriteLine(LOG_WARN, "DMAN", "Warning: dref size is larger than temp buffer");
|
||||
Log::FormatLine(LOG_DEBUG, "DMAN", "Actual dref size : %i, Temp buffer size: %u", drefSize, TMP_SIZE);
|
||||
drefSize = TMP_SIZE;
|
||||
}
|
||||
XPLMGetDatavi(xdref, iValues, 0, drefSize);
|
||||
for (int i = 0; i < drefSize; ++i)
|
||||
{
|
||||
values[i] = (float)iValues[i];
|
||||
}
|
||||
#if LOG_VERBOSITY > 4
|
||||
Log::FormatLine("[DMAN] -- value count was %i", drefSize);
|
||||
#endif
|
||||
Log::FormatLine(LOG_INFO, "DMAN", " -- value count was %i", drefSize);
|
||||
return drefSize;
|
||||
}
|
||||
if ((dataType & 32) == 32) // Byte array
|
||||
{
|
||||
char bValues[1024];
|
||||
const std::size_t TMP_SIZE = 1024;
|
||||
char bValues[TMP_SIZE];
|
||||
int drefSize = XPLMGetDatab(xdref, NULL, 0, 0);
|
||||
if (drefSize > size)
|
||||
{
|
||||
#if LOG_VERBOSITY > 1
|
||||
Log::WriteLine("[DMAN] WARN: dref size is larger than available space");
|
||||
Log::FormatLine(" Actual dref size: %i, Available size: %i", drefSize, size);
|
||||
#endif
|
||||
Log::WriteLine(LOG_WARN, "DMAN", "Warning: dref size is larger than available space");
|
||||
Log::FormatLine(LOG_DEBUG, "DMAN", "Actual dref size : %i, Available size : %i", drefSize, size);
|
||||
drefSize = size;
|
||||
}
|
||||
if (drefSize > 1024)
|
||||
if (drefSize > TMP_SIZE)
|
||||
{
|
||||
#if LOG_VERBOSITY > 1
|
||||
Log::WriteLine("[DMAN] WARN: dref size is larger than temp buffer");
|
||||
Log::FormatLine(" Actual dref size: %i, Temp buffer size: 1024", drefSize);
|
||||
#endif
|
||||
drefSize = 1024;
|
||||
Log::WriteLine(LOG_WARN, "DMAN", "Warning: dref size is larger than temp buffer");
|
||||
Log::FormatLine(LOG_DEBUG, "DMAN", "Actual dref size : %i, Temp buffer size: %u", drefSize, TMP_SIZE);
|
||||
drefSize = TMP_SIZE;
|
||||
}
|
||||
XPLMGetDatab(xdref, bValues, 0, drefSize);
|
||||
for (int i = 0; i < drefSize; ++i)
|
||||
{
|
||||
values[i] = (float)bValues[i];
|
||||
}
|
||||
#if LOG_VERBOSITY > 4
|
||||
Log::FormatLine("[DMAN] -- value count was %i", drefSize);
|
||||
#endif
|
||||
Log::FormatLine(LOG_INFO, "DMAN", " -- value count was %i", drefSize);
|
||||
return drefSize;
|
||||
}
|
||||
|
||||
// No match
|
||||
#if LOG_VERBOSITY > 0
|
||||
Log::WriteLine("[DMAN] ERROR: Unrecognized data type.");
|
||||
#endif
|
||||
Log::WriteLine(LOG_ERROR, "DMAN", "ERROR: Unrecognized data type.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -429,9 +413,8 @@ namespace XPC
|
||||
{
|
||||
const XPLMDataRef& xdref = aircraft == 0 ? drefs[dref] : mdrefs[aircraft][dref];
|
||||
double value = XPLMGetDatad(xdref);
|
||||
#if LOG_VERBOSITY > 4
|
||||
Log::FormatLine("[DMAN] Get DREF %i (x:%X) result %f for a/c %i", dref, xdref, value, aircraft);
|
||||
#endif
|
||||
Log::FormatLine(LOG_INFO, "DMAN", "Get DREF %i (x:%X) result %f for a/c %i",
|
||||
dref, xdref, value, aircraft);
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -439,9 +422,8 @@ namespace XPC
|
||||
{
|
||||
const XPLMDataRef& xdref = aircraft == 0 ? drefs[dref] : mdrefs[aircraft][dref];
|
||||
float value = XPLMGetDataf(xdref);
|
||||
#if LOG_VERBOSITY > 4
|
||||
Log::FormatLine("[DMAN] Get DREF %i (x:%X) result %f for a/c %i", dref, xdref, value, aircraft);
|
||||
#endif
|
||||
Log::FormatLine(LOG_INFO, "DMAN", "Get DREF %i (x:%X) result %f for a/c %i",
|
||||
dref, xdref, value, aircraft);
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -449,9 +431,8 @@ namespace XPC
|
||||
{
|
||||
const XPLMDataRef& xdref = aircraft == 0 ? drefs[dref] : mdrefs[aircraft][dref];
|
||||
int value = XPLMGetDatai(xdref);
|
||||
#if LOG_VERBOSITY > 4
|
||||
Log::FormatLine("[DMAN] Get DREF %i (x:%X) result %i for a/c %i", dref, xdref, value, aircraft);
|
||||
#endif
|
||||
Log::FormatLine(LOG_INFO, "DMAN", "Get DREF %i (x:%X) result %i for a/c %i",
|
||||
dref, xdref, value, aircraft);
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -459,9 +440,8 @@ namespace XPC
|
||||
{
|
||||
const XPLMDataRef& xdref = aircraft == 0 ? drefs[dref] : mdrefs[aircraft][dref];
|
||||
int resultSize = XPLMGetDatavf(xdref, values, 0, size);
|
||||
#if LOG_VERBOSITY > 4
|
||||
Log::FormatLine("[DMAN] Get DREF %i (x:%X) result size %i for a/c %i", dref, xdref, resultSize, aircraft);
|
||||
#endif
|
||||
Log::FormatLine(LOG_INFO, "DMAN", "Get DREF %i (x:%X) result size %i for a/c %i",
|
||||
dref, xdref, resultSize, aircraft);
|
||||
return resultSize;
|
||||
}
|
||||
|
||||
@@ -469,62 +449,66 @@ namespace XPC
|
||||
{
|
||||
const XPLMDataRef& xdref = aircraft == 0 ? drefs[dref] : mdrefs[aircraft][dref];
|
||||
int resultSize = XPLMGetDatavi(xdref, values, 0, size);
|
||||
#if LOG_VERBOSITY > 4
|
||||
Log::FormatLine("[DMAN] Get DREF %i (x:%X) result size %i for a/c %i", dref, xdref, resultSize, aircraft);
|
||||
#endif
|
||||
Log::FormatLine(LOG_INFO, "DMAN", "Get DREF %i (x:%X) result size %i for a/c %i",
|
||||
dref, xdref, resultSize, aircraft);
|
||||
return resultSize;
|
||||
}
|
||||
|
||||
void DataManager::Set(DREF dref, double value, char aircraft)
|
||||
{
|
||||
const XPLMDataRef& xdref = aircraft == 0 ? drefs[dref] : mdrefs[aircraft][dref];
|
||||
#if LOG_VERBOSITY > 4
|
||||
Log::FormatLine("[DMAN] Setting DREF %i (x:%X) to %f for a/c %i", dref, xdref, value, aircraft);
|
||||
#endif
|
||||
Log::FormatLine(LOG_INFO, "DMAN", "Setting DREF %i (x:%X) to %f for a/c %i",
|
||||
dref, xdref, value, aircraft);
|
||||
XPLMSetDatad(xdref, value);
|
||||
}
|
||||
|
||||
void DataManager::Set(DREF dref, float value, char aircraft)
|
||||
{
|
||||
const XPLMDataRef& xdref = aircraft == 0 ? drefs[dref] : mdrefs[aircraft][dref];
|
||||
#if LOG_VERBOSITY > 4
|
||||
Log::FormatLine("[DMAN] Set DREF %i (x:%X) to %f for a/c %i", dref, xdref, value, aircraft);
|
||||
#endif
|
||||
Log::FormatLine(LOG_INFO, "DMAN", "Setting DREF %i (x:%X) to %f for a/c %i",
|
||||
dref, xdref, value, aircraft);
|
||||
XPLMSetDataf(xdref, value);
|
||||
}
|
||||
|
||||
void DataManager::Set(DREF dref, int value, char aircraft)
|
||||
{
|
||||
const XPLMDataRef& xdref = aircraft == 0 ? drefs[dref] : mdrefs[aircraft][dref];
|
||||
#if LOG_VERBOSITY > 4
|
||||
Log::FormatLine("[DMAN] Set DREF %i (x:%X) to %i for a/c %i", dref, xdref, value, aircraft);
|
||||
#endif
|
||||
Log::FormatLine(LOG_INFO, "DMAN", "Setting DREF %i (x:%X) to %i for a/c %i",
|
||||
dref, xdref, value, aircraft);
|
||||
XPLMSetDatai(xdref, value);
|
||||
}
|
||||
|
||||
void DataManager::Set(DREF dref, float values[], int size, char aircraft)
|
||||
{
|
||||
const XPLMDataRef& xdref = aircraft == 0 ? drefs[dref] : mdrefs[aircraft][dref];
|
||||
#if LOG_VERBOSITY > 4
|
||||
Log::FormatLine("[DMAN] Set DREF %i (x:%X) (%i values) for a/c %i", dref, xdref, size, aircraft);
|
||||
#endif
|
||||
Log::FormatLine(LOG_INFO, "DMAN", "Setting DREF %i (x:%X) (%i values) for a/c %i",
|
||||
dref, xdref, size, aircraft);
|
||||
int drefSize = XPLMGetDatavf(xdref, NULL, 0, 0);
|
||||
if (drefSize < size)
|
||||
{
|
||||
Log::FormatLine(LOG_WARN, "DMAN", "Warning: Too many values when setting DREF %i. Expected %i, got %i",
|
||||
dref, drefSize, size);
|
||||
}
|
||||
drefSize = min(drefSize, size);
|
||||
XPLMSetDatavf(xdref, values, 0, drefSize);
|
||||
}
|
||||
|
||||
|
||||
void DataManager::Set(DREF dref, int values[], int size, char aircraft)
|
||||
{
|
||||
const XPLMDataRef& xdref = aircraft == 0 ? drefs[dref] : mdrefs[aircraft][dref];
|
||||
#if LOG_VERBOSITY > 4
|
||||
Log::FormatLine("[DMAN] Setting DREF %i (x:%X) (%i values) for a/c %i", dref, xdref, size, aircraft);
|
||||
#endif
|
||||
Log::FormatLine(LOG_INFO, "DMAN", "Setting DREF %i (x:%X) (%i values) for a/c %i",
|
||||
dref, xdref, size, aircraft);
|
||||
int drefSize = XPLMGetDatavi(xdref, NULL, 0, 0);
|
||||
if (drefSize < size)
|
||||
{
|
||||
Log::FormatLine(LOG_WARN, "DMAN", "Warning: Too many values when setting DREF %i. Expected %i, got %i",
|
||||
dref, drefSize, size);
|
||||
}
|
||||
drefSize = min(drefSize, size);
|
||||
XPLMSetDatavi(xdref, values, 0, drefSize);
|
||||
}
|
||||
|
||||
void DataManager::Set(string dref, float values[], int size)
|
||||
void DataManager::Set(const string& dref, float values[], int size)
|
||||
{
|
||||
XPLMDataRef& xdref = sdrefs[dref];
|
||||
if (xdref == NULL)
|
||||
@@ -534,149 +518,121 @@ namespace XPC
|
||||
if (!xdref)
|
||||
{
|
||||
// DREF does not exist
|
||||
#if LOG_VERBOSITY > 0
|
||||
Log::FormatLine("[DMAN] ERROR: invalid DREF %s", dref.c_str());
|
||||
#endif
|
||||
Log::FormatLine(LOG_ERROR, "DMAN", "ERROR: invalid DREF %s", dref.c_str());
|
||||
return;
|
||||
}
|
||||
if (isnan(values[0]))
|
||||
{
|
||||
#if LOG_VERBOSITY > 0
|
||||
Log::WriteLine("[DMAN] ERROR: Value must be a number (NaN received)");
|
||||
#endif
|
||||
Log::WriteLine(LOG_ERROR, "DMAN", "ERROR: Value must be a number (NaN received)");
|
||||
return;
|
||||
}
|
||||
|
||||
XPLMDataTypeID dataType = XPLMGetDataRefTypes(xdref);
|
||||
#if LOG_VERBOSITY > 4
|
||||
Log::FormatLine("[DMAN] Setting DREF %s (x:%X) Type: %i", dref.c_str(), xdref, dataType);
|
||||
#endif
|
||||
Log::FormatLine(LOG_INFO, "DMAN", "Setting DREF %s (x:%X) Type: %i", xdref, dataType);
|
||||
if ((dataType & 2) == 2) // Float
|
||||
{
|
||||
XPLMSetDataf(xdref, values[0]);
|
||||
#if LOG_VERBOSITY > 4
|
||||
Log::FormatLine("[DMAN] -- value was %f", values[0]);
|
||||
#endif
|
||||
Log::FormatLine(LOG_INFO, "DMAN", " -- value was %f", values[0]);
|
||||
}
|
||||
else if ((dataType & 8) == 8) // Float Array
|
||||
{
|
||||
int drefSize = XPLMGetDatavf(xdref, NULL, 0, 0);
|
||||
#if LOG_VERBOSITY > 1
|
||||
if (size > drefSize)
|
||||
{
|
||||
Log::WriteLine("[DMAN] WARN: Provided size is larger than actual dref size");
|
||||
Log::FormatLine(" Actual dref size: %i, Provided buffer size: %i", drefSize, size);
|
||||
Log::WriteLine(LOG_WARN, "DMAN", "Warning: dref size is larger than actual dref size");
|
||||
Log::FormatLine(LOG_DEBUG, "DMAN", "Actual dref size : %i, Provided buffer size : %i",
|
||||
drefSize, size);
|
||||
}
|
||||
#endif
|
||||
drefSize = min(drefSize, size);
|
||||
XPLMSetDatavf(xdref, values, 0, drefSize);
|
||||
#if LOG_VERBOSITY > 4
|
||||
Log::FormatLine("[DMAN] -- value count was %i", drefSize);
|
||||
#endif
|
||||
Log::FormatLine(LOG_INFO, "DMAN", " -- value count was %i", drefSize);
|
||||
}
|
||||
else if ((dataType & 4) == 4) // Double
|
||||
{
|
||||
XPLMSetDatad(xdref, values[0]);
|
||||
#if LOG_VERBOSITY > 4
|
||||
Log::FormatLine("[DMAN] -- value was %f", values[0]);
|
||||
#endif
|
||||
Log::FormatLine(LOG_INFO, "DMAN", " -- value was %f", values[0]);
|
||||
}
|
||||
else if ((dataType & 1) == 1) // Integer
|
||||
{
|
||||
XPLMSetDatai(xdref, (int)values[0]);
|
||||
#if LOG_VERBOSITY > 4
|
||||
Log::FormatLine("[DMAN] -- value was %i", (int)values[0]);
|
||||
#endif
|
||||
Log::FormatLine(LOG_INFO, "DMAN", " -- value was %i", (int)values[0]);
|
||||
}
|
||||
else if ((dataType & 16) == 16) // Integer Array
|
||||
{
|
||||
int iValues[200];
|
||||
const std::size_t TMP_SIZE = 200;
|
||||
int iValues[TMP_SIZE];
|
||||
int drefSize = XPLMGetDatavi(xdref, NULL, 0, 0);
|
||||
#if LOG_VERBOSITY > 1
|
||||
if (size > drefSize)
|
||||
{
|
||||
Log::WriteLine("[DMAN] WARN: Provided size is larger than actual dref size");
|
||||
Log::FormatLine(" Actual dref size: %i, Provided buffer size: %i", drefSize, size);
|
||||
Log::WriteLine(LOG_WARN, "DMAN", "Warning: dref size is larger than actual dref size");
|
||||
Log::FormatLine(LOG_DEBUG, "DMAN", "Actual dref size : %i, Provided buffer size : %i",
|
||||
drefSize, size);
|
||||
}
|
||||
#endif
|
||||
drefSize = min(drefSize, size);
|
||||
if (drefSize > 200)
|
||||
if (drefSize > TMP_SIZE)
|
||||
{
|
||||
#if LOG_VERBOSITY > 1
|
||||
Log::WriteLine("[DMAN] WARN: drefSize larger than temp buffer size.");
|
||||
Log::FormatLine(" Actual dref size: %i, Temp buffer size: 200", drefSize);
|
||||
#endif
|
||||
drefSize = 200;
|
||||
Log::WriteLine(LOG_WARN, "DMAN", "Warning: dref size is larger temp buffer size");
|
||||
Log::FormatLine(LOG_DEBUG, "DMAN", "Actual dref size : %i, Temp buffer size: %i",
|
||||
drefSize, TMP_SIZE);
|
||||
drefSize = TMP_SIZE;
|
||||
}
|
||||
for (int i = 0; i < drefSize; ++i)
|
||||
{
|
||||
iValues[i] = (int)values[i];
|
||||
}
|
||||
XPLMSetDatavi(xdref, iValues, 0, drefSize);
|
||||
#if LOG_VERBOSITY > 4
|
||||
Log::FormatLine("[DMAN] -- value count was %i", drefSize);
|
||||
#endif
|
||||
Log::FormatLine(LOG_INFO, "DMAN", " -- value count was %i", drefSize);
|
||||
}
|
||||
else if ((dataType & 32) == 32) // Byte Array
|
||||
{
|
||||
char bValues[1024];
|
||||
const std::size_t TMP_SIZE = 1024;
|
||||
char bValues[TMP_SIZE];
|
||||
int drefSize = XPLMGetDatab(xdref, NULL, 0, 0);
|
||||
#if LOG_VERBOSITY > 1
|
||||
if (size > drefSize)
|
||||
{
|
||||
Log::WriteLine("[DMAN] WARN: Provided size is larger than actual dref size");
|
||||
Log::FormatLine(" Actual dref size: %i, Provided buffer size: %i", drefSize, size);
|
||||
Log::WriteLine(LOG_WARN, "DMAN", "Warning: dref size is larger than actual dref size");
|
||||
Log::FormatLine(LOG_DEBUG, "DMAN", "Actual dref size : %i, Provided buffer size : %i",
|
||||
drefSize, size);
|
||||
}
|
||||
#endif
|
||||
drefSize = min(drefSize, size);
|
||||
if (drefSize > 1024)
|
||||
if (drefSize > TMP_SIZE)
|
||||
{
|
||||
#if LOG_VERBOSITY > 1
|
||||
Log::WriteLine("[DMAN] WARN: drefSize larger than temp buffer size.");
|
||||
Log::FormatLine(" Actual dref size: %i, Temp buffer size: 1024", drefSize);
|
||||
#endif
|
||||
drefSize = 1024;
|
||||
Log::WriteLine(LOG_WARN, "DMAN", "Warning: dref size is larger temp buffer size");
|
||||
Log::FormatLine(LOG_DEBUG, "DMAN", "Actual dref size : %i, Temp buffer size: %i",
|
||||
drefSize, TMP_SIZE);
|
||||
drefSize = TMP_SIZE;
|
||||
}
|
||||
for (int i = 0; i < drefSize; ++i)
|
||||
{
|
||||
bValues[i] = (char)values[i];
|
||||
}
|
||||
XPLMSetDatab(xdref, bValues, 0, drefSize);
|
||||
#if LOG_VERBOSITY > 4
|
||||
Log::FormatLine("[DMAN] -- value count was %i", drefSize);
|
||||
#endif
|
||||
Log::FormatLine(LOG_INFO, "DMAN", " -- value count was %i", drefSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if LOG_VERBOSITY > 0
|
||||
Log::WriteLine("[DMAN] ERROR: Unknown type.");
|
||||
#endif
|
||||
Log::WriteLine(LOG_ERROR, "DMAN", "ERROR: Unknown type.");
|
||||
}
|
||||
|
||||
|
||||
#if LOG_VERBOSITY > 1
|
||||
if (!XPLMCanWriteDataRef(xdref))
|
||||
{
|
||||
Log::WriteLine("[DMAN] WARN: dref is not writable. The write operation probably failed.");
|
||||
Log::WriteLine(LOG_WARN, "DMAN", "WARN: dref is not writable. The write operation probably failed.");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void DataManager::SetGear(float gear, bool immediate, char aircraft)
|
||||
{
|
||||
#if LOG_VERBOSITY > 3
|
||||
Log::FormatLine("[DMAN] Setting gear (value:%f, immediate:%i) for aircraft %i", gear, immediate, aircraft);
|
||||
#endif
|
||||
if (isnan(gear) || gear < 0 || gear > 1)
|
||||
Log::FormatLine(LOG_INFO, "DMAN", "Setting gear (value:%f, immediate:%i) for aircraft %i",
|
||||
gear, immediate, aircraft);
|
||||
|
||||
if ((gear < -8.5 && gear > -9.5) || IsDefault(gear))
|
||||
{
|
||||
#if LOG_VERBOSITY > 0
|
||||
Log::WriteLine("[GEAR] ERROR: Value must be 0 or 1");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
if ((gear < -8.5 && gear > -9.5) || (gear < -997.9 && gear > -999.1))
|
||||
if (isnan(gear) || gear < 0 || gear > 1)
|
||||
{
|
||||
Log::WriteLine(LOG_ERROR, "DMAN", "ERROR: Gear value must be 0 or 1");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -702,26 +658,23 @@ namespace XPC
|
||||
|
||||
void DataManager::SetPosition(float pos[3], char aircraft)
|
||||
{
|
||||
#if LOG_VERBOSITY > 3
|
||||
Log::FormatLine("[DMAN] Setting position (%f, %f, %f) for aircraft %i", pos[0], pos[1], pos[2], aircraft);
|
||||
#endif
|
||||
Log::FormatLine(LOG_INFO, "DMAN", "Setting position (%f, %f, %f) for aircraft %i",
|
||||
pos[0], pos[1], pos[2], aircraft);
|
||||
if (isnan(pos[0] + pos[1] + pos[2]))
|
||||
{
|
||||
#if LOG_VERBOSITY > 0
|
||||
Log::WriteLine("[DMAN] ERROR: Position must be a number (NaN received)");
|
||||
#endif
|
||||
Log::WriteLine(LOG_ERROR, "DMAN", "ERROR: Position must be a number (NaN received)");
|
||||
return;
|
||||
}
|
||||
|
||||
if (pos[0] < -997.9 && pos[0] > -999.1)
|
||||
if (IsDefault(pos[0]))
|
||||
{
|
||||
pos[0] = (float)GetDouble(DREF_Latitude, aircraft);
|
||||
}
|
||||
if (pos[1] < -997.9 && pos[1] > -999.1)
|
||||
if (IsDefault(pos[1]))
|
||||
{
|
||||
pos[1] = (float)GetDouble(DREF_Longitude, aircraft);
|
||||
}
|
||||
if (pos[2] < -997.9 && pos[2] > -999.1)
|
||||
if (IsDefault(pos[2]))
|
||||
{
|
||||
pos[2] = (float)GetDouble(DREF_Elevation, aircraft);
|
||||
}
|
||||
@@ -734,7 +687,6 @@ namespace XPC
|
||||
Set(DREF_LocalY, local[1], aircraft);
|
||||
Set(DREF_LocalZ, local[2], aircraft);
|
||||
// If the sim is unpaused, this will override the above settings.
|
||||
// TODO: Are these setable when paused? Are these necessary?
|
||||
Set(DREF_Latitude, (double)pos[0], aircraft);
|
||||
Set(DREF_Longitude, (double)pos[1], aircraft);
|
||||
Set(DREF_Elevation, (double)pos[2], aircraft);
|
||||
@@ -742,27 +694,23 @@ namespace XPC
|
||||
|
||||
void DataManager::SetOrientation(float orient[3], char aircraft)
|
||||
{
|
||||
#if LOG_VERBOSITY > 3
|
||||
Log::FormatLine("[DMAN] Setting orientation (%f, %f, %f) for aircraft %i",
|
||||
Log::FormatLine(LOG_INFO, "DMAN", "Setting orientation (%f, %f, %f) for aircraft %i",
|
||||
orient[0], orient[1], orient[2], aircraft);
|
||||
#endif
|
||||
if (isnan(orient[0] + orient[1] + orient[2]))
|
||||
{
|
||||
#if LOG_VERBOSITY > 0
|
||||
Log::WriteLine("[DMAN] ERROR: Orientation must be a number (NaN received)");
|
||||
#endif
|
||||
Log::WriteLine(LOG_ERROR, "DMAN", "ERROR: Orientation must be a number (NaN received)");
|
||||
return;
|
||||
}
|
||||
|
||||
if (orient[0] < -997.9 && orient[0] > -999.1)
|
||||
if (IsDefault(orient[0]))
|
||||
{
|
||||
orient[0] = GetFloat(DREF_Pitch, aircraft);
|
||||
}
|
||||
if (orient[1] < -997.9 && orient[1] > -999.1)
|
||||
if (IsDefault(orient[1]))
|
||||
{
|
||||
orient[1] = GetFloat(DREF_Roll, aircraft);
|
||||
}
|
||||
if (orient[2] < -997.9 && orient[2] > -999.1)
|
||||
if (IsDefault(orient[2]))
|
||||
{
|
||||
orient[2] = GetFloat(DREF_HeadingTrue, aircraft);
|
||||
}
|
||||
@@ -778,7 +726,7 @@ namespace XPC
|
||||
{
|
||||
// Convert to Quaternions
|
||||
// from: http://www.xsquawkbox.net/xpsdk/mediawiki/MovingThePlane
|
||||
// http://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19770024290.pdf
|
||||
// http://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19770024290.pdf
|
||||
float q[4];
|
||||
float halfRad = 0.00872664625997F;
|
||||
orient[2] = halfRad * orient[2];
|
||||
@@ -797,14 +745,14 @@ namespace XPC
|
||||
|
||||
void DataManager::SetFlaps(float value)
|
||||
{
|
||||
Log::FormatLine(LOG_INFO, "DMAN", "Setting flaps (value:%f)", value);
|
||||
|
||||
if (isnan(value))
|
||||
{
|
||||
#if LOG_VERBOSITY > 0
|
||||
Log::WriteLine("[DMAN] ERROR: Flap value must be a number (NaN received)");
|
||||
#endif
|
||||
Log::WriteLine(LOG_ERROR, "DMAN", "ERROR: Flap value must be a number (NaN received)");
|
||||
return;
|
||||
}
|
||||
if (value < -997.9 && value > -999.1)
|
||||
if (IsDefault(value))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -815,4 +763,14 @@ namespace XPC
|
||||
Set(DREF_FlapSetting, value);
|
||||
Set(DREF_FlapActual, value);
|
||||
}
|
||||
}
|
||||
|
||||
float DataManager::GetDefaultValue()
|
||||
{
|
||||
return -998.0F;
|
||||
}
|
||||
|
||||
bool DataManager::IsDefault(float value)
|
||||
{
|
||||
return value < -997.9 && value > -999.1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
//National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#ifndef XPC_DATAMANAGER_H
|
||||
#define XPC_DATAMANAGER_H
|
||||
// Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
// National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#ifndef XPCPLUGIN_DATAMANAGER_H_
|
||||
#define XPCPLUGIN_DATAMANAGER_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
@@ -62,7 +62,7 @@ namespace XPC
|
||||
DREF_L,
|
||||
DREF_N,
|
||||
|
||||
//PQR (Angular Velocities)
|
||||
// PQR (Angular Velocities)
|
||||
DREF_QRad = 1600,
|
||||
DREF_PRad,
|
||||
DREF_RRad,
|
||||
@@ -105,7 +105,8 @@ namespace XPC
|
||||
// Multiplayer Aircraft
|
||||
DREF_FlapActual2,
|
||||
DREF_Spoiler,
|
||||
DREF_BrakeSpeed,
|
||||
DREF_SpeedBrakeSet,
|
||||
DREF_SpeedBrakeActual,
|
||||
DREF_Sweep,
|
||||
DREF_Slats,
|
||||
|
||||
@@ -135,13 +136,16 @@ namespace XPC
|
||||
DREF_MP7Alt
|
||||
};
|
||||
|
||||
/// Marshals data between the plugin and X-Plane.
|
||||
/// Maps X-Plane dataref lines to XPC DREF values.
|
||||
extern DREF XPData[134][8];
|
||||
|
||||
/// Contains methods to martial data between the plugin and X-Plane.
|
||||
///
|
||||
/// \author Jason Watkins
|
||||
/// \version 1.0.1
|
||||
/// \version 1.1
|
||||
/// \since 1.0.0
|
||||
/// \date Intial Version: 2015-04-13
|
||||
/// \date Last Updated: 2015-04-29
|
||||
/// \date Last Updated: 2015-05-14
|
||||
class DataManager
|
||||
{
|
||||
public:
|
||||
@@ -161,7 +165,7 @@ namespace XPC
|
||||
/// \remarks The first time this method is called for a given dataref, it must
|
||||
/// perform a relatively expensive lookup operation to translate the
|
||||
/// given string into an X-Plane internal pointer. This value is cached,
|
||||
/// so subsequent calls will incure minimal extra overhead compared to
|
||||
/// so subsequent calls will incur minimal extra overhead compared to
|
||||
/// the other methods in this class.
|
||||
///
|
||||
/// \remarks For simplicity, this method is provided with only one output type.
|
||||
@@ -170,7 +174,7 @@ namespace XPC
|
||||
/// doubles where high precision is required, using this method may result
|
||||
/// in a loss of precision. In that case, consider using one of the
|
||||
/// strongly typed methods instead.
|
||||
static int Get(std::string dref, float values[], int size);
|
||||
static int Get(const std::string& dref, float values[], int size);
|
||||
|
||||
/// Gets the value of a double dataref.
|
||||
///
|
||||
@@ -290,7 +294,7 @@ namespace XPC
|
||||
/// doubles where high precision is required, using this method may result
|
||||
/// in a loss of precision. In that case, consider using one of the
|
||||
/// strongly typed methods instead.
|
||||
static void Set(std::string dref, float values[], int size);
|
||||
static void Set(const std::string& dref, float values[], int size);
|
||||
|
||||
/// Sets the value of a double dataref.
|
||||
///
|
||||
@@ -405,7 +409,15 @@ namespace XPC
|
||||
///
|
||||
/// \param value The flaps settings. Should be between 0.0 (no flaps) and 1.0 (full flaps).
|
||||
static void SetFlaps(float value);
|
||||
|
||||
/// Gets a default value that indicates that a dataref should not be changed.
|
||||
static float GetDefaultValue();
|
||||
|
||||
/// Checks whether the given value should be treated as a default value.
|
||||
///
|
||||
/// \param value The value to check.
|
||||
/// \returns true if value is a default value; otherwise false.
|
||||
static bool IsDefault(float value);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
//National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#include "DataManager.h"
|
||||
|
||||
namespace XPC
|
||||
{
|
||||
DREF XPData[134][8] = { DREF_None };
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
//National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#ifndef XPC_DATAMAPS_H
|
||||
#define XPC_DATAMAPS_H
|
||||
#include "DataManager.h"
|
||||
|
||||
namespace XPC
|
||||
{
|
||||
/// Maps X-Plane dataref lines to XPC DREF values.
|
||||
extern DREF XPData[134][8];
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,19 +1,19 @@
|
||||
//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
//National Aeronautics and Space Administration. All Rights Reserved.
|
||||
// Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
// National Aeronautics and Space Administration. All Rights Reserved.
|
||||
//
|
||||
//X-Plane API
|
||||
//Copyright(c) 2008, Sandy Barbour and Ben Supnik All rights reserved.
|
||||
//Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
//associated documentation files(the "Software"), to deal in the Software without restriction,
|
||||
//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
|
||||
//furnished to do so, subject to the following conditions :
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// * 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
|
||||
// without specific prior written permission from the authors or
|
||||
// Laminar Research, respectively.
|
||||
// X-Plane API
|
||||
// Copyright(c) 2008, Sandy Barbour and Ben Supnik All rights reserved.
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
// associated documentation files(the "Software"), to deal in the Software without restriction,
|
||||
// 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
|
||||
// furnished to do so, subject to the following conditions :
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// * 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
|
||||
// without specific prior written permission from the authors or
|
||||
// Laminar Research, respectively.
|
||||
#include "Drawing.h"
|
||||
|
||||
#include "XPLMDisplay.h"
|
||||
@@ -23,7 +23,7 @@
|
||||
#include <cmath>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
//OpenGL includes
|
||||
// OpenGL includes
|
||||
#if IBM
|
||||
#include <windows.h>
|
||||
#endif
|
||||
@@ -31,11 +31,11 @@
|
||||
# include <OpenGL/gl.h>
|
||||
#else
|
||||
# include <GL/gl.h>
|
||||
#endif/*__APPLE__*/
|
||||
#endif
|
||||
|
||||
namespace XPC
|
||||
{
|
||||
//Internal Structures
|
||||
// Internal Structures
|
||||
typedef struct
|
||||
{
|
||||
double x;
|
||||
@@ -43,7 +43,7 @@ namespace XPC
|
||||
double z;
|
||||
} LocalPoint;
|
||||
|
||||
//Internal Memory
|
||||
// Internal Memory
|
||||
static const size_t MSG_MAX = 1024;
|
||||
static const size_t MSG_LINE_MAX = MSG_MAX / 16;
|
||||
static bool msgEnabled = false;
|
||||
@@ -64,7 +64,9 @@ namespace XPC
|
||||
XPLMDataRef planeYref;
|
||||
XPLMDataRef planeZref;
|
||||
|
||||
//Internal Functions
|
||||
// Internal Functions
|
||||
|
||||
/// Comparse two size_t integers. Used by qsort in RemoveWaypoints.
|
||||
static int cmp(const void * a, const void * b)
|
||||
{
|
||||
std::size_t sa = *(size_t*)a;
|
||||
@@ -80,36 +82,42 @@ namespace XPC
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Draws a cube centered at the specified OpenGL world coordinates.
|
||||
///
|
||||
/// \param x The X coordinate.
|
||||
/// \param y The Y coordinate.
|
||||
/// \param z The Z coordinate.
|
||||
/// \param d The distance from the player airplane to the center of the cube.
|
||||
static void gl_drawCube(float x, float y, float z, float d)
|
||||
{
|
||||
//tan(0.25) degrees. Should scale all markers to appear about the same size
|
||||
// tan(0.25) degrees. Should scale all markers to appear about the same size
|
||||
const float TAN = 0.00436335F;
|
||||
float h = d * TAN;
|
||||
|
||||
glBegin(GL_QUAD_STRIP);
|
||||
//Top
|
||||
// Top
|
||||
glVertex3f(x - h, y + h, z - h);
|
||||
glVertex3f(x + h, y + h, z - h);
|
||||
glVertex3f(x - h, y + h, z + h);
|
||||
glVertex3f(x + h, y + h, z + h);
|
||||
//Front
|
||||
// Front
|
||||
glVertex3f(x - h, y - h, z + h);
|
||||
glVertex3f(x + h, y - h, z + h);
|
||||
//Bottom
|
||||
// Bottom
|
||||
glVertex3f(x - h, y - h, z - h);
|
||||
glVertex3f(x + h, y - h, z - h);
|
||||
//Back
|
||||
// Back
|
||||
glVertex3f(x - h, y + h, z - h);
|
||||
glVertex3f(x + h, y + h, z - h);
|
||||
|
||||
glEnd();
|
||||
glBegin(GL_QUADS);
|
||||
//Left
|
||||
// Left
|
||||
glVertex3f(x - h, y + h, z - h);
|
||||
glVertex3f(x - h, y + h, z + h);
|
||||
glVertex3f(x - h, y - h, z + h);
|
||||
glVertex3f(x - h, y - h, z - h);
|
||||
//Right
|
||||
// Right
|
||||
glVertex3f(x + h, y + h, z + h);
|
||||
glVertex3f(x + h, y + h, z - h);
|
||||
glVertex3f(x + h, y - h, z - h);
|
||||
@@ -118,25 +126,28 @@ namespace XPC
|
||||
glEnd();
|
||||
}
|
||||
|
||||
/// Draws the string set by the TEXT command.
|
||||
static int MessageDrawCallback(XPLMDrawingPhase inPhase, int inIsBefore, void * inRefcon)
|
||||
{
|
||||
const int LINE_HEIGHT = 16;
|
||||
XPLMDrawString(rgb, msgX, msgY, msgVal, NULL, xplmFont_Basic);
|
||||
int y = msgY - 16;
|
||||
int y = msgY - LINE_HEIGHT;
|
||||
for (size_t i = 0; i < newLineCount; ++i)
|
||||
{
|
||||
XPLMDrawString(rgb, msgX, y, msgVal + newLines[i], NULL, xplmFont_Basic);
|
||||
y -= 16;
|
||||
y -= LINE_HEIGHT;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/// Draws waypoints.
|
||||
static int RouteDrawCallback(XPLMDrawingPhase inPhase, int inIsBefore, void * inRefcon)
|
||||
{
|
||||
float px = XPLMGetDataf(planeXref);
|
||||
float py = XPLMGetDataf(planeYref);
|
||||
float pz = XPLMGetDataf(planeZref);
|
||||
|
||||
//Convert to local
|
||||
// Convert to local
|
||||
for (size_t i = 0; i < numWaypoints; ++i)
|
||||
{
|
||||
Waypoint* g = &waypoints[i];
|
||||
@@ -146,7 +157,7 @@ namespace XPC
|
||||
}
|
||||
|
||||
|
||||
//Draw posts
|
||||
// Draw posts
|
||||
glColor3f(1.0F, 1.0F, 1.0F);
|
||||
glBegin(GL_LINES);
|
||||
for (size_t i = 0; i < numWaypoints; ++i)
|
||||
@@ -157,7 +168,7 @@ namespace XPC
|
||||
}
|
||||
glEnd();
|
||||
|
||||
//Draw route
|
||||
// Draw route
|
||||
glColor3f(1.0F, 0.0F, 0.0F);
|
||||
glBegin(GL_LINE_STRIP);
|
||||
for (size_t i = 0; i < numWaypoints; ++i)
|
||||
@@ -167,7 +178,7 @@ namespace XPC
|
||||
}
|
||||
glEnd();
|
||||
|
||||
//Draw markers
|
||||
// Draw markers
|
||||
glColor3f(1.0F, 1.0F, 1.0F);
|
||||
for (size_t i = 0; i < numWaypoints; ++i)
|
||||
{
|
||||
@@ -181,7 +192,7 @@ namespace XPC
|
||||
return 1;
|
||||
}
|
||||
|
||||
//Public Functions
|
||||
// Public Functions
|
||||
void Drawing::ClearMessage()
|
||||
{
|
||||
XPLMUnregisterDrawCallback(MessageDrawCallback, xplm_Phase_Window, 0, NULL);
|
||||
@@ -190,8 +201,7 @@ namespace XPC
|
||||
|
||||
void Drawing::SetMessage(int x, int y, char* msg)
|
||||
{
|
||||
//Determine size of message and clear instead if the message string
|
||||
//is empty.
|
||||
// Determine the size of the message and clear it if it is empty.
|
||||
size_t len = strnlen(msg, MSG_MAX - 1);
|
||||
if (len == 0)
|
||||
{
|
||||
@@ -199,7 +209,7 @@ namespace XPC
|
||||
return;
|
||||
}
|
||||
|
||||
//Set the message, location, and mark new lines.
|
||||
// Set the message, location, and mark new lines.
|
||||
strncpy(msgVal, msg, len + 1);
|
||||
newLineCount = 0;
|
||||
for (size_t i = 0; i < len && newLineCount < MSG_LINE_MAX; ++i)
|
||||
@@ -213,7 +223,7 @@ namespace XPC
|
||||
msgX = x < 0 ? 10 : x;
|
||||
msgY = y < 0 ? 600 : y;
|
||||
|
||||
//Enable drawing if necessary
|
||||
// Enable drawing if necessary
|
||||
if (!msgEnabled)
|
||||
{
|
||||
XPLMRegisterDrawCallback(MessageDrawCallback, xplm_Phase_Window, 0, NULL);
|
||||
@@ -258,7 +268,7 @@ namespace XPC
|
||||
|
||||
void Drawing::RemoveWaypoints(Waypoint points[], size_t numPoints)
|
||||
{
|
||||
//Build a list of indices of waypoints we should delete.
|
||||
// Build a list of indices of waypoints we should delete.
|
||||
size_t delPoints[WAYPOINT_MAX];
|
||||
size_t delPointsCur = 0;
|
||||
for (size_t i = 0; i < numPoints; ++i)
|
||||
@@ -276,10 +286,10 @@ namespace XPC
|
||||
}
|
||||
}
|
||||
}
|
||||
//Sort the indices so that we only have to iterate them once
|
||||
// Sort the indices so that we only have to iterate them once
|
||||
qsort(delPoints, delPointsCur, sizeof(size_t), cmp);
|
||||
|
||||
//Copy the new array on top of the old array
|
||||
// Copy the new array on top of the old array
|
||||
size_t copyCur = 0;
|
||||
size_t count = delPointsCur;
|
||||
delPointsCur = 0;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
//National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#ifndef XPC_DRAWING_H
|
||||
#define XPC_DRAWING_H
|
||||
// Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
// National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#ifndef XPCPLUGIN_DRAWING_H_
|
||||
#define XPCPLUGIN_DRAWING_H_
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
@@ -57,5 +57,4 @@ namespace XPC
|
||||
static void RemoveWaypoints(Waypoint points[], size_t numPoints);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1,97 +1,158 @@
|
||||
//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
//National Aeronautics and Space Administration. All Rights Reserved.
|
||||
// Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
// National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#include "Log.h"
|
||||
#include <cstdarg>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
// Implementation note: I initial wrote this class using C++ iostreams, but I couldn't find any
|
||||
#include "XPLMUtilities.h"
|
||||
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
#include <ctime>
|
||||
|
||||
#include <chrono>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
// Implementation note: I initially wrote this class using C++ iostreams, but I couldn't find any
|
||||
// way to implement FormatLine without adding in a call to sprintf. It therefore seems more
|
||||
// efficient to me to just use C-style IO and call fprintf directly.
|
||||
// efficient to me to just use C-style IO and call std::fprintf directly.
|
||||
namespace XPC
|
||||
{
|
||||
static std::FILE* fd;
|
||||
static void WriteTime(FILE* fd)
|
||||
{
|
||||
time_t rawtime;
|
||||
tm* timeinfo;
|
||||
time(&rawtime);
|
||||
timeinfo = localtime(&rawtime);
|
||||
using namespace std::chrono;
|
||||
|
||||
char buffer[16] = { 0 };
|
||||
// Format is equivalent to [%F %T], but neither of those specifiers is
|
||||
// supported on Windows as of Visual Studio 13
|
||||
strftime(buffer, 16, "[%H:%M:%S] ", timeinfo);
|
||||
|
||||
fprintf(fd, buffer);
|
||||
system_clock::time_point now = system_clock::now();
|
||||
std::time_t now_tt = system_clock::to_time_t(now);
|
||||
system_clock::time_point now_sec = system_clock::from_time_t(now_tt);
|
||||
milliseconds ms = duration_cast<milliseconds>(now - now_sec);
|
||||
std::tm * tm = std::localtime(&now_tt);
|
||||
|
||||
std::stringstream ss;
|
||||
ss << std::setfill('0')
|
||||
<< std::setw(2) << tm->tm_hour << ":"
|
||||
<< std::setw(2) << tm->tm_min << ":"
|
||||
<< std::setw(2) << tm->tm_sec << "."
|
||||
<< std::setw(3) << ms.count() << "|";
|
||||
|
||||
std::fprintf(fd, ss.str().c_str());
|
||||
}
|
||||
|
||||
void Log::Initialize(std::string version)
|
||||
static void WriteLevel(FILE* fd, int level)
|
||||
{
|
||||
FILE* fd = fopen("XPCLog.txt", "w");
|
||||
char* str;
|
||||
switch (level)
|
||||
{
|
||||
case LOG_OFF:
|
||||
str = " OFF|";
|
||||
break;
|
||||
case LOG_FATAL:
|
||||
str = "FATAL|";
|
||||
break;
|
||||
case LOG_ERROR:
|
||||
str = "ERROR|";
|
||||
break;
|
||||
case LOG_WARN:
|
||||
str = " WARN|";
|
||||
break;
|
||||
case LOG_INFO:
|
||||
str = " INFO|";
|
||||
break;
|
||||
case LOG_DEBUG:
|
||||
str = "DEBUG|";
|
||||
break;
|
||||
case LOG_TRACE:
|
||||
str = "TRACE|";
|
||||
break;
|
||||
default:
|
||||
str = " UNK|";
|
||||
break;
|
||||
}
|
||||
std::fprintf(fd, str);
|
||||
}
|
||||
|
||||
void Log::Initialize(const std::string& version)
|
||||
{
|
||||
if (LOG_LEVEL == LOG_OFF)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Note: Mode "w" deletes an existing file with the same name. This means that we only
|
||||
// ever get the log from the last run. This matches the way that X-Plane treats its
|
||||
// log.
|
||||
fd = std::fopen("XPCLog.txt", "w");
|
||||
if (fd != NULL)
|
||||
{
|
||||
time_t rawtime;
|
||||
tm* timeinfo;
|
||||
time(&rawtime);
|
||||
timeinfo = localtime(&rawtime);
|
||||
std::time_t rawtime;
|
||||
std::tm* timeinfo;
|
||||
std::time(&rawtime);
|
||||
timeinfo = std::localtime(&rawtime);
|
||||
|
||||
char timeStr[16] = { 0 };
|
||||
// Format is equivalent to %F, but neither of those specifiers is
|
||||
// supported on Windows as of Visual Studio 13
|
||||
strftime(timeStr, 16, "%Y-%m-%d", timeinfo);
|
||||
std::strftime(timeStr, 16, "%Y-%m-%d", timeinfo);
|
||||
|
||||
fprintf(fd, "X-Plane Connect [Version %s]\n", version.c_str());
|
||||
fprintf(fd, "Compiled %s %s\n", __DATE__, __TIME__);
|
||||
fprintf(fd, "Copyright (c) 2013-2015 United States Government as represented by the\n");
|
||||
fprintf(fd, "Administrator of the National Aeronautics and Space Administration.\n");
|
||||
fprintf(fd, "All Rights Reserved.\n\n");
|
||||
std::fprintf(fd, "X-Plane Connect [Version %s]\n", version.c_str());
|
||||
std::fprintf(fd, "Compiled %s %s\n", __DATE__, __TIME__);
|
||||
std::fprintf(fd, "Copyright (c) 2013-2015 United States Government as represented by the\n");
|
||||
std::fprintf(fd, "Administrator of the National Aeronautics and Space Administration.\n");
|
||||
std::fprintf(fd, "All Rights Reserved.\n\n");
|
||||
|
||||
fprintf(fd, "This file contains debugging information about the X-Plane Connect plugin.\n");
|
||||
fprintf(fd, "If you have technical issues with the plugin, please report them by opening\n");
|
||||
fprintf(fd, "an issue on GitHub (https://github.com/nasa/XPlaneConnect/issues) or by\n");
|
||||
fprintf(fd, "emailing Christopher Teubert (christopher.a.teubert@nasa.gov).\n\n");
|
||||
std::fprintf(fd, "This file contains debugging information about the X-Plane Connect plugin.\n");
|
||||
std::fprintf(fd, "If you have technical issues with the plugin, please report them by opening\n");
|
||||
std::fprintf(fd, "an issue on GitHub (https://github.com/nasa/XPlaneConnect/issues) or by\n");
|
||||
std::fprintf(fd, "emailing Christopher Teubert (christopher.a.teubert@nasa.gov).\n\n");
|
||||
|
||||
fprintf(fd, "Log file generated on %s.\n", timeStr);
|
||||
fclose(fd);
|
||||
int xpVer;
|
||||
int xplmVer;
|
||||
XPLMHostApplicationID hostID;
|
||||
XPLMGetVersions(&xpVer, &xplmVer, &hostID);
|
||||
std::fprintf(fd, "X-Plane Version: %d\n", xpVer);
|
||||
std::fprintf(fd, "Plugin Manager Version: %d\n", xplmVer);
|
||||
std::fprintf(fd, "Host Application ID: %d\n", hostID);
|
||||
std::fprintf(fd, "Log file generated on %s.\n", timeStr);
|
||||
std::fflush(fd);
|
||||
}
|
||||
}
|
||||
|
||||
void Log::WriteLine(const std::string& value)
|
||||
void Log::Close()
|
||||
{
|
||||
Log::WriteLine(value.c_str());
|
||||
if (fd)
|
||||
{
|
||||
std::fclose(fd);
|
||||
}
|
||||
}
|
||||
|
||||
void Log::WriteLine(const char* value)
|
||||
void Log::WriteLine(int level, const std::string& tag, const std::string& value)
|
||||
{
|
||||
FILE* fd = fopen("XPCLog.txt", "a");
|
||||
if (!fd)
|
||||
if (level > LOG_LEVEL || !fd)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
WriteTime(fd);
|
||||
fprintf(fd, "%s\n", value);
|
||||
|
||||
fclose(fd);
|
||||
WriteLevel(fd, level);
|
||||
std::fprintf(fd, "%s|%s\n", tag.c_str(), value.c_str());
|
||||
std::fflush(fd);
|
||||
}
|
||||
|
||||
void Log::FormatLine(const char* format, ...)
|
||||
void Log::FormatLine(int level, const std::string& tag, std::string format, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
FILE* fd = fopen("XPCLog.txt", "a");
|
||||
if (!fd)
|
||||
if (level > LOG_LEVEL || !fd)
|
||||
{
|
||||
return;
|
||||
}
|
||||
va_start(args, format);
|
||||
|
||||
WriteTime(fd);
|
||||
vfprintf(fd, format, args);
|
||||
fprintf(fd, "\n");
|
||||
|
||||
fclose(fd);
|
||||
WriteLevel(fd, level);
|
||||
std::fprintf(fd, "%s|", tag.c_str());
|
||||
std::vfprintf(fd, format.c_str(), args);
|
||||
std::fprintf(fd, "\n");
|
||||
std::fflush(fd);
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,28 @@
|
||||
//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
//National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#ifndef XPC_LOG_H
|
||||
#define XPC_LOG_H
|
||||
// Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
// National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#ifndef XPCPLUGIN_LOG_H_
|
||||
#define XPCPLUGIN_LOG_H_
|
||||
#include <string>
|
||||
|
||||
// LOG_VERBOSITY determines the level of logging throughout the plugin.
|
||||
// 0: Minimum logging. Only plugin manager events will be logged.
|
||||
// 1: Critical errors. When an error that prevents correct operation of the
|
||||
// plugin, attempt to write useful information to the log. Note that since
|
||||
// XPC runs inside the X-Plane executable, we try very hard no to crash.
|
||||
// As a result, these log messages may be the only indication of failure.
|
||||
// 2: All errors. Any time something unexpected happens, log it.
|
||||
// 3: Significant actions. Any time something happens outside of normal
|
||||
// command processing, log it.
|
||||
// 5: Everything. Log nearly every single action the plugin takes. This may
|
||||
// have a detrimental impact on X-Plane performance.
|
||||
#define LOG_VERBOSITY 2
|
||||
// OFF: No logging at all will be performed.
|
||||
// FATAL: Critical errors that would normally result in termination of the program. Because XPC
|
||||
// operates in the X-Plane process, we try to never actually crash. As a result, we this
|
||||
// level of logging may be the only indication of a problem.
|
||||
// ERROR: All errors not covered by FATAL
|
||||
// WARN: Potentially, but not definitely, incorrect behavior
|
||||
// INFO: Information about normal actions taken by the plugin.
|
||||
// DEBUG: More verbose information usefull for debugging.
|
||||
// TRACE: Log all the things!
|
||||
#define LOG_OFF 0
|
||||
#define LOG_FATAL 1
|
||||
#define LOG_ERROR 2
|
||||
#define LOG_WARN 3
|
||||
#define LOG_INFO 4
|
||||
#define LOG_DEBUG 5
|
||||
#define LOG_TRACE 6
|
||||
|
||||
#define LOG_LEVEL LOG_TRACE
|
||||
|
||||
namespace XPC
|
||||
{
|
||||
@@ -23,37 +30,37 @@ namespace XPC
|
||||
///
|
||||
/// \details Provides functions to write lines to the XPC log file.
|
||||
/// \author Jason Watkins
|
||||
/// \version 1.0
|
||||
/// \version 1.1
|
||||
/// \since 1.0
|
||||
/// \date Intial Version: 2015-04-09
|
||||
/// \date Last Updated: 2015-04-09
|
||||
/// \date Last Updated: 2015-05-11
|
||||
class Log
|
||||
{
|
||||
public:
|
||||
/// Initializes the logging component by deleting old log files,
|
||||
/// writing header information to the log file.
|
||||
static void Initialize(std::string header);
|
||||
static void Initialize(const std::string& header);
|
||||
|
||||
/// Writes the C string pointed to by format, followed by a line
|
||||
/// Closes the log file.
|
||||
static void Close();
|
||||
|
||||
/// Writes the string pointed to by format, followed by a line
|
||||
/// terminator to the XPC log file. If format contains format
|
||||
/// specifiers, additional arguments following format will be formatted
|
||||
/// and inserted in the resulting string, replacing their respective
|
||||
/// specifiers.
|
||||
///
|
||||
/// \param format The format string appropriate for consumption by sprintf.
|
||||
static void FormatLine(const char* format, ...);
|
||||
///
|
||||
/// \remarks Note that Visual C++ silently fails va_start when the last non-varargs
|
||||
/// argument is a reference, so we need a value-type format here.
|
||||
static void FormatLine(int level, const std::string& tag, const std::string format, ...);
|
||||
|
||||
/// Writes the specified string value, followed by a line terminator
|
||||
/// to the XPC log file.
|
||||
///
|
||||
/// \param value The value to write.
|
||||
static void WriteLine(const std::string& value);
|
||||
|
||||
/// Writes the specified C string value, followed by a line terminator
|
||||
/// to the XPC log file.
|
||||
///
|
||||
/// \param value The value to write.
|
||||
static void WriteLine(const char* value);
|
||||
static void WriteLine(int level, const std::string& tag, const std::string& value);
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
//National Aeronautics and Space Administration. All Rights Reserved.
|
||||
// Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
// National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#include "Message.h"
|
||||
#include "Log.h"
|
||||
|
||||
@@ -11,56 +11,49 @@ namespace XPC
|
||||
{
|
||||
Message::Message() {}
|
||||
|
||||
Message Message::ReadFrom(UDPSocket& sock)
|
||||
Message Message::ReadFrom(const UDPSocket& sock)
|
||||
{
|
||||
Message m;
|
||||
int len = sock.Read(m.buffer, bufferSize, &m.source);
|
||||
m.size = len < 0 ? 0 : len;
|
||||
if (len > 0)
|
||||
{
|
||||
Log::FormatLine(LOG_TRACE, "MESG", "Read message with length %i", len);
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
unsigned long Message::GetMagicNumber()
|
||||
|
||||
unsigned long Message::GetMagicNumber() const
|
||||
{
|
||||
if (size < 4)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return *((unsigned long*)buffer);
|
||||
unsigned long val = size < 4 ? 0 : *((unsigned long*)buffer);
|
||||
return val;
|
||||
}
|
||||
|
||||
std::string Message::GetHead()
|
||||
std::string Message::GetHead() const
|
||||
{
|
||||
if (size < 4)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
return std::string((char*)buffer, 4);
|
||||
std::string val = size < 4 ? "" : std::string((char*)buffer, 4);
|
||||
return val;
|
||||
}
|
||||
|
||||
const unsigned char* Message::GetBuffer()
|
||||
const unsigned char* Message::GetBuffer() const
|
||||
{
|
||||
if (size == 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return buffer;
|
||||
const unsigned char* val = size == 0 ? NULL : buffer;
|
||||
return val;
|
||||
}
|
||||
|
||||
std::size_t Message::GetSize()
|
||||
std::size_t Message::GetSize() const
|
||||
{
|
||||
return size;
|
||||
}
|
||||
|
||||
struct sockaddr Message::GetSource()
|
||||
struct sockaddr Message::GetSource() const
|
||||
{
|
||||
return source;
|
||||
}
|
||||
|
||||
void Message::PrintToLog()
|
||||
void Message::PrintToLog() const
|
||||
{
|
||||
#if LOG_VERBOSITY > 4
|
||||
std::stringstream ss;
|
||||
ss << "[DEBUG]";
|
||||
|
||||
// Dump raw bytes to string
|
||||
ss << std::hex << std::setfill('0');
|
||||
@@ -68,18 +61,17 @@ namespace XPC
|
||||
{
|
||||
ss << ' ' << std::setw(2) << static_cast<unsigned>(buffer[i]);
|
||||
}
|
||||
Log::WriteLine(ss.str());
|
||||
Log::WriteLine(LOG_DEBUG, "DBUG", ss.str());
|
||||
|
||||
ss << std::dec;
|
||||
ss.str("");
|
||||
ss << "[" << GetHead() << "-DEBUG] (" << GetSize() << ")";
|
||||
ss << "Head: " << GetHead() << "(0x" << std::setw(8) << GetMagicNumber() << ")" << std::dec << " Size: " << GetSize();
|
||||
switch (GetMagicNumber()) // Binary version of head
|
||||
{
|
||||
case 0x4E4EF443: // CONN
|
||||
case 0x54505957: // WYPT
|
||||
case 0x54584554: // TEXT
|
||||
{
|
||||
Log::WriteLine(ss.str());
|
||||
Log::WriteLine(LOG_DEBUG, "DBUG", ss.str());
|
||||
break;
|
||||
}
|
||||
case 0x4C525443: // CTRL
|
||||
@@ -98,7 +90,7 @@ namespace XPC
|
||||
}
|
||||
ss << " Attitude:(" << pitch << " " << roll << " " << yaw << ")";
|
||||
ss << " Thr:" << thr << " Gear:" << (int)gear << " Flaps:" << flaps;
|
||||
Log::WriteLine(ss.str());
|
||||
Log::WriteLine(LOG_DEBUG, "DBUG", ss.str());
|
||||
break;
|
||||
}
|
||||
case 0x41544144: // DATA
|
||||
@@ -108,45 +100,46 @@ namespace XPC
|
||||
for (int i = 0; i < numCols; ++i)
|
||||
{
|
||||
values[i][0] = buffer[5 + 36 * i];
|
||||
memcpy(values[i] + 1, buffer + 9 + 36 * i, 9 * sizeof(float));
|
||||
std::memcpy(values[i] + 1, buffer + 9 + 36 * i, 9 * sizeof(float));
|
||||
}
|
||||
ss << " (" << numCols << " lines)";
|
||||
Log::WriteLine(ss.str());
|
||||
ss << " (" << numCols << " lines)";
|
||||
Log::WriteLine(LOG_DEBUG, "DBUG", ss.str());
|
||||
for (int i = 0; i < numCols; ++i)
|
||||
{
|
||||
ss.str("");
|
||||
ss << "\t#" << values[i][0];
|
||||
ss << " #" << values[i][0];
|
||||
for (int j = 1; j < 9; ++j)
|
||||
{
|
||||
ss << " " << values[i][j];
|
||||
}
|
||||
Log::WriteLine(ss.str());
|
||||
}
|
||||
Log::WriteLine(LOG_DEBUG, "DBUG", ss.str());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x46455244: // DREF
|
||||
{
|
||||
Log::WriteLine(ss.str());
|
||||
{
|
||||
Log::WriteLine(LOG_DEBUG, "DBUG", ss.str());
|
||||
std::string dref((char*)buffer + 6, buffer[5]);
|
||||
Log::FormatLine("-\tDREF (size %i) = %s", dref.length(), dref.c_str());
|
||||
Log::FormatLine(LOG_DEBUG, "DBUG", " DREF (size %i) = %s", dref.length(), dref.c_str());
|
||||
ss.str("");
|
||||
int values = buffer[6 + buffer[5]];
|
||||
ss << "\tValues(size " << values << ") =";
|
||||
ss << " Values(size " << values << ") =";
|
||||
for (int i = 0; i < values; ++i)
|
||||
{
|
||||
ss << " " << *((float*)(buffer + values + 1 + sizeof(float) * i));
|
||||
}
|
||||
Log::WriteLine(ss.str());
|
||||
}
|
||||
Log::WriteLine(LOG_DEBUG, "DBUG", ss.str());
|
||||
break;
|
||||
}
|
||||
case 0x44544547: // GETD
|
||||
{
|
||||
Log::WriteLine(ss.str());
|
||||
{
|
||||
Log::WriteLine(LOG_DEBUG, "DBUG", ss.str());
|
||||
int cur = 6;
|
||||
for (int i = 0; i < buffer[5]; ++i)
|
||||
{
|
||||
std::string dref((char*)buffer + cur + 1, buffer[cur]);
|
||||
Log::FormatLine("\t#%i/%i (size:%i) %s", i + 1, buffer[5], dref.length(), dref.c_str());
|
||||
Log::FormatLine(LOG_DEBUG, "DBUG", " #%i/%i (size:%i) %s",
|
||||
i + 1, buffer[5], dref.length(), dref.c_str());
|
||||
cur += 1 + buffer[cur];
|
||||
}
|
||||
break;
|
||||
@@ -157,28 +150,27 @@ namespace XPC
|
||||
float gear = *((float*)(buffer + 30));
|
||||
float pos[3];
|
||||
float orient[3];
|
||||
memcpy(pos, buffer + 6, 12);
|
||||
memcpy(orient, buffer + 18, 12);
|
||||
std::memcpy(pos, buffer + 6, 12);
|
||||
std::memcpy(orient, buffer + 18, 12);
|
||||
ss << " AC:" << (int)aircraft;
|
||||
ss << " Pos:(" << pos[0] << ' ' << pos[1] << ' ' << pos[2] << ") Orient:(";
|
||||
ss << orient[3] << ' ' << orient[4] << ' ' << orient[5] << ") Gear:";
|
||||
ss << gear;
|
||||
Log::WriteLine(ss.str());
|
||||
ss << gear;
|
||||
Log::WriteLine(LOG_DEBUG, "DBUG", ss.str());
|
||||
break;
|
||||
}
|
||||
case 0x554D4953: // SIMU
|
||||
{
|
||||
ss << ' ' << (int)buffer[5];
|
||||
Log::WriteLine(ss.str());
|
||||
ss << ' ' << (int)buffer[5];
|
||||
Log::WriteLine(LOG_DEBUG, "DBUG", ss.str());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
ss << " UNKNOWN HEADER ";
|
||||
Log::WriteLine(ss.str());
|
||||
ss << " UNKNOWN HEADER ";
|
||||
Log::WriteLine(LOG_DEBUG, "DBUG", ss.str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
//National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#ifndef XPC_MESSAGE_H
|
||||
#define XPC_MESSAGE_H
|
||||
// Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
// National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#ifndef XPCPLUGIN_MESSAGE_H_
|
||||
#define XPCPLUGIN_MESSAGE_H_
|
||||
|
||||
#include "UDPSocket.h"
|
||||
|
||||
@@ -10,10 +10,10 @@ namespace XPC
|
||||
/// Represents a message received from an XPC client.
|
||||
///
|
||||
/// \author Jason Watkins
|
||||
/// \version 1.0
|
||||
/// \version 1.1
|
||||
/// \since 1.0
|
||||
/// \date Intial Version: 2015-04-11
|
||||
/// \date Last Updated: 2015-04-11
|
||||
/// \date Last Updated: 2015-05-11
|
||||
class Message
|
||||
{
|
||||
public:
|
||||
@@ -24,25 +24,25 @@ namespace XPC
|
||||
/// \returns A message parsed from the data read from sock. If no
|
||||
/// data was read or an error occurs, returns a message
|
||||
/// with the size set to 0.
|
||||
static Message ReadFrom(UDPSocket& sock);
|
||||
static Message ReadFrom(const UDPSocket& sock);
|
||||
|
||||
/// Gets the message header in binary form.
|
||||
unsigned long GetMagicNumber();
|
||||
unsigned long GetMagicNumber() const;
|
||||
|
||||
/// Gets the message header.
|
||||
std::string GetHead();
|
||||
std::string GetHead() const;
|
||||
|
||||
/// Gets the buffer underlying the message.
|
||||
const unsigned char* GetBuffer();
|
||||
const unsigned char* GetBuffer() const;
|
||||
|
||||
/// Gets the size of the message in bytes.
|
||||
std::size_t GetSize();
|
||||
std::size_t GetSize() const;
|
||||
|
||||
/// Gets the address this message was read from.
|
||||
struct sockaddr GetSource();
|
||||
struct sockaddr GetSource() const;
|
||||
|
||||
/// Prints the contents of the message to the XPC log.
|
||||
void PrintToLog();
|
||||
void PrintToLog() const;
|
||||
|
||||
private:
|
||||
Message();
|
||||
@@ -53,5 +53,4 @@ namespace XPC
|
||||
struct sockaddr source;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1,11 +1,26 @@
|
||||
//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
//National Aeronautics and Space Administration. All Rights Reserved.
|
||||
// Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
// National Aeronautics and Space Administration. All Rights Reserved.
|
||||
//
|
||||
// X-Plane API
|
||||
// Copyright(c) 2008, Sandy Barbour and Ben Supnik All rights reserved.
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
// associated documentation files(the "Software"), to deal in the Software without restriction,
|
||||
// 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
|
||||
// furnished to do so, subject to the following conditions :
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// * 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
|
||||
// without specific prior written permission from the authors or
|
||||
// Laminar Research, respectively.
|
||||
#include "MessageHandlers.h"
|
||||
#include "DataManager.h"
|
||||
#include "DataMaps.h"
|
||||
#include "Drawing.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include "XPLMUtilities.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
|
||||
@@ -20,6 +35,7 @@ namespace XPC
|
||||
|
||||
void MessageHandlers::SetSocket(UDPSocket* socket)
|
||||
{
|
||||
Log::WriteLine(LOG_TRACE, "MSGH", "Setting socket");
|
||||
MessageHandlers::sock = socket;
|
||||
}
|
||||
|
||||
@@ -27,6 +43,7 @@ namespace XPC
|
||||
{
|
||||
if (handlers.size() == 0)
|
||||
{
|
||||
Log::WriteLine(LOG_TRACE, "MSGH", "Initializing handlers");
|
||||
// Common messages
|
||||
handlers.insert(std::make_pair("CONN", MessageHandlers::HandleConn));
|
||||
handlers.insert(std::make_pair("CTRL", MessageHandlers::HandleCtrl));
|
||||
@@ -37,8 +54,7 @@ namespace XPC
|
||||
handlers.insert(std::make_pair("SIMU", MessageHandlers::HandleSimu));
|
||||
handlers.insert(std::make_pair("TEXT", MessageHandlers::HandleText));
|
||||
handlers.insert(std::make_pair("WYPT", MessageHandlers::HandleWypt));
|
||||
// Not implemented messages
|
||||
handlers.insert(std::make_pair("VIEW", MessageHandlers::HandleUnknown));
|
||||
handlers.insert(std::make_pair("VIEW", MessageHandlers::HandleView));
|
||||
// X-Plane data messages
|
||||
handlers.insert(std::make_pair("DSEL", MessageHandlers::HandleXPlaneData));
|
||||
handlers.insert(std::make_pair("USEL", MessageHandlers::HandleXPlaneData));
|
||||
@@ -66,16 +82,14 @@ namespace XPC
|
||||
std::string head = msg.GetHead();
|
||||
if (head == "")
|
||||
{
|
||||
Log::WriteLine(LOG_WARN, "MSGH", "Warning: HandleMessage called with empty message.");
|
||||
return; // No Message to handle
|
||||
}
|
||||
msg.PrintToLog();
|
||||
|
||||
// Set current connection
|
||||
sockaddr sourceaddr = msg.GetSource();
|
||||
connectionKey = UDPSocket::GetHost(&sourceaddr);
|
||||
#if LOG_VERBOSITY > 4
|
||||
Log::FormatLine("[MSGH] Handling message from %s", connectionKey.c_str());
|
||||
#endif
|
||||
Log::FormatLine(LOG_INFO, "MSGH", "Handling message from %s", connectionKey.c_str());
|
||||
std::map<std::string, ConnectionInfo>::iterator conn = connections.find(connectionKey);
|
||||
if (conn == connections.end()) // New connection
|
||||
{
|
||||
@@ -87,19 +101,17 @@ namespace XPC
|
||||
connection.addr = sourceaddr;
|
||||
connection.getdCount = 0;
|
||||
connections[connectionKey] = connection;
|
||||
#if LOG_VERBOSITY > 2
|
||||
Log::FormatLine("[MSGH] New connection. ID=%u, Remote=%s", connection.id, connectionKey.c_str());
|
||||
#endif
|
||||
Log::FormatLine(LOG_DEBUG, "MSGH", "New connection. ID=%u, Remote=%s",
|
||||
connection.id, connectionKey.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
connection = (*conn).second;
|
||||
#if LOG_VERBOSITY > 3
|
||||
Log::FormatLine("[MSGH] Existing connection. ID=%u, Remote=%s",
|
||||
Log::FormatLine(LOG_DEBUG, "MSGH", "Existing connection. ID=%u, Remote=%s",
|
||||
connection.id, connectionKey.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
msg.PrintToLog();
|
||||
// Check if there is a handler for this message type. If so, execute
|
||||
// that handler. Otherwise, execute the unknown message handler.
|
||||
std::map<std::string, MessageHandler>::iterator iter = handlers.find(head);
|
||||
@@ -114,7 +126,7 @@ namespace XPC
|
||||
}
|
||||
}
|
||||
|
||||
void MessageHandlers::HandleConn(Message& msg)
|
||||
void MessageHandlers::HandleConn(const Message& msg)
|
||||
{
|
||||
const unsigned char* buffer = msg.GetBuffer();
|
||||
|
||||
@@ -123,23 +135,21 @@ namespace XPC
|
||||
sockaddr* sa = &connection.addr;
|
||||
switch (sa->sa_family)
|
||||
{
|
||||
case AF_INET:
|
||||
case AF_INET: // IPV4 address
|
||||
{
|
||||
sockaddr_in* sin = reinterpret_cast<sockaddr_in*>(sa);
|
||||
(*sin).sin_port = htons(port);
|
||||
break;
|
||||
}
|
||||
case AF_INET6:
|
||||
case AF_INET6: // IPV6 addres
|
||||
{
|
||||
sockaddr_in6* sin = reinterpret_cast<sockaddr_in6*>(sa);
|
||||
(*sin).sin6_port = htons(port);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
#if LOG_VERBOSITY > 0
|
||||
Log::WriteLine("[CONN] ERROR: Unknown address type.");
|
||||
Log::WriteLine(LOG_ERROR, "CONN", "ERROR: Unknown address type.");
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
connections.erase(connectionKey);
|
||||
connectionKey = UDPSocket::GetHost(&connection.addr);
|
||||
@@ -150,31 +160,26 @@ namespace XPC
|
||||
response[5] = connection.id;
|
||||
|
||||
// Update log
|
||||
#if LOG_VERBOSITY > 1
|
||||
Log::FormatLine("[CONN] ID: %u New destination port: %u",
|
||||
Log::FormatLine(LOG_TRACE, "CONN", "ID: %u New destination port: %u",
|
||||
connection.id, port);
|
||||
#endif
|
||||
|
||||
// Send response
|
||||
sock->SendTo(response, 6, &connection.addr);
|
||||
}
|
||||
|
||||
void MessageHandlers::HandleCtrl(Message& msg)
|
||||
void MessageHandlers::HandleCtrl(const Message& msg)
|
||||
{
|
||||
// Update Log
|
||||
#if LOG_VERBOSITY > 2
|
||||
Log::FormatLine("[CTRL] Message Received (Conn %i)", connection.id);
|
||||
#endif
|
||||
Log::FormatLine(LOG_TRACE, "CTRL", "Message Received (Conn %i)", connection.id);
|
||||
|
||||
const unsigned char* buffer = msg.GetBuffer();
|
||||
std::size_t size = msg.GetSize();
|
||||
//Legacy packets that don't specify an aircraft number should be 26 bytes long.
|
||||
//Packets specifying an A/C num should be 27 bytes.
|
||||
if (size != 26 && size != 27)
|
||||
// Legacy packets that don't specify an aircraft number should be 26 bytes long.
|
||||
// Packets specifying an A/C num should be 27 bytes. Packets specifying a speedbrake
|
||||
// should be 31 bytes.
|
||||
if (size != 26 && size != 27 && size != 31)
|
||||
{
|
||||
#if LOG_VERBOSITY > 0
|
||||
Log::FormatLine("[CTRL] ERROR: Unexpected message length (%i)", size);
|
||||
#endif
|
||||
Log::FormatLine(LOG_ERROR, "CTRL", "ERROR: Unexpected message length (%i)", size);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -182,41 +187,63 @@ namespace XPC
|
||||
float pitch = *((float*)(buffer + 5));
|
||||
float roll = *((float*)(buffer + 9));
|
||||
float yaw = *((float*)(buffer + 13));
|
||||
float thr = *((float*)(buffer + 17));
|
||||
float throttle = *((float*)(buffer + 17));
|
||||
char gear = buffer[21];
|
||||
float flaps = *((float*)(buffer + 22));
|
||||
unsigned char aircraft = 0;
|
||||
if (size == 27)
|
||||
unsigned char aircraftNumber = 0;
|
||||
if (size >= 27)
|
||||
{
|
||||
aircraft = buffer[26];
|
||||
aircraftNumber = buffer[26];
|
||||
}
|
||||
float spdbrk = DataManager::GetDefaultValue();
|
||||
if (size >= 31)
|
||||
{
|
||||
spdbrk = *((float*)(buffer + 27));
|
||||
}
|
||||
|
||||
float thrArray[8];
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
thrArray[i] = thr;
|
||||
}
|
||||
|
||||
DataManager::Set(DREF_YokePitch, pitch, aircraft);
|
||||
DataManager::Set(DREF_YokeRoll, roll, aircraft);
|
||||
DataManager::Set(DREF_YokeHeading, yaw, aircraft);
|
||||
DataManager::Set(DREF_ThrottleSet, thrArray, 8, aircraft);
|
||||
DataManager::Set(DREF_ThrottleActual, thrArray, 8, aircraft);
|
||||
if (aircraft == 0)
|
||||
if (!DataManager::IsDefault(pitch))
|
||||
{
|
||||
DataManager::Set("sim/flightmodel/engine/ENGN_thro_override", thrArray, 1);
|
||||
DataManager::Set(DREF_YokePitch, pitch, aircraftNumber);
|
||||
}
|
||||
if (!DataManager::IsDefault(roll))
|
||||
{
|
||||
DataManager::Set(DREF_YokeRoll, roll, aircraftNumber);
|
||||
}
|
||||
if (!DataManager::IsDefault(yaw))
|
||||
{
|
||||
DataManager::Set(DREF_YokeHeading, yaw, aircraftNumber);
|
||||
}
|
||||
if (!DataManager::IsDefault(throttle))
|
||||
{
|
||||
|
||||
float throttleArray[8];
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
throttleArray[i] = throttle;
|
||||
}
|
||||
DataManager::Set(DREF_ThrottleSet, throttleArray, 8, aircraftNumber);
|
||||
DataManager::Set(DREF_ThrottleActual, throttleArray, 8, aircraftNumber);
|
||||
if (aircraftNumber == 0)
|
||||
{
|
||||
DataManager::Set("sim/flightmodel/engine/ENGN_thro_override", throttleArray, 1);
|
||||
}
|
||||
}
|
||||
if (gear != -1)
|
||||
{
|
||||
DataManager::SetGear(gear, false, aircraft);
|
||||
DataManager::SetGear(gear, false, aircraftNumber);
|
||||
}
|
||||
if (flaps < -999.5 || flaps > -997.5)
|
||||
if (!DataManager::IsDefault(flaps))
|
||||
{
|
||||
DataManager::Set(DREF_FlapSetting, flaps, aircraft);
|
||||
DataManager::Set(DREF_FlapSetting, flaps, aircraftNumber);
|
||||
}
|
||||
if (!DataManager::IsDefault(spdbrk))
|
||||
{
|
||||
DataManager::Set(DREF_SpeedBrakeSet, spdbrk, aircraftNumber);
|
||||
}
|
||||
}
|
||||
|
||||
void MessageHandlers::HandleData(Message& msg)
|
||||
void MessageHandlers::HandleData(const Message& msg)
|
||||
{
|
||||
// Parse data
|
||||
const unsigned char* buffer = msg.GetBuffer();
|
||||
@@ -224,59 +251,51 @@ namespace XPC
|
||||
std::size_t numCols = (size - 5) / 36;
|
||||
if (numCols > 0)
|
||||
{
|
||||
#if LOG_VERBOSITY > 1
|
||||
Log::FormatLine("[DATA] Message Received (Conn %i)", connection.id);
|
||||
#endif
|
||||
Log::FormatLine(LOG_TRACE, "DATA", "Message Received (Conn %i)", connection.id);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if LOG_VERBOSITY > 0
|
||||
Log::FormatLine("[DATA] WARNING: Empty data packet received (Conn %i)", connection.id);
|
||||
#endif
|
||||
Log::FormatLine(LOG_WARN, "DATA", "WARNING: Empty data packet received (Conn %i)", connection.id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (numCols > 134) // Error. Will overflow values
|
||||
{
|
||||
#if LOG_VERBOSITY > 0
|
||||
Log::FormatLine("[DATA] ERROR: numCols to large.");
|
||||
#endif
|
||||
Log::FormatLine(LOG_ERROR, "DATA", "ERROR: numCols to large.");
|
||||
return;
|
||||
}
|
||||
float values[134][9];
|
||||
for (int i = 0; i < numCols; ++i)
|
||||
{
|
||||
// 5 byte header + (9 * 4 = 36) bytes per row
|
||||
values[i][0] = buffer[5 + 36 * i];
|
||||
memcpy(values[i] + 1, buffer + 9 + 36 * i, 9 * sizeof(float));
|
||||
}
|
||||
|
||||
// Update log
|
||||
|
||||
float savedAlpha = -998;
|
||||
float savedHPath = -998;
|
||||
float savedAlpha = DataManager::GetDefaultValue();
|
||||
float savedHPath = DataManager::GetDefaultValue();
|
||||
for (int i = 0; i < numCols; ++i)
|
||||
{
|
||||
unsigned char dataRef = (unsigned char)values[i][0];
|
||||
if (dataRef >= 134)
|
||||
{
|
||||
#if LOG_VERBOSITY > 0
|
||||
Log::FormatLine("[DATA] ERROR: DataRef # must be between 0 - 134 (Received: %hi)", (int)dataRef);
|
||||
#endif
|
||||
Log::FormatLine(LOG_ERROR, "DATA", "ERROR: DataRef # must be between 0 - 134 (Received: %hi)", (int)dataRef);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (dataRef)
|
||||
{
|
||||
// TODO(jason-watkins): This currently overwrites the velocity several times. Should look into making this case smarter somehow.
|
||||
case 3: // Velocity
|
||||
{
|
||||
float theta = DataManager::GetFloat(DREF_Pitch);
|
||||
float alpha = savedAlpha != -998 ? savedAlpha : DataManager::GetFloat(DREF_AngleOfAttack);
|
||||
float hpath = savedHPath != -998 ? savedHPath : DataManager::GetFloat(DREF_HPath);
|
||||
float alpha = DataManager::IsDefault(savedAlpha) ? savedAlpha : DataManager::GetFloat(DREF_AngleOfAttack);
|
||||
float hpath = DataManager::IsDefault(savedHPath) ? savedHPath : DataManager::GetFloat(DREF_HPath);
|
||||
if (alpha != alpha || hpath != hpath)
|
||||
{
|
||||
#if LOG_VERBOSITY > 0
|
||||
Log::WriteLine("[DATA] ERROR: Value must be a number (NaN received)");
|
||||
#endif
|
||||
Log::WriteLine(LOG_ERROR, "DATA", "ERROR: Value must be a number (NaN received)");
|
||||
break;
|
||||
}
|
||||
const float deg2rad = 0.0174532925F;
|
||||
@@ -284,7 +303,7 @@ namespace XPC
|
||||
for (int j = 0; j < 3; ++j)
|
||||
{
|
||||
float v = values[i][ind[j]];
|
||||
if (v != -998)
|
||||
if (!DataManager::IsDefault(v))
|
||||
{
|
||||
DataManager::Set(DREF_LocalVX, v*cos((theta - alpha)*deg2rad)*sin(hpath*deg2rad));
|
||||
DataManager::Set(DREF_LocalVY, v*sin((theta - alpha)*deg2rad));
|
||||
@@ -295,27 +314,25 @@ namespace XPC
|
||||
}
|
||||
case 17: // Orientation
|
||||
{
|
||||
float orient[3];
|
||||
orient[0] = values[i][1];
|
||||
orient[1] = values[i][2];
|
||||
orient[2] = values[i][3];
|
||||
DataManager::SetOrientation(orient);
|
||||
float orientation[3];
|
||||
orientation[0] = values[i][1];
|
||||
orientation[1] = values[i][2];
|
||||
orientation[2] = values[i][3];
|
||||
DataManager::SetOrientation(orientation);
|
||||
break;
|
||||
}
|
||||
case 18: // Alpha, hpath etc.
|
||||
{
|
||||
if (values[i][1] != values[i][1] || values[i][3] != values[i][3])
|
||||
{
|
||||
#if LOG_VERBOSITY > 0
|
||||
Log::WriteLine("[DATA] ERROR: Value must be a number (NaN received)");
|
||||
#endif
|
||||
Log::WriteLine(LOG_ERROR, "DATA", "ERROR: Value must be a number (NaN received)");
|
||||
break;
|
||||
}
|
||||
if (values[i][1] != -998)
|
||||
if (!DataManager::IsDefault(values[i][1]))
|
||||
{
|
||||
savedAlpha = values[i][1];
|
||||
}
|
||||
if (values[i][3] != -998)
|
||||
if (DataManager::IsDefault(values[i][3]))
|
||||
{
|
||||
savedHPath = values[i][3];
|
||||
}
|
||||
@@ -334,17 +351,15 @@ namespace XPC
|
||||
{
|
||||
if (values[i][1] != values[i][1])
|
||||
{
|
||||
#if LOG_VERBOSITY > 0
|
||||
Log::WriteLine("[DATA] ERROR: Value must be a number (NaN received)");
|
||||
#endif
|
||||
Log::WriteLine(LOG_ERROR, "DATA", "ERROR: Value must be a number (NaN received)");
|
||||
break;
|
||||
}
|
||||
float thr[8];
|
||||
float throttle[8];
|
||||
for (int j = 0; j < 8; ++j)
|
||||
{
|
||||
thr[j] = values[i][1];
|
||||
throttle[j] = values[i][1];
|
||||
}
|
||||
DataManager::Set(DREF_ThrottleSet, thr, 8);
|
||||
DataManager::Set(DREF_ThrottleSet, throttle, 8);
|
||||
break;
|
||||
}
|
||||
default: // Non-Special dataRefs
|
||||
@@ -353,10 +368,8 @@ namespace XPC
|
||||
memcpy(line, values[i] + 1, 8 * sizeof(float));
|
||||
for (int j = 0; j < 8; ++j)
|
||||
{
|
||||
#if LOG_VERBOSITY > 1
|
||||
Log::FormatLine("[DATA] Setting Dataref %i.%i to %f", dataRef, j, line[j]);
|
||||
#endif
|
||||
|
||||
Log::FormatLine(LOG_ERROR, "DATA", "Setting Dataref %i.%i to %f", dataRef, j, line[j]);
|
||||
// TODO(jason-watkins): Why is this a special case?
|
||||
if (dataRef == 14 && j == 0)
|
||||
{
|
||||
DataManager::SetGear(line[0], true);
|
||||
@@ -366,7 +379,7 @@ namespace XPC
|
||||
DREF dref = XPData[dataRef][j];
|
||||
if (dref == DREF_None)
|
||||
{
|
||||
// TODO: Send single line instead!
|
||||
// TODO(jason): Send single line instead!
|
||||
HandleXPlaneData(msg);
|
||||
}
|
||||
else
|
||||
@@ -379,46 +392,59 @@ namespace XPC
|
||||
}
|
||||
}
|
||||
|
||||
void MessageHandlers::HandleDref(Message& msg)
|
||||
void MessageHandlers::HandleDref(const Message& msg)
|
||||
{
|
||||
Log::FormatLine(LOG_TRACE, "DREF", "Request to set DREF value received (Conn %i)", connection.id);
|
||||
const unsigned char* buffer = msg.GetBuffer();
|
||||
unsigned char len = buffer[5];
|
||||
std::string dref = std::string((char*)buffer + 6, len);
|
||||
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 dref = std::string((char*)buffer + pos, len);
|
||||
pos += len;
|
||||
|
||||
unsigned char valueCount = buffer[6 + len];
|
||||
float* values = (float*)(buffer + 7 + len);
|
||||
unsigned char valueCount = buffer[pos++];
|
||||
if (pos + 4 * valueCount > size)
|
||||
{
|
||||
break;
|
||||
}
|
||||
float* values = (float*)(buffer + pos);
|
||||
pos += 4 * valueCount;
|
||||
|
||||
#if LOG_VERBOSITY > 1
|
||||
Log::FormatLine("[DREF] Request to set DREF value received (Conn %i): %s", connection.id, dref.c_str());
|
||||
#endif
|
||||
|
||||
DataManager::Set(dref, values, valueCount);
|
||||
DataManager::Set(dref, values, valueCount);
|
||||
Log::FormatLine(LOG_DEBUG, "DREF", "Set %d values for %s", valueCount, dref.c_str());
|
||||
}
|
||||
if (pos != size)
|
||||
{
|
||||
Log::WriteLine(LOG_ERROR, "DREF", "ERROR: Command did not terminate at the expected position.");
|
||||
}
|
||||
}
|
||||
|
||||
void MessageHandlers::HandleGetD(Message& msg)
|
||||
void MessageHandlers::HandleGetD(const Message& msg)
|
||||
{
|
||||
const unsigned char* buffer = msg.GetBuffer();
|
||||
unsigned char drefCount = buffer[5];
|
||||
if (drefCount == 0) // Use last request
|
||||
{
|
||||
#if LOG_VERBOSITY > 0
|
||||
Log::FormatLine("[GETD] DATA Requested: Repeat last request from connection %i (%i data refs)",
|
||||
Log::FormatLine(LOG_TRACE, "GETD",
|
||||
"DATA Requested: Repeat last request from connection %i (%i data refs)",
|
||||
connection.id, connection.getdCount);
|
||||
#endif
|
||||
if (connection.getdCount == 0) // No previous request to use
|
||||
{
|
||||
#if LOG_VERBOSITY > 1
|
||||
Log::FormatLine("[GETD] ERROR: No previous requests from connection %i.", connection.id);
|
||||
#endif
|
||||
Log::FormatLine(LOG_ERROR, "GETD", "ERROR: No previous requests from connection %i.",
|
||||
connection.id);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else // New request
|
||||
{
|
||||
#if LOG_VERBOSITY > 0
|
||||
Log::FormatLine("[GETD] DATA Requested: New Request for connection %i (%i data refs)",
|
||||
Log::FormatLine(LOG_TRACE, "GETD", "DATA Requested: New Request for connection %i (%i data refs)",
|
||||
connection.id, drefCount);
|
||||
#endif
|
||||
std::size_t ptr = 6;
|
||||
for (int i = 0; i < drefCount; ++i)
|
||||
{
|
||||
@@ -445,85 +471,96 @@ namespace XPC
|
||||
sock->SendTo(response, cur, &connection.addr);
|
||||
}
|
||||
|
||||
void MessageHandlers::HandlePosi(Message& msg)
|
||||
void MessageHandlers::HandlePosi(const Message& msg)
|
||||
{
|
||||
// Update log
|
||||
#if LOG_VERBOSITY > 0
|
||||
Log::FormatLine("[POSI] Message Received (Conn %i)", connection.id);
|
||||
#endif
|
||||
Log::FormatLine(LOG_TRACE, "POSI", "Message Received (Conn %i)", connection.id);
|
||||
|
||||
const unsigned char* buffer = msg.GetBuffer();
|
||||
const std::size_t size = msg.GetSize();
|
||||
if (size < 34)
|
||||
{
|
||||
#if LOG_VERBOSITY > 1
|
||||
Log::FormatLine("[POSI] ERROR: Unexpected size: %i (Expected at least 34)", size);
|
||||
#endif
|
||||
Log::FormatLine(LOG_ERROR, "POSI", "ERROR: Unexpected size: %i (Expected at least 34)", size);
|
||||
return;
|
||||
}
|
||||
|
||||
char aircraft = buffer[5];
|
||||
char aircraftNumber = buffer[5];
|
||||
float gear = *((float*)(buffer + 30));
|
||||
float pos[3];
|
||||
float orient[3];
|
||||
memcpy(pos, buffer + 6, 12);
|
||||
memcpy(orient, buffer + 18, 12);
|
||||
|
||||
if (aircraft > 0)
|
||||
if (aircraftNumber > 0)
|
||||
{
|
||||
// Enable AI for the aircraft we are setting
|
||||
// Enable AI for the aircraftNumber we are setting
|
||||
float ai[20];
|
||||
std::size_t result = DataManager::GetFloatArray(DREF_PauseAI, ai, 20);
|
||||
if (result == 20) // Only set values if they were retrieved successfully.
|
||||
{
|
||||
ai[aircraft] = 1;
|
||||
ai[aircraftNumber] = 1;
|
||||
DataManager::Set(DREF_PauseAI, ai, 0, 20);
|
||||
}
|
||||
}
|
||||
|
||||
DataManager::SetPosition(pos, aircraft);
|
||||
DataManager::SetOrientation(orient, aircraft);
|
||||
DataManager::SetPosition(pos, aircraftNumber);
|
||||
DataManager::SetOrientation(orient, aircraftNumber);
|
||||
if (gear != -1)
|
||||
{
|
||||
DataManager::SetGear(gear, true, aircraft);
|
||||
DataManager::SetGear(gear, true, aircraftNumber);
|
||||
}
|
||||
}
|
||||
|
||||
void MessageHandlers::HandleSimu(Message& msg)
|
||||
void MessageHandlers::HandleSimu(const Message& msg)
|
||||
{
|
||||
// Update log
|
||||
#if LOG_VERBOSITY > 0
|
||||
Log::FormatLine("[SIMU] Message Received (Conn %i)", connection.id);
|
||||
#endif
|
||||
Log::FormatLine(LOG_TRACE, "SIMU", "Message Received (Conn %i)", connection.id);
|
||||
|
||||
const unsigned char* buffer = msg.GetBuffer();
|
||||
|
||||
// Set DREF
|
||||
int value[20];
|
||||
for (int i = 0; i < 20; ++i)
|
||||
char v = msg.GetBuffer()[5];
|
||||
if (v < 0 || v > 2)
|
||||
{
|
||||
value[i] = buffer[5];
|
||||
Log::FormatLine(LOG_ERROR, "SIMU", "ERROR: Invalid argument: %i", v);
|
||||
return;
|
||||
}
|
||||
DataManager::Set(DREF_Pause, value, 20);
|
||||
|
||||
#if LOG_VERBOSITY > 2
|
||||
if (buffer[5] == 0)
|
||||
|
||||
int value[20];
|
||||
if (v == 2)
|
||||
{
|
||||
Log::FormatLine("[SIMU] Simulation Resumed (Conn %i)", connection.id);
|
||||
DataManager::GetIntArray(DREF_Pause, value, 20);
|
||||
for (int i = 0; i < 20; ++i)
|
||||
{
|
||||
value[i] = value[i] ? 0 : 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::FormatLine("[SIMU] Simulation Paused (Conn %i)", connection.id);
|
||||
for (int i = 0; i < 20; ++i)
|
||||
{
|
||||
value[i] = v;
|
||||
}
|
||||
}
|
||||
|
||||
// Set DREF
|
||||
DataManager::Set(DREF_Pause, value, 20);
|
||||
|
||||
switch (v)
|
||||
{
|
||||
case 0:
|
||||
Log::WriteLine(LOG_INFO, "SIMU", "Simulation resumed");
|
||||
break;
|
||||
case 1:
|
||||
Log::WriteLine(LOG_INFO, "SIMU", "Simulation paused");
|
||||
break;
|
||||
case 2:
|
||||
Log::FormatLine(LOG_INFO, "SIMU", "Simulation switched to %i", value[0]);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void MessageHandlers::HandleText(Message& msg)
|
||||
void MessageHandlers::HandleText(const Message& msg)
|
||||
{
|
||||
// Update Log
|
||||
#if LOG_VERBOSITY > 0
|
||||
Log::FormatLine("[TEXT] Message Received (Conn %i)", connection.id);
|
||||
#endif
|
||||
Log::FormatLine(LOG_TRACE, "TEXT", "Message Received (Conn %i)", connection.id);
|
||||
|
||||
std::size_t len = msg.GetSize();
|
||||
const unsigned char* buffer = msg.GetBuffer();
|
||||
@@ -531,18 +568,14 @@ namespace XPC
|
||||
char text[256] = { 0 };
|
||||
if (len < 14)
|
||||
{
|
||||
#if LOG_VERBOSITY > 1
|
||||
Log::WriteLine("[TEXT] ERROR: Length less than 14 bytes");
|
||||
#endif
|
||||
Log::WriteLine(LOG_ERROR, "TEXT", "ERROR: Length less than 14 bytes");
|
||||
return;
|
||||
}
|
||||
size_t msgLen = (unsigned char)buffer[13];
|
||||
if (msgLen == 0)
|
||||
{
|
||||
Drawing::ClearMessage();
|
||||
#if LOG_VERBOSITY > 2
|
||||
Log::WriteLine("[TEXT] Text cleared");
|
||||
#endif
|
||||
Log::WriteLine(LOG_INFO, "TEXT", "[TEXT] Text cleared");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -550,18 +583,30 @@ namespace XPC
|
||||
int y = *((int*)(buffer + 9));
|
||||
strncpy(text, (char*)buffer + 14, msgLen);
|
||||
Drawing::SetMessage(x, y, text);
|
||||
#if LOG_VERBOSITY > 2
|
||||
Log::WriteLine("[TEXT] Text set");
|
||||
#endif
|
||||
Log::WriteLine(LOG_INFO, "TEXT", "[TEXT] Text set");
|
||||
}
|
||||
}
|
||||
|
||||
void MessageHandlers::HandleWypt(Message& msg)
|
||||
void MessageHandlers::HandleView(const Message& msg)
|
||||
{
|
||||
// Update Log
|
||||
#if LOG_VERBOSITY > 0
|
||||
Log::FormatLine("[WYPT] Message Received (Conn %i)", connection.id);
|
||||
#endif
|
||||
Log::FormatLine(LOG_TRACE, "VIEW", "Message Received(Conn %i)", connection.id);
|
||||
|
||||
const std::size_t size = msg.GetSize();
|
||||
if (size != 9)
|
||||
{
|
||||
Log::FormatLine(LOG_ERROR, "VIEW", "Error: Unexpected length. Message was %d bytes, expected 9.", size);
|
||||
return;
|
||||
}
|
||||
const unsigned char* buffer = msg.GetBuffer();
|
||||
int type = *((int*)(buffer + 5));
|
||||
XPLMCommandKeyStroke(type);
|
||||
}
|
||||
|
||||
void MessageHandlers::HandleWypt(const Message& msg)
|
||||
{
|
||||
// Update Log
|
||||
Log::FormatLine(LOG_TRACE, "WYPT", "Message Received (Conn %i)", connection.id);
|
||||
|
||||
// Parse data
|
||||
const unsigned char* buffer = msg.GetBuffer();
|
||||
@@ -578,9 +623,7 @@ namespace XPC
|
||||
}
|
||||
|
||||
// Perform operation
|
||||
#if LOG_VERBOSITY > 2
|
||||
Log::FormatLine("[WYPT] Performing operation %i", op);
|
||||
#endif
|
||||
Log::FormatLine(LOG_INFO, "WYPT", "Performing operation %i", op);
|
||||
switch (op)
|
||||
{
|
||||
case 1:
|
||||
@@ -593,18 +636,14 @@ namespace XPC
|
||||
Drawing::ClearWaypoints();
|
||||
break;
|
||||
default:
|
||||
#if LOG_VERBOSITY > 1
|
||||
Log::FormatLine("[WYPT] ERROR: %i is not a valid operation.", op);
|
||||
#endif
|
||||
Log::FormatLine(LOG_ERROR, "WYPT", "ERROR: %i is not a valid operation.", op);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MessageHandlers::HandleXPlaneData(Message& msg)
|
||||
void MessageHandlers::HandleXPlaneData(const Message& msg)
|
||||
{
|
||||
#if LOG_VERBOSITY > 1
|
||||
Log::WriteLine("[MSGH] Sending raw data to X-Plane");
|
||||
#endif
|
||||
Log::WriteLine(LOG_TRACE, "MSGH", "Sending raw data to X - Plane");
|
||||
sockaddr_in loopback;
|
||||
loopback.sin_family = AF_INET;
|
||||
loopback.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
@@ -612,11 +651,8 @@ namespace XPC
|
||||
sock->SendTo(msg.GetBuffer(), msg.GetSize(), (sockaddr*)&loopback);
|
||||
}
|
||||
|
||||
void MessageHandlers::HandleUnknown(Message& msg)
|
||||
void MessageHandlers::HandleUnknown(const Message& msg)
|
||||
{
|
||||
// UPDATE LOG
|
||||
#if LOG_VERBOSITY > 0
|
||||
Log::FormatLine("[EXEC] ERROR: Unknown packet type %s", msg.GetHead().c_str());
|
||||
#endif
|
||||
Log::FormatLine(LOG_ERROR, "MSGH", "ERROR: Unknown packet type %s", msg.GetHead().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
//National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#ifndef XPC_MESSAGEHANDLERS_H
|
||||
#define XPC_MESSAGEHANDLERS_H
|
||||
// Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
// National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#ifndef XPCPLUGIN_MESSAGEHANDLERS_H_
|
||||
#define XPCPLUGIN_MESSAGEHANDLERS_H_
|
||||
#include "Message.h"
|
||||
|
||||
#include <string>
|
||||
@@ -10,15 +10,15 @@
|
||||
namespace XPC
|
||||
{
|
||||
/// A function that handles a message.
|
||||
typedef void(*MessageHandler)(Message&);
|
||||
typedef void(*MessageHandler)(const Message&);
|
||||
|
||||
/// Handles incommming messages and manages connections.
|
||||
/// Handles incoming messages and manages connections.
|
||||
///
|
||||
/// \author Jason Watkins
|
||||
/// \version 1.0
|
||||
/// \version 1.1
|
||||
/// \since 1.0
|
||||
/// \date Intial Version: 2015-04-12
|
||||
/// \date Last Updated: 2015-04-12
|
||||
/// \date Last Updated: 2015-05-11
|
||||
class MessageHandlers
|
||||
{
|
||||
public:
|
||||
@@ -33,21 +33,25 @@ namespace XPC
|
||||
/// \param msg The message to be processed.
|
||||
static void HandleMessage(Message& msg);
|
||||
|
||||
/// Sets the socke that message handlers use to send responses.
|
||||
/// Sets the socket that message handlers use to send responses.
|
||||
static void SetSocket(UDPSocket* socket);
|
||||
|
||||
private:
|
||||
static void HandleConn(Message& msg);
|
||||
static void HandleCtrl(Message& msg);
|
||||
static void HandleData(Message& msg);
|
||||
static void HandleDref(Message& msg);
|
||||
static void HandleGetD(Message& msg);
|
||||
static void HandlePosi(Message& msg);
|
||||
static void HandleSimu(Message& msg);
|
||||
static void HandleText(Message& msg);
|
||||
static void HandleWypt(Message& msg);
|
||||
static void HandleXPlaneData(Message& msg);
|
||||
static void HandleUnknown(Message& msg);
|
||||
// One handler per message type. Message types are descripbed on the
|
||||
// wiki at https://github.com/nasa/XPlaneConnect/wiki/Network-Information
|
||||
static void HandleConn(const Message& msg);
|
||||
static void HandleCtrl(const Message& msg);
|
||||
static void HandleData(const Message& msg);
|
||||
static void HandleDref(const Message& msg);
|
||||
static void HandleGetD(const Message& msg);
|
||||
static void HandlePosi(const Message& msg);
|
||||
static void HandleSimu(const Message& msg);
|
||||
static void HandleText(const Message& msg);
|
||||
static void HandleWypt(const Message& msg);
|
||||
static void HandleView(const Message& msg);
|
||||
|
||||
static void HandleXPlaneData(const Message& msg);
|
||||
static void HandleUnknown(const Message& msg);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@@ -64,5 +68,4 @@ namespace XPC
|
||||
static UDPSocket* sock; // Outgoing network socket
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
//National Aeronautics and Space Administration. All Rights Reserved.
|
||||
// Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
// National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#include "Log.h"
|
||||
#include "UDPSocket.h"
|
||||
|
||||
@@ -8,41 +8,37 @@
|
||||
|
||||
namespace XPC
|
||||
{
|
||||
const static std::string tag = "SOCK";
|
||||
|
||||
UDPSocket::UDPSocket(unsigned short recvPort)
|
||||
{
|
||||
#if LOG_VERBOSITY > 1
|
||||
Log::FormatLine("[SOCK] Opening socket (port:%d)", recvPort);
|
||||
#endif
|
||||
Log::FormatLine(LOG_TRACE, tag, "Opening socket (port:%d)", recvPort);
|
||||
// Setup Port
|
||||
struct sockaddr_in localAddr;
|
||||
localAddr.sin_family = AF_INET;
|
||||
localAddr.sin_addr.s_addr = INADDR_ANY;
|
||||
localAddr.sin_port = htons(recvPort);
|
||||
|
||||
//Create and bind the socket
|
||||
|
||||
// Create and bind the socket
|
||||
#ifdef _WIN32
|
||||
WSADATA wsa;
|
||||
int startResult = WSAStartup(MAKEWORD(2, 2), &wsa);
|
||||
if (startResult != 0)
|
||||
{
|
||||
#if LOG_VERBOSITY > 0
|
||||
Log::FormatLine("[SOCK] ERROR: WSAStartup failed with error code %i.", startResult);
|
||||
#endif
|
||||
Log::FormatLine(LOG_FATAL, tag, "ERROR: WSAStartup failed with error code %i.", startResult);
|
||||
this->sock = ~0;
|
||||
return;
|
||||
}
|
||||
if ((this->sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET)
|
||||
{
|
||||
#if LOG_VERBOSITY > 0
|
||||
int err = WSAGetLastError();
|
||||
Log::FormatLine("[SOCK] ERROR: Failed to open socket. (Error code %i)", err);
|
||||
#endif
|
||||
Log::FormatLine(LOG_FATAL, tag, "ERROR: Failed to open socket. (Error code %i)", err);
|
||||
return;
|
||||
}
|
||||
#elif (__APPLE__ || __linux)
|
||||
if ((this->sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
|
||||
{
|
||||
Log::WriteLine("[SOCK] ERROR: Failed to open socket");
|
||||
Log::WriteLine(LOG_FATAL, tag, "ERROR: Failed to open socket");
|
||||
return;
|
||||
}
|
||||
int optval = 1;
|
||||
@@ -52,39 +48,35 @@ namespace XPC
|
||||
if (bind(this->sock, (struct sockaddr*)&localAddr, sizeof(localAddr)) != 0)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
#if LOG_VERBOSITY > 0
|
||||
int err = WSAGetLastError();
|
||||
Log::FormatLine("[SOCK] ERROR: Failed to bind socket. (Error code %i)", err);
|
||||
#endif
|
||||
Log::FormatLine(LOG_FATAL, tag, "ERROR: Failed to bind socket. (Error code %i)", err);
|
||||
#else
|
||||
Log::WriteLine(LOG_FATAL, tag, "ERROR: Failed to bind socket.");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
//Set Timout
|
||||
// Set Timout
|
||||
int usTimeOut = 500;
|
||||
|
||||
#ifdef _WIN32
|
||||
DWORD msTimeOutWin = 1; // Minimum socket timeout in Windows is 1ms
|
||||
if(setsockopt(this->sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&msTimeOutWin, sizeof(msTimeOutWin)) != 0)
|
||||
{
|
||||
#if LOG_VERBOSITY > 1
|
||||
int err = WSAGetLastError();
|
||||
Log::FormatLine("[SOCK] ERROR: Failed to set timeout. (Error code %i)", err);
|
||||
#endif
|
||||
Log::FormatLine(LOG_ERROR, tag, "ERROR: Failed to set timeout. (Error code %i)", err);
|
||||
}
|
||||
#else
|
||||
struct timeval tv;
|
||||
tv.tv_sec = 0; /* Sec Timeout */
|
||||
tv.tv_usec = usTimeOut; // Microsec Timeout
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = usTimeOut;
|
||||
setsockopt(this->sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval));
|
||||
#endif
|
||||
}
|
||||
|
||||
UDPSocket::~UDPSocket()
|
||||
{
|
||||
#if LOG_VERBOSITY > 1
|
||||
Log::FormatLine("[SOCK] Closing socket (%d)", this->sock);
|
||||
#endif
|
||||
Log::FormatLine(LOG_TRACE, tag, "Closing socket (%d)", this->sock);
|
||||
#ifdef _WIN32
|
||||
closesocket(this->sock);
|
||||
#elif (__APPLE__ || __linux)
|
||||
@@ -92,7 +84,7 @@ namespace XPC
|
||||
#endif
|
||||
}
|
||||
|
||||
int UDPSocket::Read(unsigned char* dst, int maxLen, sockaddr* recvAddr)
|
||||
int UDPSocket::Read(unsigned char* dst, int maxLen, sockaddr* recvAddr) const
|
||||
{
|
||||
socklen_t recvaddrlen = sizeof(*recvAddr);
|
||||
int status = 0;
|
||||
@@ -111,18 +103,16 @@ namespace XPC
|
||||
FD_SET(sock, &stReadFDS);
|
||||
FD_ZERO(&stExceptFDS);
|
||||
FD_SET(sock, &stExceptFDS);
|
||||
tv.tv_sec = 0; /* Sec Timeout */
|
||||
tv.tv_usec = 250; // Microsec Timeout
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 250;
|
||||
|
||||
// Select Command
|
||||
int result = select(-1, &stReadFDS, (FD_SET *)0, &stExceptFDS, &tv);
|
||||
#if LOG_VERBOSITY > 1
|
||||
if (result == SOCKET_ERROR)
|
||||
{
|
||||
int err = WSAGetLastError();
|
||||
Log::FormatLine("[SOCK] ERROR: Select failed. (Error code %i)", err);
|
||||
Log::FormatLine(LOG_ERROR, tag, "ERROR: Select failed. (Error code %i)", err);
|
||||
}
|
||||
#endif
|
||||
if (result <= 0) // No Data or error
|
||||
{
|
||||
return -1;
|
||||
@@ -137,22 +127,18 @@ namespace XPC
|
||||
return status;
|
||||
}
|
||||
|
||||
void UDPSocket::SendTo(const unsigned char* buffer, std::size_t len, sockaddr* remote)
|
||||
void UDPSocket::SendTo(const unsigned char* buffer, std::size_t len, sockaddr* remote) const
|
||||
{
|
||||
if (sendto(sock, (char*)buffer, (int)len, 0, remote, sizeof(*remote)) < 0)
|
||||
{
|
||||
#if LOG_VERBOSITY > 0
|
||||
Log::FormatLine("[SOCK] Send failed. (remote: %s)", GetHost(remote).c_str());
|
||||
#endif
|
||||
Log::FormatLine(LOG_ERROR, tag, "Send failed. (remote: %s)", GetHost(remote).c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
#if LOG_VERBOSITY > 3
|
||||
Log::FormatLine("[SOCK] Datagram sent. (remote: %s)", GetHost(remote).c_str());
|
||||
#endif
|
||||
Log::FormatLine(LOG_INFO, tag, "Send failed. (remote: %s)", GetHost(remote).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string UDPSocket::GetHost(sockaddr* sa)
|
||||
{
|
||||
char ip[INET6_ADDRSTRLEN + 6] = { 0 };
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
//National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#ifndef XPC_SOCKET_H
|
||||
#define XPC_SOCKET_H
|
||||
// Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
// National Aeronautics and Space Administration. All Rights Reserved.
|
||||
#ifndef XPCPLUGIN_SOCKET_H_
|
||||
#define XPCPLUGIN_SOCKET_H_
|
||||
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#pragma comment(lib,"ws2_32.lib") //Winsock Library
|
||||
#pragma comment(lib, "ws2_32.lib") // Winsock Library
|
||||
#elif (__APPLE__ || __linux)
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
@@ -23,10 +23,10 @@ namespace XPC
|
||||
/// data to XPC clients.
|
||||
///
|
||||
/// \author Jason Watkins
|
||||
/// \version 1.0
|
||||
/// \version 1.1
|
||||
/// \since 1.0
|
||||
/// \date Intial Version: 2015-04-10
|
||||
/// \date Last Updated: 2015-04-11
|
||||
/// \date Last Updated: 2015-05-11
|
||||
class UDPSocket
|
||||
{
|
||||
public:
|
||||
@@ -34,7 +34,7 @@ namespace XPC
|
||||
/// specified receive port.
|
||||
///
|
||||
/// \param recvPort The port on which this instance will receive data.
|
||||
UDPSocket(unsigned short recvPort);
|
||||
explicit UDPSocket(unsigned short recvPort);
|
||||
|
||||
/// Closes the underlying socket for this instance.
|
||||
~UDPSocket();
|
||||
@@ -45,17 +45,17 @@ namespace XPC
|
||||
/// \param buffer The array to copy the data into.
|
||||
/// \param size The number of bytes to read.
|
||||
/// \param remoteAddr When at least one byte is read, contains the address
|
||||
/// of the remote host.
|
||||
/// of the remote host.
|
||||
/// \returns The number of bytes read, or a negative number if
|
||||
/// an error occurs.
|
||||
int Read(unsigned char* buffer, int size, sockaddr* remoteAddr);
|
||||
/// an error occurs.
|
||||
int Read(unsigned char* buffer, int size, sockaddr* remoteAddr) const;
|
||||
|
||||
/// Sends data to the specified remote endpoint.
|
||||
///
|
||||
/// \param data The data to be sent.
|
||||
/// \param len The number of bytes to send.
|
||||
/// \param remote The destination socket.
|
||||
void SendTo(const unsigned char* buffer, std::size_t len, sockaddr* remote);
|
||||
void SendTo(const unsigned char* buffer, std::size_t len, sockaddr* remote) const;
|
||||
|
||||
/// Gets a string containing the IP address and port contained in the given sockaddr.
|
||||
///
|
||||
@@ -70,5 +70,4 @@ namespace XPC
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1,58 +1,58 @@
|
||||
//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
//National Aeronautics and Space Administration. All Rights Reserved.
|
||||
// Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
|
||||
// National Aeronautics and Space Administration. All Rights Reserved.
|
||||
//
|
||||
//DISCLAIMERS
|
||||
// No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY KIND,
|
||||
// EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY THAT
|
||||
// THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY
|
||||
// THAT THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED,
|
||||
// WILL CONFORM TO THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN
|
||||
// ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, RESULTING DESIGNS,
|
||||
// HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS RESULTING FROM USE OF THE SUBJECT
|
||||
// SOFTWARE. FURTHER, GOVERNMENT AGENCY DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING
|
||||
// THIRD-PARTY SOFTWARE, IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS."
|
||||
// DISCLAIMERS
|
||||
// No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY KIND,
|
||||
// EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY THAT
|
||||
// THE SUBJECT SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY
|
||||
// THAT THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED,
|
||||
// WILL CONFORM TO THE SUBJECT SOFTWARE. THIS AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN
|
||||
// ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT OF ANY RESULTS, RESULTING DESIGNS,
|
||||
// HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS RESULTING FROM USE OF THE SUBJECT
|
||||
// SOFTWARE. FURTHER, GOVERNMENT AGENCY DISCLAIMS ALL WARRANTIES AND LIABILITIES REGARDING
|
||||
// THIRD-PARTY SOFTWARE, IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT "AS IS."
|
||||
//
|
||||
// Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST THE UNITED STATES
|
||||
// GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY PRIOR RECIPIENT. IF
|
||||
// RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES
|
||||
// OR LOSSES ARISING FROM SUCH USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING
|
||||
// FROM, RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD HARMLESS THE
|
||||
// UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY PRIOR RECIPIENT,
|
||||
// TO THE EXTENT PERMITTED BY LAW. RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE
|
||||
// IMMEDIATE, UNILATERAL TERMINATION OF THIS AGREEMENT.
|
||||
// Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST THE UNITED STATES
|
||||
// GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY PRIOR RECIPIENT. IF
|
||||
// RECIPIENT'S USE OF THE SUBJECT SOFTWARE RESULTS IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES
|
||||
// OR LOSSES ARISING FROM SUCH USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING
|
||||
// FROM, RECIPIENT'S USE OF THE SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD HARMLESS THE
|
||||
// UNITED STATES GOVERNMENT, ITS CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY PRIOR RECIPIENT,
|
||||
// TO THE EXTENT PERMITTED BY LAW. RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE
|
||||
// IMMEDIATE, UNILATERAL TERMINATION OF THIS AGREEMENT.
|
||||
//
|
||||
//X-Plane API
|
||||
//Copyright(c) 2008, Sandy Barbour and Ben Supnik All rights reserved.
|
||||
//Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
//associated documentation files(the "Software"), to deal in the Software without restriction,
|
||||
//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
|
||||
//furnished to do so, subject to the following conditions :
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// * 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
|
||||
// without specific prior written permission from the authors or
|
||||
// Laminar Research, respectively.
|
||||
// X-Plane API
|
||||
// Copyright(c) 2008, Sandy Barbour and Ben Supnik All rights reserved.
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
// associated documentation files(the "Software"), to deal in the Software without restriction,
|
||||
// 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
|
||||
// furnished to do so, subject to the following conditions :
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// * 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
|
||||
// without specific prior written permission from the authors or
|
||||
// Laminar Research, respectively.
|
||||
|
||||
|
||||
// X-Plane Connect Plugin
|
||||
// X-Plane Connect Plugin
|
||||
//
|
||||
// DESCRIPTION
|
||||
// XPCPlugin Facilitates Communication to and from the XPlane
|
||||
// DESCRIPTION
|
||||
// XPCPlugin Facilitates Communication to and from the XPlane
|
||||
//
|
||||
// INSTRUCTIONS
|
||||
// See Readme.md in the root of this repository or the wiki hosted on GitHub at
|
||||
// https://github.com/nasa/XPlaneConnect/wiki for requirements, installation instructions,
|
||||
// and detailed documentation.
|
||||
// INSTRUCTIONS
|
||||
// See Readme.md in the root of this repository or the wiki hosted on GitHub at
|
||||
// https://github.com/nasa/XPlaneConnect/wiki for requirements, installation instructions,
|
||||
// and detailed documentation.
|
||||
//
|
||||
// CONTACT
|
||||
// For questions email Christopher Teubert (christopher.a.teubert@nasa.gov)
|
||||
// CONTACT
|
||||
// For questions email Christopher Teubert (christopher.a.teubert@nasa.gov)
|
||||
//
|
||||
// CONTRIBUTORS
|
||||
// CT: Christopher Teubert (christopher.a.teubert@nasa.gov)
|
||||
// JW: Jason Watkins (jason.w.watkins@nasa.gov)
|
||||
// CONTRIBUTORS
|
||||
// CT: Christopher Teubert (christopher.a.teubert@nasa.gov)
|
||||
// JW: Jason Watkins (jason.w.watkins@nasa.gov)
|
||||
|
||||
// XPC Includes
|
||||
#include "DataManager.h"
|
||||
@@ -75,7 +75,8 @@
|
||||
|
||||
XPC::UDPSocket* sock = NULL;
|
||||
|
||||
double start,lap;
|
||||
double start;
|
||||
double lap;
|
||||
static double timeConvert = 0.0;
|
||||
int benchmarkingSwitch = 0; // 1 = time for operations, 2 = time for op + cycle;
|
||||
int cyclesToClear = -1; // Clear message bus every n cycles. -1 == dont clear
|
||||
@@ -93,36 +94,34 @@ PLUGIN_API int XPluginStart(char* outName, char* outSig, char* outDesc)
|
||||
strcpy(outName, "X-Plane Connect [Version 1.0.1]");
|
||||
strcpy(outSig, "NASA.XPlaneConnect");
|
||||
strcpy(outDesc, "X Plane Communications Toolbox\nCopyright (c) 2013-2015 United States Government as represented by the Administrator of the National Aeronautics and Space Administration. All Rights Reserved.");
|
||||
|
||||
|
||||
#if (__APPLE__)
|
||||
if ( abs(timeConvert) <= 1e-9 ) // is about 0
|
||||
{
|
||||
mach_timebase_info_data_t timeBase;
|
||||
(void)mach_timebase_info( &timeBase );
|
||||
(void)mach_timebase_info(&timeBase);
|
||||
timeConvert = (double)timeBase.numer /
|
||||
(double)timeBase.denom /
|
||||
1000000000.0;
|
||||
}
|
||||
#endif
|
||||
XPC::Log::Initialize("1.0.1");
|
||||
XPC::Log::WriteLine("[EXEC] Plugin Start");
|
||||
XPC::Log::Initialize("1.1.0");
|
||||
XPC::Log::WriteLine(LOG_INFO, "EXEC", "Plugin Start");
|
||||
XPC::DataManager::Initialize();
|
||||
|
||||
float interval = -1; // Call every frame
|
||||
void* refcon = NULL; // Don't pass anything to the callback directly
|
||||
XPLMRegisterFlightLoopCallback(XPCFlightLoopCallback, interval, refcon);
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
PLUGIN_API void XPluginStop(void)
|
||||
{
|
||||
XPLMUnregisterFlightLoopCallback(XPCFlightLoopCallback, NULL);
|
||||
XPC::Log::WriteLine("[EXEC] Plugin Shutdown");
|
||||
XPC::Log::WriteLine(LOG_INFO, "EXEC", "Plugin Shutdown");
|
||||
XPC::Log::Close();
|
||||
}
|
||||
|
||||
PLUGIN_API void XPluginDisable(void)
|
||||
{
|
||||
XPLMUnregisterFlightLoopCallback(XPCFlightLoopCallback, NULL);
|
||||
|
||||
// Close sockets
|
||||
delete sock;
|
||||
sock = NULL;
|
||||
@@ -133,7 +132,7 @@ PLUGIN_API void XPluginDisable(void)
|
||||
// Stop rendering waypoints to screen.
|
||||
XPC::Drawing::ClearWaypoints();
|
||||
|
||||
XPC::Log::WriteLine("[EXEC] Plugin Disabled, sockets closed");
|
||||
XPC::Log::WriteLine(LOG_INFO, "EXEC", "Plugin Disabled, sockets closed");
|
||||
}
|
||||
|
||||
PLUGIN_API int XPluginEnable(void)
|
||||
@@ -142,15 +141,17 @@ PLUGIN_API int XPluginEnable(void)
|
||||
sock = new XPC::UDPSocket(RECVPORT);
|
||||
XPC::MessageHandlers::SetSocket(sock);
|
||||
|
||||
XPC::Log::WriteLine("[EXEC] Plugin Enabled, sockets opened");
|
||||
XPC::Log::WriteLine(LOG_INFO, "EXEC", "Plugin Enabled, sockets opened");
|
||||
if (benchmarkingSwitch > 0)
|
||||
{
|
||||
XPC::Log::FormatLine("[EXEC] Benchmarking Enabled (Verbosity: %i)", benchmarkingSwitch);
|
||||
XPC::Log::FormatLine(LOG_INFO, "EXEC", "Benchmarking Enabled (Verbosity: %i)", benchmarkingSwitch);
|
||||
}
|
||||
#if LOG_VERBOSITY > 0
|
||||
XPC::Log::FormatLine("[EXEC] Debug Logging Enabled (Verbosity: %i)", LOG_VERBOSITY);
|
||||
#endif
|
||||
XPC::Log::FormatLine(LOG_INFO, "EXEC", "Debug Logging Enabled (Verbosity: %i)", LOG_LEVEL);
|
||||
|
||||
float interval = -1; // Call every frame
|
||||
void* refcon = NULL; // Don't pass anything to the callback directly
|
||||
XPLMRegisterFlightLoopCallback(XPCFlightLoopCallback, interval, refcon);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -172,7 +173,7 @@ float XPCFlightLoopCallback(float inElapsedSinceLastCall,
|
||||
counter++;
|
||||
if (benchmarkingSwitch > 1)
|
||||
{
|
||||
XPC::Log::FormatLine("Cycle time %.6f", inElapsedSinceLastCall);
|
||||
XPC::Log::FormatLine(LOG_DEBUG, "EXEC", "Cycle time %.6f", inElapsedSinceLastCall);
|
||||
}
|
||||
|
||||
for (int i = 0; i < OPS_PER_CYCLE; i++)
|
||||
@@ -195,15 +196,15 @@ float XPCFlightLoopCallback(float inElapsedSinceLastCall,
|
||||
{
|
||||
#if (__APPLE__)
|
||||
lap = (double)mach_absolute_time( ) * timeConvert;
|
||||
diff_t = lap-start;
|
||||
XPC::Log::FormatLine("[BENCH] Runtime %.6f",diff_t);
|
||||
diff_t = lap - start;
|
||||
XPC::Log::FormatLine(LOG_INFO, "EXEC", "Runtime %.6f", diff_t);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (cyclesToClear != -1 && counter%cyclesToClear == 0)
|
||||
{
|
||||
XPC::Log::WriteLine("[EXEC] Cleared UDP Buffer");
|
||||
XPC::Log::WriteLine(LOG_DEBUG, "EXEC", "Cleared UDP Buffer");
|
||||
delete sock;
|
||||
sock = new XPC::UDPSocket(RECVPORT);
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -10,7 +10,6 @@
|
||||
BE37D960187C8B0F0033B082 /* XPCPlugin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE37D95E187C8B0F0033B082 /* XPCPlugin.cpp */; };
|
||||
BE8361EF18C5591C00E9C923 /* mac.xpl in CopyFiles */ = {isa = PBXBuildFile; fileRef = D607B19909A556E400699BC3 /* mac.xpl */; };
|
||||
BEABAD371AE041A3007BA7DA /* DataManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEABAD2B1AE041A3007BA7DA /* DataManager.cpp */; };
|
||||
BEABAD381AE041A3007BA7DA /* DataMaps.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEABAD2D1AE041A3007BA7DA /* DataMaps.cpp */; };
|
||||
BEABAD391AE041A3007BA7DA /* Drawing.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEABAD2F1AE041A3007BA7DA /* Drawing.cpp */; };
|
||||
BEABAD3A1AE041A3007BA7DA /* Log.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEABAD311AE041A3007BA7DA /* Log.cpp */; };
|
||||
BEABAD3B1AE041A3007BA7DA /* Message.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEABAD331AE041A3007BA7DA /* Message.cpp */; };
|
||||
@@ -40,8 +39,6 @@
|
||||
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>"; };
|
||||
BEABAD2C1AE041A3007BA7DA /* DataManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DataManager.h; sourceTree = "<group>"; };
|
||||
BEABAD2D1AE041A3007BA7DA /* DataMaps.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DataMaps.cpp; sourceTree = "<group>"; };
|
||||
BEABAD2E1AE041A3007BA7DA /* DataMaps.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DataMaps.h; sourceTree = "<group>"; };
|
||||
BEABAD2F1AE041A3007BA7DA /* Drawing.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Drawing.cpp; sourceTree = "<group>"; };
|
||||
BEABAD301AE041A3007BA7DA /* Drawing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Drawing.h; sourceTree = "<group>"; };
|
||||
BEABAD311AE041A3007BA7DA /* Log.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Log.cpp; sourceTree = "<group>"; };
|
||||
@@ -82,7 +79,6 @@
|
||||
BE37D95E187C8B0F0033B082 /* XPCPlugin.cpp */,
|
||||
BEDC620218EDF1A7005DB364 /* xplaneConnect.c */,
|
||||
BEABAD2B1AE041A3007BA7DA /* DataManager.cpp */,
|
||||
BEABAD2D1AE041A3007BA7DA /* DataMaps.cpp */,
|
||||
BEABAD2F1AE041A3007BA7DA /* Drawing.cpp */,
|
||||
BEABAD311AE041A3007BA7DA /* Log.cpp */,
|
||||
BEABAD331AE041A3007BA7DA /* Message.cpp */,
|
||||
@@ -97,7 +93,6 @@
|
||||
children = (
|
||||
BEDC620318EDF1A7005DB364 /* xplaneConnect.h */,
|
||||
BEABAD2C1AE041A3007BA7DA /* DataManager.h */,
|
||||
BEABAD2E1AE041A3007BA7DA /* DataMaps.h */,
|
||||
BEABAD301AE041A3007BA7DA /* Drawing.h */,
|
||||
BEABAD321AE041A3007BA7DA /* Log.h */,
|
||||
BEABAD341AE041A3007BA7DA /* Message.h */,
|
||||
@@ -192,7 +187,6 @@
|
||||
BEABAD3A1AE041A3007BA7DA /* Log.cpp in Sources */,
|
||||
BEABAD3B1AE041A3007BA7DA /* Message.cpp in Sources */,
|
||||
BEABAD3C1AE041A3007BA7DA /* MessageHandlers.cpp in Sources */,
|
||||
BEABAD381AE041A3007BA7DA /* DataMaps.cpp in Sources */,
|
||||
BEDC620418EDF1A7005DB364 /* xplaneConnect.c in Sources */,
|
||||
BEABAD371AE041A3007BA7DA /* DataManager.cpp in Sources */,
|
||||
BEABAD391AE041A3007BA7DA /* Drawing.cpp in Sources */,
|
||||
|
||||
@@ -201,7 +201,6 @@
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\DataManager.h" />
|
||||
<ClInclude Include="..\DataMaps.h" />
|
||||
<ClInclude Include="..\Drawing.h" />
|
||||
<ClInclude Include="..\Log.h" />
|
||||
<ClInclude Include="..\Message.h" />
|
||||
@@ -210,7 +209,6 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\DataManager.cpp" />
|
||||
<ClCompile Include="..\DataMaps.cpp" />
|
||||
<ClCompile Include="..\Drawing.cpp" />
|
||||
<ClCompile Include="..\Log.cpp" />
|
||||
<ClCompile Include="..\Message.cpp" />
|
||||
|
||||
@@ -30,9 +30,6 @@
|
||||
<ClInclude Include="..\DataManager.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\DataMaps.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\MessageHandlers.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
@@ -59,9 +56,6 @@
|
||||
<ClCompile Include="..\MessageHandlers.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\DataMaps.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Library Include="..\SDK\Libraries\Win\XPLM.lib">
|
||||
|
||||
Reference in New Issue
Block a user