Merge branch 'more-getters' into develop
This commit is contained in:
@@ -521,6 +521,38 @@ int getDREFs(XPCSocket sock, const char* drefs[], float* values[], unsigned char
|
||||
/*****************************************************************************/
|
||||
/**** POSI functions ****/
|
||||
/*****************************************************************************/
|
||||
int getPOSI(XPCSocket sock, float values[7], char ac)
|
||||
{
|
||||
// Setup send command
|
||||
unsigned char buffer[6] = "GETP";
|
||||
buffer[5] = ac;
|
||||
|
||||
// Send command
|
||||
if (sendUDP(sock, buffer, 6) < 0)
|
||||
{
|
||||
printError("getPOSI", "Failed to send command.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Get response
|
||||
unsigned char readBuffer[34];
|
||||
int readResult = readUDP(sock, readBuffer, 34);
|
||||
if (readResult < 0)
|
||||
{
|
||||
printError("getPOSI", "Failed to read response.");
|
||||
return -2;
|
||||
}
|
||||
if (readResult != 34)
|
||||
{
|
||||
printError("getPOSI", "Unexpected response length.");
|
||||
return -3;
|
||||
}
|
||||
|
||||
// Copy response into values
|
||||
memcpy(values, readBuffer + 6, 7 * sizeof(float));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sendPOSI(XPCSocket sock, float values[], int size, char ac)
|
||||
{
|
||||
// Validate input
|
||||
@@ -565,6 +597,41 @@ int sendPOSI(XPCSocket sock, float values[], int size, char ac)
|
||||
/*****************************************************************************/
|
||||
/**** CTRL functions ****/
|
||||
/*****************************************************************************/
|
||||
int getCTRL(XPCSocket sock, float values[7], char ac)
|
||||
{
|
||||
// Setup send command
|
||||
unsigned char buffer[6] = "GETC";
|
||||
buffer[5] = ac;
|
||||
|
||||
// Send command
|
||||
if (sendUDP(sock, buffer, 6) < 0)
|
||||
{
|
||||
printError("getCTRL", "Failed to send command.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Get response
|
||||
unsigned char readBuffer[31];
|
||||
int readResult = readUDP(sock, readBuffer, 31);
|
||||
if (readResult < 0)
|
||||
{
|
||||
printError("getCTRL", "Failed to read response.");
|
||||
return -2;
|
||||
}
|
||||
if (readResult != 31)
|
||||
{
|
||||
printError("getCTRL", "Unexpected response length.");
|
||||
return -3;
|
||||
}
|
||||
|
||||
// Copy response into values
|
||||
memcpy(values, readBuffer + 5, 4 * sizeof(float));
|
||||
values[4] = readBuffer[21];
|
||||
values[5] = *((float*)(readBuffer + 22));
|
||||
values[6] = *((float*)(readBuffer + 27));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sendCTRL(XPCSocket sock, float values[], int size, char ac)
|
||||
{
|
||||
// Validate input
|
||||
|
||||
@@ -196,6 +196,14 @@ int getDREFs(XPCSocket sock, const char* drefs[], float* values[], unsigned char
|
||||
|
||||
// Position
|
||||
|
||||
/// Gets the position and orientation of the specified aircraft.
|
||||
///
|
||||
/// \param sock The socket used to send the command and receive the response.
|
||||
/// \param values An array to store the position information returned by the
|
||||
/// plugin. The format of values is [Lat, Lon, Alt, Pitch, Roll, Yaw, Gear]
|
||||
/// \returns 0 if successful, otherwise a negative value.
|
||||
int getPOSI(XPCSocket sock, float values[7], char ac);
|
||||
|
||||
/// Sets the position and orientation of the specified aircraft.
|
||||
///
|
||||
/// \param sock The socket to use to send the command.
|
||||
@@ -209,6 +217,16 @@ int sendPOSI(XPCSocket sock, float values[], int size, char ac);
|
||||
|
||||
// Controls
|
||||
|
||||
/// Gets the control surface information for the specified aircraft.
|
||||
///
|
||||
/// \param sock The socket used to send the command and receive the response.
|
||||
/// \param values An array to store the position information returned by the
|
||||
/// plugin. The format of values is [Elevator, Aileron, Rudder,
|
||||
/// Throttle, Gear, Flaps, Speed Brakes]
|
||||
/// \param ac The aircraft to set the control surfaces of. 0 is the main/player aircraft.
|
||||
/// \returns 0 if successful, otherwise a negative value.
|
||||
int getCTRL(XPCSocket sock, float values[7], char ac);
|
||||
|
||||
/// Sets the control surfaces of the specified aircraft.
|
||||
///
|
||||
/// \param sock The socket to use to send the command.
|
||||
|
||||
@@ -398,6 +398,47 @@ public class XPlaneConnect implements AutoCloseable
|
||||
sendUDP(os.toByteArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the control surface information for the specified airplane.
|
||||
*
|
||||
* @param ac The aircraft to get control surface information for.
|
||||
* @return An array containing control surface data in the same format as {@code sendCTRL}.
|
||||
* @throws IOException If the command cannot be sent or a response cannot be read.
|
||||
*/
|
||||
public float[] getCTRL(int ac) throws IOException
|
||||
{
|
||||
// Send request
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
os.write("GETC".getBytes(StandardCharsets.UTF_8));
|
||||
os.write(0xFF); //Placeholder for message length
|
||||
os.write(ac);
|
||||
sendUDP(os.toByteArray());
|
||||
|
||||
// Read response
|
||||
byte[] data = readUDP();
|
||||
if(data.length == 0)
|
||||
{
|
||||
throw new IOException("No response received.");
|
||||
}
|
||||
if(data.length < 31)
|
||||
{
|
||||
throw new IOException("Response too short");
|
||||
}
|
||||
|
||||
// Parse response
|
||||
float[] result = new float[7];
|
||||
ByteBuffer bb = ByteBuffer.wrap(data);
|
||||
bb.order(ByteOrder.LITTLE_ENDIAN);
|
||||
result[0] = bb.getFloat(5);
|
||||
result[1] = bb.getFloat(9);
|
||||
result[2] = bb.getFloat(13);
|
||||
result[3] = bb.getFloat(17);
|
||||
result[4] = bb.get(21);
|
||||
result[5] = bb.getFloat(22);
|
||||
result[6] = bb.getFloat(27);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends command to X-Plane setting control surfaces on the player ac.
|
||||
*
|
||||
@@ -409,6 +450,7 @@ public class XPlaneConnect implements AutoCloseable
|
||||
* <li>Throttle [-1, 1]</li>
|
||||
* <li>Gear (0=up, 1=down)</li>
|
||||
* <li>Flaps [0, 1]</li>
|
||||
* <li>Speedbrakes [-0.5, 1.5]</li>
|
||||
* </ol>
|
||||
* <p>
|
||||
* If @{code ctrl} is less than 6 elements long, The missing elements will not be changed. To
|
||||
@@ -433,6 +475,7 @@ public class XPlaneConnect implements AutoCloseable
|
||||
* <li>Throttle [-1, 1]</li>
|
||||
* <li>Gear (0=up, 1=down)</li>
|
||||
* <li>Flaps [0, 1]</li>
|
||||
* <li>Speedbrakes [-0.5, 1.5]</li>
|
||||
* </ol>
|
||||
* <p>
|
||||
* If @{code ctrl} is less than 6 elements long, The missing elements will not be changed. To
|
||||
@@ -492,6 +535,44 @@ public class XPlaneConnect implements AutoCloseable
|
||||
sendUDP(os.toByteArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets position information for the specified airplane.
|
||||
*
|
||||
* @param ac The aircraft to get position information for.
|
||||
* @return An array containing control surface data in the same format as {@code sendPOSI}.
|
||||
* @throws IOException If the command cannot be sent or a response cannot be read.
|
||||
*/
|
||||
public float[] getPOSI(int ac) throws IOException
|
||||
{
|
||||
// Send request
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
os.write("GETP".getBytes(StandardCharsets.UTF_8));
|
||||
os.write(0xFF); //Placeholder for message length
|
||||
os.write(ac);
|
||||
sendUDP(os.toByteArray());
|
||||
|
||||
// Read response
|
||||
byte[] data = readUDP();
|
||||
if(data.length == 0)
|
||||
{
|
||||
throw new IOException("No response received.");
|
||||
}
|
||||
if(data.length < 34)
|
||||
{
|
||||
throw new IOException("Response too short");
|
||||
}
|
||||
|
||||
// Parse response
|
||||
float[] result = new float[7];
|
||||
ByteBuffer bb = ByteBuffer.wrap(data);
|
||||
bb.order(ByteOrder.LITTLE_ENDIAN);
|
||||
for(int i = 0; i < 7; ++i)
|
||||
{
|
||||
result[i] = bb.getFloat(6 + 4 * i);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the position of the player ac.
|
||||
*
|
||||
|
||||
Binary file not shown.
29
MATLAB/+XPlaneConnect/getCTRL.m
Normal file
29
MATLAB/+XPlaneConnect/getCTRL.m
Normal file
@@ -0,0 +1,29 @@
|
||||
function ctrl = getCTRL(ac, socket)
|
||||
% getCTRL Gets control surface information for the specified aircraft
|
||||
%
|
||||
% Inputs
|
||||
% ac: The aircraft number to get control surface data for.
|
||||
% Outputs
|
||||
% posi: An array of values matching the the format used by sendCTRL
|
||||
|
||||
|
||||
import XPlaneConnect.*
|
||||
|
||||
%% Get client
|
||||
global clients;
|
||||
if ~exist('socket', 'var')
|
||||
assert(isequal(length(clients) < 2, 1), '[getCTRL] ERROR: Multiple clients open. You must specify which client to use.');
|
||||
if isempty(clients)
|
||||
socket = openUDP();
|
||||
else
|
||||
socket = clients(1);
|
||||
end
|
||||
end
|
||||
|
||||
%% Validate input
|
||||
ac = int32(ac);
|
||||
|
||||
%% Send command
|
||||
ctrl = socket.getCTRL(ac);
|
||||
|
||||
end
|
||||
29
MATLAB/+XPlaneConnect/getPOSI.m
Normal file
29
MATLAB/+XPlaneConnect/getPOSI.m
Normal file
@@ -0,0 +1,29 @@
|
||||
function posi = getPOSI(ac, socket)
|
||||
% getPOSI Gets position information for the specified aircraft
|
||||
%
|
||||
% Inputs
|
||||
% ac: The aircraft number to get position data for.
|
||||
% Outputs
|
||||
% posi: An array of values matching the the format used by sendPOSI
|
||||
|
||||
|
||||
import XPlaneConnect.*
|
||||
|
||||
%% Get client
|
||||
global clients;
|
||||
if ~exist('socket', 'var')
|
||||
assert(isequal(length(clients) < 2, 1), '[getPOSI] ERROR: Multiple clients open. You must specify which client to use.');
|
||||
if isempty(clients)
|
||||
socket = openUDP();
|
||||
else
|
||||
socket = clients(1);
|
||||
end
|
||||
end
|
||||
|
||||
%% Validate input
|
||||
ac = int32(ac);
|
||||
|
||||
%% Send command
|
||||
posi = socket.getPOSI(ac);
|
||||
|
||||
end
|
||||
@@ -143,7 +143,29 @@ class XPlaneConnect(object):
|
||||
buffer += struct.pack("<I8f", *row)
|
||||
self.sendUDP(buffer)
|
||||
|
||||
# Position
|
||||
# Position
|
||||
def getPOSI(self, ac = 0):
|
||||
'''Gets position information for the specified aircraft.
|
||||
|
||||
Args:
|
||||
ac: The aircraft to set the control surfaces of. 0 is the main/player aircraft.
|
||||
'''
|
||||
# Send request
|
||||
buffer = struct.pack("<4sxB", "GETP", ac)
|
||||
self.sendUDP(buffer)
|
||||
|
||||
# Read response
|
||||
resultBuf = self.readUDP()
|
||||
if len(resultBuf) != 34:
|
||||
raise ValueError("Unexpected response length.")
|
||||
|
||||
result = struct.unpack("<4sxBfffffff", resultBuf)
|
||||
if result[0] != "POSI":
|
||||
raise ValueError("Unexpected header: " + result[0])
|
||||
|
||||
# Drop the header & ac from the return value
|
||||
return result[2:]
|
||||
|
||||
def sendPOSI(self, values, ac = 0):
|
||||
'''Sets position information on the specified aircraft.
|
||||
|
||||
@@ -155,8 +177,8 @@ class XPlaneConnect(object):
|
||||
* Latitude (deg)
|
||||
* Longitude (deg)
|
||||
* Altitude (m above MSL)
|
||||
* Roll (deg)
|
||||
* Pitch (deg)
|
||||
* Roll (deg)
|
||||
* True Heading (deg)
|
||||
* Gear (0=up, 1=down)
|
||||
ac: The aircraft to set the control surfaces of. 0 is the main/player aircraft.
|
||||
@@ -179,6 +201,29 @@ class XPlaneConnect(object):
|
||||
self.sendUDP(buffer)
|
||||
|
||||
# Controls
|
||||
def getCTRL(self, ac = 0):
|
||||
'''Gets the control surface information for the specified aircraft.
|
||||
|
||||
Args:
|
||||
ac: The aircraft to set the control surfaces of. 0 is the main/player aircraft.
|
||||
'''
|
||||
# Send request
|
||||
buffer = struct.pack("<4sxB", "GETC", ac)
|
||||
self.sendUDP(buffer)
|
||||
|
||||
# Read response
|
||||
resultBuf = self.readUDP()
|
||||
if len(resultBuf) != 31:
|
||||
raise ValueError("Unexpected response length.")
|
||||
|
||||
result = struct.unpack("<4sxffffbfBf", resultBuf)
|
||||
if result[0] != "CTRL":
|
||||
raise ValueError("Unexpected header: " + result[0])
|
||||
|
||||
# Drop the header from the return value
|
||||
result =result[1:7] + result[8:]
|
||||
return result
|
||||
|
||||
def sendCTRL(self, values, ac = 0):
|
||||
'''Sets control surface information on the specified aircraft.
|
||||
|
||||
|
||||
@@ -38,6 +38,33 @@ int doCTRLTest(char* drefs[7], float values[], int size, int ac, float expected[
|
||||
return compareArray(expected, actual, 7);
|
||||
}
|
||||
|
||||
int doGETCTest(float values[7], int ac, float expected[7])
|
||||
{
|
||||
// Execute Test
|
||||
float actual[7];
|
||||
XPCSocket sock = openUDP(IP);
|
||||
int result = sendCTRL(sock, values, 7, ac);
|
||||
if (result >= 0)
|
||||
{
|
||||
result = getCTRL(sock, actual, ac);
|
||||
}
|
||||
closeUDP(sock);
|
||||
if (result < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Test values
|
||||
for (int i = 0; i < 7; ++i)
|
||||
{
|
||||
if (fabs(expected[i] - actual[i]) > 1e-4)
|
||||
{
|
||||
return -10 - i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int basicCTRLTest(char** drefs, int ac)
|
||||
{
|
||||
// Set control surfaces to known state.
|
||||
@@ -146,4 +173,16 @@ int testCTRL_Speedbrakes()
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int testGETC()
|
||||
{
|
||||
float CTRL[7] = { 0.0F, 0.0F, 0.0F, 0.8F, 1.0F, 0.5F, -1.5F };
|
||||
return doGETCTest(CTRL, 0, CTRL);
|
||||
}
|
||||
|
||||
int testGETC_NonPlayer()
|
||||
{
|
||||
float CTRL[7] = { 0.0F, 0.0F, 0.0F, 0.8F, 1.0F, 0.5F, -1.5F };
|
||||
return doGETCTest(CTRL, 2, CTRL);
|
||||
}
|
||||
#endif
|
||||
@@ -40,6 +40,33 @@ int doPOSITest(char* drefs[7], float values[], int size, int ac, float expected[
|
||||
return compareArray(expected, actual, 7);
|
||||
}
|
||||
|
||||
int doGETPTest(float values[7], int ac, float expected[7])
|
||||
{
|
||||
// Execute Test
|
||||
float actual[7];
|
||||
XPCSocket sock = openUDP(IP);
|
||||
int result = sendPOSI(sock, values, 7, ac);
|
||||
if (result >= 0)
|
||||
{
|
||||
result = getPOSI(sock, actual, ac);
|
||||
}
|
||||
closeUDP(sock);
|
||||
if (result < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Test values
|
||||
for (int i = 0; i < 7; ++i)
|
||||
{
|
||||
if (fabs(expected[i] - actual[i]) > 1e-4)
|
||||
{
|
||||
return -10 - i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int basicPOSITest(char** drefs, int ac)
|
||||
{
|
||||
// Set psoition and initial orientation
|
||||
@@ -116,6 +143,16 @@ int testPOSI_NonPlayer()
|
||||
return basicPOSITest(drefs, 1);
|
||||
}
|
||||
|
||||
int testGetPOSI_Player()
|
||||
{
|
||||
float POSI[7] = { 37.524F, -122.06899F, 2500, 0, 0, 0, 1 };
|
||||
doGETPTest(POSI, 0, POSI);
|
||||
}
|
||||
|
||||
int testGetPOSI_NonPlayer()
|
||||
{
|
||||
float POSI[7] = { 37.624F, -122.06899F, 1500, 0, 0, 0, 1 };
|
||||
doGETPTest(POSI, 3, POSI);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -40,9 +40,13 @@ int main(int argc, const char * argv[])
|
||||
runTest(testCTRL_Player, "CTRL (player)");
|
||||
runTest(testCTRL_NonPlayer, "CTRL (non-player)");
|
||||
runTest(testCTRL_Speedbrakes, "CTRL (speedbrakes)");
|
||||
runTest(testGETC, "GETC (player)");
|
||||
runTest(testGETC_NonPlayer, "GETC (Non-player)");
|
||||
// POSI
|
||||
runTest(testPOSI_Player, "POSI (player)");
|
||||
runTest(testPOSI_NonPlayer, "POSI (non-player)");
|
||||
runTest(testGetPOSI_Player, "GETP (player)");
|
||||
runTest(testGetPOSI_NonPlayer, "GETP (non-player)");
|
||||
// Data
|
||||
runTest(testDATA, "DATA");
|
||||
// Text
|
||||
|
||||
@@ -698,4 +698,31 @@ public class XPlaneConnectTest
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetPOSI() throws IOException
|
||||
{
|
||||
float[] values = { 37.524F, -122.06899F, 2500.0F, 45.0F, -45.0F, 15.0F, 1.0F };
|
||||
try(XPlaneConnect xpc = new XPlaneConnect())
|
||||
{
|
||||
xpc.pauseSim(true);
|
||||
xpc.sendPOSI(values);
|
||||
float[] actual = xpc.getPOSI(0);
|
||||
|
||||
assertArrayEquals(values, actual, 1e-4F);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetCTRL() throws IOException
|
||||
{
|
||||
float[] values = { 0.0F, 0.0F, 0.0F, 0.8F, 1.0F, 0.5F, -1.5F };
|
||||
try(XPlaneConnect xpc = new XPlaneConnect())
|
||||
{
|
||||
xpc.sendCTRL(values);
|
||||
float[] actual = xpc.getCTRL(0);
|
||||
|
||||
assertArrayEquals(values, actual, 1e-4F);
|
||||
}
|
||||
}
|
||||
}
|
||||
15
TestScripts/MATLAB Tests/getCTRLTest.m
Normal file
15
TestScripts/MATLAB Tests/getCTRLTest.m
Normal file
@@ -0,0 +1,15 @@
|
||||
function getCTRLTest()
|
||||
%GETCTRLTEST Summary of this function goes here
|
||||
% Detailed explanation goes here
|
||||
addpath('../../MATLAB')
|
||||
import XPlaneConnect.*
|
||||
|
||||
values = [10.0, 5.0, -5.0, 0.8, 1.0, 0.5, -1.5];
|
||||
sendCTRL(values, 0);
|
||||
actual = getCTRL(0);
|
||||
|
||||
assert(isequal(length(actual), length(values)));
|
||||
for i = 1:length(actual)
|
||||
assert(abs(actual(i) - values(i)) <1e-4)
|
||||
end
|
||||
end
|
||||
17
TestScripts/MATLAB Tests/getPOSITest.m
Normal file
17
TestScripts/MATLAB Tests/getPOSITest.m
Normal file
@@ -0,0 +1,17 @@
|
||||
function getPOSITest()
|
||||
%GETCTRLTEST Summary of this function goes here
|
||||
% Detailed explanation goes here
|
||||
addpath('../../MATLAB')
|
||||
import XPlaneConnect.*
|
||||
|
||||
values = [ 37.524, -122.06899, 2500, 45, -45, 15, 1 ];
|
||||
pauseSim(1);
|
||||
sendPOSI(values, 0);
|
||||
actual = getPOSI(0);
|
||||
pauseSim(0);
|
||||
|
||||
assert(isequal(length(actual), length(values)));
|
||||
for i = 1:length(actual)
|
||||
assert(abs(actual(i) - values(i)) <1e-4)
|
||||
end
|
||||
end
|
||||
@@ -1,4 +1,4 @@
|
||||
function CTRLTest( )
|
||||
function sendCTRLTest( )
|
||||
%CTRLTest Summary of this function goes here
|
||||
% Detailed explanation goes here
|
||||
%% Test player aircraft
|
||||
@@ -1,4 +1,4 @@
|
||||
function POSITest( )
|
||||
function sendPOSITest( )
|
||||
%POSITest Summary of this function goes here
|
||||
% Detailed explanation goes here
|
||||
addpath('../../MATLAB')
|
||||
@@ -18,8 +18,10 @@ theTests = {{@openCloseTest, 'Open/Close Test', 0},...
|
||||
{@getDREFsTest,'Request DREF Test', 0},...
|
||||
{@sendDREFTest,'Send DREF Test', 0},...
|
||||
{@DATATest,'DATA Test', 0},...
|
||||
{@CTRLTest,'CTRL Test', 0},...
|
||||
{@POSITest,'POSI Test', 0},...
|
||||
{@sendCTRLTest,'sendCTRL Test', 0},...
|
||||
{@getCTRLTest,'getCTRL Test', 0},...
|
||||
{@sendPOSITest,'sendPOSI Test', 0},...
|
||||
{@getPOSITest,'getPOSI Test', 0},...
|
||||
{@sendWYPTTest,'WYPT Test', 0},...
|
||||
{@sendVIEWTest,'VIEW Test', 0},...
|
||||
{@pauseTest,'Pause Test', 0},...
|
||||
|
||||
@@ -202,6 +202,29 @@ class XPCTests(unittest.TestCase):
|
||||
expected = 0.0
|
||||
do_test()
|
||||
|
||||
def test_getCTRL(self):
|
||||
values = None
|
||||
ac = 0
|
||||
expected = None
|
||||
def do_test():
|
||||
with xpc.XPlaneConnect() as client:
|
||||
# Execute
|
||||
client.sendCTRL(values, ac)
|
||||
result = client.getCTRL(ac)
|
||||
|
||||
# Test
|
||||
self.assertEqual(len(result), len(expected))
|
||||
for a, e in zip(result, expected):
|
||||
self.assertAlmostEqual(a, e, 4)
|
||||
|
||||
values = [0.0, 0.0, 0.0, 0.8, 1.0, 0.5, -1.5]
|
||||
expected = values
|
||||
ac = 0
|
||||
do_test()
|
||||
|
||||
ac = 3
|
||||
do_test()
|
||||
|
||||
|
||||
def test_sendCTRL(self):
|
||||
# Setup
|
||||
@@ -270,6 +293,31 @@ class XPCTests(unittest.TestCase):
|
||||
ctrl[6] = 0.0
|
||||
do_test()
|
||||
|
||||
def test_getPOSI(self):
|
||||
values = None
|
||||
ac = 0
|
||||
expected = None
|
||||
def do_test():
|
||||
with xpc.XPlaneConnect() as client:
|
||||
# Execute
|
||||
client.pauseSim(True)
|
||||
client.sendPOSI(values, ac)
|
||||
result = client.getPOSI(ac)
|
||||
client.pauseSim(False)
|
||||
|
||||
# Test
|
||||
self.assertEqual(len(result), len(expected))
|
||||
for a, e in zip(result, expected):
|
||||
self.assertAlmostEqual(a, e, 4)
|
||||
|
||||
values = [ 37.524, -122.06899, 2500, 45, -45, 15, 1 ]
|
||||
expected = values
|
||||
ac = 0
|
||||
do_test()
|
||||
|
||||
ac = 3
|
||||
do_test()
|
||||
|
||||
def test_sendPOSI(self):
|
||||
# Setup
|
||||
drefs = ["sim/flightmodel/position/latitude",\
|
||||
|
||||
@@ -169,8 +169,8 @@ namespace XPC
|
||||
sprintf(multi, "sim/multiplayer/position/plane%i_gear_deploy", i);
|
||||
mdrefs[i][DREF_GearDeploy] = XPLMFindDataRef(multi);
|
||||
sprintf(multi, "sim/multiplayer/position/plane%i_flap_ratio", i);
|
||||
mdrefs[i][DREF_FlapSetting] = XPLMFindDataRef(multi); // Can't set the actual flap setting on npc aircraft
|
||||
mdrefs[i][DREF_FlapActual] = XPLMFindDataRef(multi);
|
||||
mdrefs[i][DREF_FlapSetting] = mdrefs[i][DREF_FlapActual]; // Can't set the actual flap setting on npc aircraft
|
||||
sprintf(multi, "sim/multiplayer/position/plane%i_flap_ratio2", i);
|
||||
mdrefs[i][DREF_FlapActual2] = XPLMFindDataRef(multi);
|
||||
sprintf(multi, "sim/multiplayer/position/plane%i_spoiler_ratio", i);
|
||||
@@ -183,6 +183,7 @@ namespace XPC
|
||||
mdrefs[i][DREF_Sweep] = XPLMFindDataRef(multi);
|
||||
sprintf(multi, "sim/multiplayer/position/plane%i_throttle", i);
|
||||
mdrefs[i][DREF_ThrottleActual] = XPLMFindDataRef(multi);
|
||||
mdrefs[i][DREF_ThrottleSet] = mdrefs[i][DREF_ThrottleActual]; // No throttle set for multiplayer planes.
|
||||
sprintf(multi, "sim/multiplayer/position/plane%i_yolk_pitch", i);
|
||||
mdrefs[i][DREF_YokePitch] = XPLMFindDataRef(multi);
|
||||
sprintf(multi, "sim/multiplayer/position/plane%i_yolk_roll", i);
|
||||
@@ -729,13 +730,13 @@ namespace XPC
|
||||
// http://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19770024290.pdf
|
||||
float q[4];
|
||||
float halfRad = 0.00872664625997F;
|
||||
orient[2] = halfRad * orient[2];
|
||||
orient[0] = halfRad * orient[0];
|
||||
orient[1] = halfRad * orient[1];
|
||||
q[0] = cos(orient[2]) * cos(orient[0]) * cos(orient[1]) + sin(orient[2]) * sin(orient[0]) * sin(orient[1]);
|
||||
q[1] = cos(orient[2]) * cos(orient[0]) * sin(orient[1]) - sin(orient[2]) * sin(orient[0]) * cos(orient[1]);
|
||||
q[2] = cos(orient[2]) * sin(orient[0]) * cos(orient[1]) + sin(orient[2]) * cos(orient[0]) * sin(orient[1]);
|
||||
q[3] = sin(orient[2]) * cos(orient[0]) * cos(orient[1]) - cos(orient[2]) * sin(orient[0]) * sin(orient[1]);
|
||||
float theta = halfRad * orient[0];
|
||||
float phi = halfRad * orient[1];
|
||||
float psi = halfRad * orient[2];
|
||||
q[0] = cos(phi) * cos(theta) * cos(psi) + sin(phi) * sin(theta) * sin(psi);
|
||||
q[1] = sin(phi) * cos(theta) * cos(psi) - cos(phi) * sin(theta) * sin(psi);
|
||||
q[2] = cos(phi) * sin(theta) * cos(psi) + sin(phi) * cos(theta) * sin(psi);
|
||||
q[3] = cos(phi) * cos(theta) * sin(psi) - sin(phi) * sin(theta) * cos(psi);
|
||||
|
||||
// If the sim is un-paused, this will overwrite the pitch/roll/yaw
|
||||
// values set above.
|
||||
|
||||
@@ -55,6 +55,8 @@ namespace XPC
|
||||
handlers.insert(std::make_pair("TEXT", MessageHandlers::HandleText));
|
||||
handlers.insert(std::make_pair("WYPT", MessageHandlers::HandleWypt));
|
||||
handlers.insert(std::make_pair("VIEW", MessageHandlers::HandleView));
|
||||
handlers.insert(std::make_pair("GETC", MessageHandlers::HandleGetC));
|
||||
handlers.insert(std::make_pair("GETP", MessageHandlers::HandleGetP));
|
||||
// X-Plane data messages
|
||||
handlers.insert(std::make_pair("DSEL", MessageHandlers::HandleXPlaneData));
|
||||
handlers.insert(std::make_pair("USEL", MessageHandlers::HandleXPlaneData));
|
||||
@@ -425,6 +427,43 @@ namespace XPC
|
||||
}
|
||||
}
|
||||
|
||||
void MessageHandlers::HandleGetC(const Message& msg)
|
||||
{
|
||||
const unsigned char* buffer = msg.GetBuffer();
|
||||
std::size_t size = msg.GetSize();
|
||||
if (size != 6)
|
||||
{
|
||||
Log::FormatLine(LOG_ERROR, "GCTL", "Unexpected message length: %u", size);
|
||||
return;
|
||||
}
|
||||
unsigned char aircraft = buffer[5];
|
||||
// TODO(jason-watkins): Get proper printf specifier for unsigned char
|
||||
Log::FormatLine(LOG_TRACE, "GCTL", "Getting control information for aircraft %u", aircraft);
|
||||
|
||||
float throttle[8];
|
||||
unsigned char response[31] = "CTRL";
|
||||
*((float*)(response + 5)) = DataManager::GetFloat(DREF_Elevator, aircraft);
|
||||
*((float*)(response + 9)) = DataManager::GetFloat(DREF_Aileron, aircraft);
|
||||
*((float*)(response + 13)) = DataManager::GetFloat(DREF_Rudder, aircraft);
|
||||
DataManager::GetFloatArray(DREF_ThrottleSet, throttle, 8, aircraft);
|
||||
*((float*)(response + 17)) = throttle[0];
|
||||
if (aircraft == 0)
|
||||
{
|
||||
response[21] = (char)DataManager::GetInt(DREF_GearHandle, aircraft);
|
||||
}
|
||||
else
|
||||
{
|
||||
float mpGear[10];
|
||||
DataManager::GetFloatArray(DREF_GearDeploy, mpGear, 10, aircraft);
|
||||
response[21] = mpGear[0] > 0.5 ? 1 : 0;
|
||||
}
|
||||
*((float*)(response + 22)) = DataManager::GetFloat(DREF_FlapSetting, aircraft);
|
||||
response[26] = aircraft;
|
||||
*((float*)(response + 27)) = DataManager::GetFloat(DREF_SpeedBrakeSet, aircraft);
|
||||
|
||||
sock->SendTo(response, 31, &connection.addr);
|
||||
}
|
||||
|
||||
void MessageHandlers::HandleGetD(const Message& msg)
|
||||
{
|
||||
const unsigned char* buffer = msg.GetBuffer();
|
||||
@@ -471,6 +510,34 @@ namespace XPC
|
||||
sock->SendTo(response, cur, &connection.addr);
|
||||
}
|
||||
|
||||
void MessageHandlers::HandleGetP(const Message& msg)
|
||||
{
|
||||
const unsigned char* buffer = msg.GetBuffer();
|
||||
std::size_t size = msg.GetSize();
|
||||
if (size != 6)
|
||||
{
|
||||
Log::FormatLine(LOG_ERROR, "GPOS", "Unexpected message length: %u", size);
|
||||
return;
|
||||
}
|
||||
unsigned char aircraft = buffer[5];
|
||||
Log::FormatLine(LOG_TRACE, "GPOS", "Getting position information for aircraft %u", aircraft);
|
||||
|
||||
unsigned char response[34] = "POSI";
|
||||
response[5] = (char)DataManager::GetInt(DREF_GearHandle, aircraft);
|
||||
*((float*)(response + 6)) = (float)DataManager::GetDouble(DREF_Latitude, aircraft);
|
||||
*((float*)(response + 10)) = (float)DataManager::GetDouble(DREF_Longitude, aircraft);
|
||||
*((float*)(response + 14)) = (float)DataManager::GetDouble(DREF_Elevation, aircraft);
|
||||
*((float*)(response + 18)) = DataManager::GetFloat(DREF_Pitch, aircraft);
|
||||
*((float*)(response + 22)) = DataManager::GetFloat(DREF_Roll, aircraft);
|
||||
*((float*)(response + 26)) = DataManager::GetFloat(DREF_HeadingTrue, aircraft);
|
||||
|
||||
float gear[10];
|
||||
DataManager::GetFloatArray(DREF_GearDeploy, gear, 10, aircraft);
|
||||
*((float*)(response + 30)) = gear[0];
|
||||
|
||||
sock->SendTo(response, 34, &connection.addr);
|
||||
}
|
||||
|
||||
void MessageHandlers::HandlePosi(const Message& msg)
|
||||
{
|
||||
// Update log
|
||||
|
||||
@@ -43,7 +43,9 @@ namespace XPC
|
||||
static void HandleCtrl(const Message& msg);
|
||||
static void HandleData(const Message& msg);
|
||||
static void HandleDref(const Message& msg);
|
||||
static void HandleGetC(const Message& msg);
|
||||
static void HandleGetD(const Message& msg);
|
||||
static void HandleGetP(const Message& msg);
|
||||
static void HandlePosi(const Message& msg);
|
||||
static void HandleSimu(const Message& msg);
|
||||
static void HandleText(const Message& msg);
|
||||
|
||||
@@ -135,7 +135,7 @@ namespace XPC
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::FormatLine(LOG_INFO, tag, "Send failed. (remote: %s)", GetHost(remote).c_str());
|
||||
Log::FormatLine(LOG_INFO, tag, "Send succeeded. (remote: %s)", GetHost(remote).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user