Merge pull request #44 from jason-watkins/feature/sendCTRL

Add support for multiplayer aircraft to sendCTRL
This commit is contained in:
Christopher Teubert
2015-04-07 11:20:02 -07:00
13 changed files with 336 additions and 137 deletions

View File

@@ -373,7 +373,12 @@ short sendPOSI(struct xpcSocket recfd, short ACNum, short numArgs, float valueAr
short sendCTRL(struct xpcSocket recfd, short numArgs, float valueArray[])
{
char message[26] = {0};
return sendpCTRL(recfd, numArgs, valueArray, 0);
}
short sendpCTRL(struct xpcSocket recfd, short numArgs, float valueArray[], char acNum)
{
char message[27] = { 0 };
int i;
short position = 5;
@@ -406,11 +411,11 @@ short sendCTRL(struct xpcSocket recfd, short numArgs, float valueArray[])
// Float Values
memcpy(&message[position],&val,sizeof(float));
position += sizeof(float);
}
}
}
message[position] = acNum;
sendUDP(recfd, message, 26);
sendUDP(recfd, message, 27);
return 0;
}
@@ -509,17 +514,21 @@ short readPOSI(struct xpcSocket recfd, float resultArray[], int arraySize, floa
return -1;
}
float readCTRL(struct xpcSocket recfd, float resultArray[4], short *gear)
xpcCtrl readCTRL(struct xpcSocket recfd)
{
char buf[5000] = {0};
readUDP(recfd,buf, NULL);
xpcCtrl result;
char buf[5000] = { 0 };
readUDP(recfd, buf, NULL);
if (buf[0] != '\0') // Buffer is not empty
{
return parseCTRL(buf, resultArray, gear);
result = parseCTRL(buf);
}
return NAN;
else
{
result.aircraft = -1;
}
return result;
}
//PARSE
@@ -610,21 +619,38 @@ short parsePOSI(const char my_message[], float resultArray[], int arraySize, flo
return my_message[5]; // Aircraft
}
float parseCTRL(const char my_message[], float resultArray[], short *gear)
xpcCtrl parseCTRL(const char data[])
{
int i;
float flaps = 0;
// Controls
for (i = 0; i < 4; i++)
xpcCtrl result;
unsigned char len = data[4];
//Preconditions
//Validate message prefix to ensure we are looking at the right kind of packet.
if (strncmp(data, "CTRL", 4) != 0)
{
memcpy(&resultArray[i],&my_message[5+4*i],4);
result.aircraft = -1;
}
// Gear, Flaps
*gear = (short) my_message[21];
memcpy(&flaps,&my_message[22],4);
return flaps;
//Legacy packets that don't specify an aircraft number should be 22 bytes long.
//Packets specifying an A/C num should be 24 bytes.
else if (len != 26 && len != 27)
{
result.aircraft = -1;
}
//Everything checks out, so we can skip over the header and copy the raw data
//into the struct.
else
{
//NOTE: It's tempting to just do a single memcpy here, but we can't do that because the
// compiler is allowed to add padding to the struct type.
result.pitch = *((float*)(data + 5));
result.roll = *((float*)(data + 9));
result.yaw = *((float*)(data + 13));
result.throttle = *((float*)(data + 17));
result.gear = data[21];
result.flaps = *((float*)(data + 22));
if (len == 27)
{
result.aircraft = data[26];
}
}
return result;
}

View File

@@ -36,6 +36,17 @@
int sock;
#endif
};
typedef struct
{
float pitch;
float roll;
float yaw;
float throttle;
char gear;
float flaps;
char aircraft;
} xpcCtrl;
// Basic Functions
struct xpcSocket openUDP(unsigned short port, const char *xpIP, unsigned short xpPort);
@@ -58,9 +69,10 @@
short sendPOSI(struct xpcSocket recfd, short ACNum, short numArgs, float valueArray[]);
// Controls
float parseCTRL(const char my_message[], float resultArray[4], short *gear);
float readCTRL(struct xpcSocket recfd, float resultArray[4], short *gear);
short sendCTRL(struct xpcSocket recfd, short numArgs, float valueArray[]);
xpcCtrl parseCTRL(const char data[]);
xpcCtrl readCTRL(struct xpcSocket recfd);
short sendCTRL(struct xpcSocket recfd, short numArgs, float valueArray[]);
short sendpCTRL(struct xpcSocket recfd, short numArgs, float valueArray[], char acNum);
// DREF Manipulation
short readDREF(struct xpcSocket recfd, float *resultArray[], short arraySizes[]);

View File

@@ -410,7 +410,7 @@ public class XPlaneConnect implements AutoCloseable
* @param aircraft The aircraft to set. 0 for the player's aircraft.
* @throws IOException If the command cannot be sent.
*/
private void sendCTRL(float[] ctrl, int aircraft) throws IOException
public void sendCTRL(float[] ctrl, int aircraft) throws IOException
{
//Preconditions
if(ctrl == null)
@@ -421,13 +421,9 @@ public class XPlaneConnect implements AutoCloseable
{
throw new IllegalArgumentException("ctrl must have 6 or fewer elements.");
}
if(aircraft < 0)
if(aircraft < 0 || aircraft > 9)
{
throw new IllegalArgumentException("aircraft must be non-negative.");
}
if(aircraft != 0) //TODO: Implement support for non-player aircraft on plugin side.
{
throw new Error("Non-player aircraft not supported yet.");
throw new IllegalArgumentException("aircraft must be non-negative and less than 9.");
}
//Pad command values and convert to bytes
@@ -461,6 +457,7 @@ public class XPlaneConnect implements AutoCloseable
cur += 4;
}
}
bb.put(cur, (byte)aircraft);
//Build and send message
ByteArrayOutputStream os = new ByteArrayOutputStream();

View File

@@ -52,7 +52,10 @@ import XPlaneConnect.*
for i=1:min(length(ctrl),length(control))
control(i) = ctrl(i);
end
dataStream = [dataStream, typecast(single(control),'uint8')];
dataStream = [dataStream, typecast(single(control(1:4)),'uint8')];
dataStream = [dataStream, uint8(control(5))];
dataStream = [dataStream, typecast(single(control(6)),'uint8')];
dataStream = [dataStream, uint8(acft)];
% Send DATA
status = sendUDP(dataStream, IP, port);

View File

@@ -234,59 +234,118 @@ short sendDATATest() // sendDATA test
short sendCTRLTest() // sendCTRL test
{
printf("sendCTRL - ");
// Initialize
int i; // Iterator
char DREFArray[100][100];
float CTRL[6] = {0.0};
float *recDATA[100];
short DREFSizes[100];
struct xpcSocket sendPort, recvPort;
short result;
// Setup
for (i = 0; i < 100; i++) {
recDATA[i] = (float *) malloc(40*sizeof(float));
memset(DREFArray[i],0,100);
}
sendPort = openUDP( 49066, "127.0.0.1", 49009 );
recvPort = openUDP( 49008, "127.0.0.1", 49009 );
strcpy(DREFArray[0],"sim/cockpit2/controls/yoke_pitch_ratio");
strcpy(DREFArray[1],"sim/cockpit2/controls/yoke_roll_ratio");
strcpy(DREFArray[2],"sim/cockpit2/controls/yoke_heading_ratio");
strcpy(DREFArray[3],"sim/flightmodel/engine/ENGN_thro");
strcpy(DREFArray[4],"sim/cockpit/switches/gear_handle_status");
strcpy(DREFArray[5],"sim/flightmodel/controls/flaprqst");
printf("sendCTRL - ");
// Initialize
int i; // Iterator
char DREFArray[100][100];
float CTRL[6] = { 0.0 };
float *recDATA[100];
short DREFSizes[100];
struct xpcSocket sendPort, recvPort;
short result;
// Setup
for (i = 0; i < 100; i++) {
recDATA[i] = (float *)malloc(40 * sizeof(float));
memset(DREFArray[i], 0, 100);
}
sendPort = openUDP(49066, "127.0.0.1", 49009);
recvPort = openUDP(49008, "127.0.0.1", 49009);
strcpy(DREFArray[0], "sim/cockpit2/controls/yoke_pitch_ratio");
strcpy(DREFArray[1], "sim/cockpit2/controls/yoke_roll_ratio");
strcpy(DREFArray[2], "sim/cockpit2/controls/yoke_heading_ratio");
strcpy(DREFArray[3], "sim/flightmodel/engine/ENGN_thro");
strcpy(DREFArray[4], "sim/cockpit/switches/gear_handle_status");
strcpy(DREFArray[5], "sim/flightmodel/controls/flaprqst");
for (i = 0; i < 100; i++) {
DREFSizes[i] = (int)strlen(DREFArray[i]);
}
CTRL[3] = 0.8; // Throttle
CTRL[4] = 1; // Gear
CTRL[5] = 0.5; // Flaps
// Execute
sendCTRL(sendPort, 6, CTRL);
result = requestDREF(sendPort, recvPort, DREFArray, DREFSizes, 6, recDATA, DREFSizes); // Test
// Close
closeUDP(sendPort);
closeUDP(recvPort);
// Tests
if ( result < 0 )// Request 1 value
{
return -6;
}
for (i=0;i<6;i++)
{
if (fabs(recDATA[i][0]-CTRL[i])>1e-4)
{
return -i - 1;
}
}
CTRL[3] = 0.8; // Throttle
CTRL[4] = 1; // Gear
CTRL[5] = 0.5; // Flaps
return 0;
// Execute
sendCTRL(sendPort, 6, CTRL);
result = requestDREF(sendPort, recvPort, DREFArray, DREFSizes, 6, recDATA, DREFSizes); // Test
// Close
closeUDP(sendPort);
closeUDP(recvPort);
// Tests
if (result < 0)// Request 1 value
{
return -6;
}
for (i = 0; i<6; i++)
{
if (fabs(recDATA[i][0] - CTRL[i])>1e-4)
{
return -i - 1;
}
}
return 0;
}
short sendpCTRLTest()
{
printf("sendNonPlayerCTRL - ");
// Initialize
int i; // Iterator
char DREFArray[100][100];
float CTRL[6] = { 0.0 };
float *recDATA[100];
short DREFSizes[100];
struct xpcSocket sendPort, recvPort;
short result;
// Setup
for (i = 0; i < 100; i++)
{
recDATA[i] = (float *)malloc(40 * sizeof(float));
memset(DREFArray[i], 0, 100);
}
sendPort = openUDP(49066, "127.0.0.1", 49009);
recvPort = openUDP(49008, "127.0.0.1", 49009);
strcpy(DREFArray[0], "sim/multiplayer/position/plane1_yolk_pitch");
strcpy(DREFArray[1], "sim/multiplayer/position/plane1_yolk_roll");
strcpy(DREFArray[2], "sim/multiplayer/position/plane1_yolk_yaw");
strcpy(DREFArray[3], "sim/multiplayer/position/plane1_throttle");
strcpy(DREFArray[4], "sim/multiplayer/position/plane1_gear_deploy");
strcpy(DREFArray[5], "sim/multiplayer/position/plane1_flap_ratio");
for (i = 0; i < 100; i++)
{
DREFSizes[i] = (int)strlen(DREFArray[i]);
}
CTRL[3] = 0.8; // Throttle
CTRL[4] = 1; // Gear
CTRL[5] = 0.5; // Flaps
// Execute
sendpCTRL(sendPort, 6, CTRL, 1);
result = requestDREF(sendPort, recvPort, DREFArray, DREFSizes, 9, recDATA, DREFSizes); // Test
// Close
closeUDP(sendPort);
closeUDP(recvPort);
// Tests
if (result < 0)// Request 1 value
{
return -6;
}
for (i = 0; i<6; i++)
{
if (fabs(recDATA[i][0] - CTRL[i])>1e-4)
{
return -i - 1;
}
}
return 0;
}
short sendPOSITest() // sendPOSI test
@@ -486,8 +545,9 @@ int main(int argc, const char * argv[])
runTest(sendReadTest);
runTest(requestDREFTest);
runTest(sendDREFTest);
runTest(sendDATATest);
runTest(sendCTRLTest);
runTest(sendDATATest);
runTest(sendCTRLTest);
runTest(sendpCTRLTest);
runTest(sendPOSITest);
runTest(pauseTest);
runTest(connTest);

View File

@@ -303,12 +303,12 @@ public class XPlaneConnectTest
public void testSendCTRL() throws IOException
{
String[] 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/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[] ctrl = new float[] {0, 0, 1, 0.8F, 0, 1};
try(XPlaneConnect xpc = new XPlaneConnect())
@@ -326,6 +326,40 @@ public class XPlaneConnectTest
}
}
@Test
public void testSendCTRL_NPC() throws IOException
{
String[] drefs1 = {
"sim/multiplayer/position/plane1_yolk_pitch",
"sim/multiplayer/position/plane1_yolk_roll",
"sim/multiplayer/position/plane1_yolk_yaw",
"sim/multiplayer/position/plane1_throttle"
};
String[] drefs2 = {
"sim/multiplayer/position/plane1_gear_deploy",
"sim/multiplayer/position/plane1_flap_ratio"
};
float[] ctrl = new float[] {0, 0, 1, 0.8F, 0, 0.5F};
try(XPlaneConnect xpc = new XPlaneConnect())
{
xpc.sendCTRL(ctrl, 1);
float[][] result1 = xpc.requestDREFs(drefs1);
float[][] result2 = xpc.requestDREFs(drefs2);
if(result1.length != 4 || result2.length != 2)
{
fail();
}
for(int i = 0; i < 4; ++i)
{
assertEquals(ctrl[i], result1[i][0], 1e-2);
}
for(int i = 0; i < 2; ++i)
{
assertEquals(ctrl[i + 4], result2[i][0], 1e-2);
}
}
}
@Test(expected = IllegalArgumentException.class)
public void testSendCTRL_NullCtrl() throws IOException
{

View File

@@ -22,5 +22,23 @@ for i=1:length(CTRL)-1
assert(abs(result{i}(1)-CTRL(i))<1e-4,['CTRLTest: DATA set unsucessful-',num2str(i)]);
end
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'};
THROT = rand();
CTRL = [0.0, 0.0, 1.0, THROT, 0.0, 1.0];
sendCTRL(CTRL, 1);
result = requestDREF(DREFS);
assert(isequal(length(result),6),'CTRLTest: requestDREF unsucessful-wrong number of elements returned');
assert(isequal(length(result{4}),8),'CTRLTest: requestDREF unsucessful- element 1 incorrect size (should be size 8)');
for i=1:length(CTRL)-1
assert(abs(result{i}(1)-CTRL(i))<1e-4,['CTRLTest: DATA set unsucessful-',num2str(i)]);
end
end

View File

@@ -719,47 +719,79 @@ int handlePOSI(char buf[])
int handleCTRL(char buf[])
{
char logmsg[100];
float flaps;
float controls[4] = {0.0};
float throtArray[8] = {0};
xpcCtrl ctrl;
float thr[8] = { 0 };
short i;
short gear = -1;
// UPDATE LOG
sprintf(logmsg,"[CTRL] Message Received (Conn %i)", current_connection+1);
updateLog(logmsg, strlen(logmsg));
flaps = parseCTRL(buf,controls,&gear);
if ( flaps != flaps ) // Is NaN
ctrl = parseCTRL(buf);
if (ctrl.aircraft < 0) //parseCTRL failed
{
return 1;
}
// SET CONTROLS
XPLMSetDataf(XPLMDataRefs[11][0],controls[0]);
XPLMSetDataf(XPLMDataRefs[11][1],controls[1]);
XPLMSetDataf(XPLMDataRefs[11][2],controls[2]);
// SET Throttle
for ( i=0; i<8; i++ )
if (ctrl.aircraft > 19) //Can only handle 19 non-player aircraft right now
{
throtArray[i]=controls[3];
return 2;
}
XPLMSetDatavf(XPLMDataRefs[25][0],throtArray,0,8);
XPLMSetDatavf(XPLMDataRefs[26][0],throtArray,0,8);
setDREF(XPLMFindDataRef("sim/flightmodel/engine/ENGN_thro_override"),controls,3,1);
// SET Gear/Flaps
if ( gear != -1 )
if (ctrl.aircraft == 0) //player aircraft
{
setGEAR(0, gear, 0); // Gear
// SET CONTROLS
XPLMSetDataf(XPLMDataRefs[11][0], ctrl.pitch);
XPLMSetDataf(XPLMDataRefs[11][1], ctrl.roll);
XPLMSetDataf(XPLMDataRefs[11][2], ctrl.yaw);
// SET Throttle
for (i = 0; i<8; i++)
{
thr[i] = ctrl.throttle;
}
XPLMSetDatavf(XPLMDataRefs[25][0], thr, 0, 8);
XPLMSetDatavf(XPLMDataRefs[26][0], thr, 0, 8);
setDREF(XPLMFindDataRef("sim/flightmodel/engine/ENGN_thro_override"), thr, 0, 1);
// SET Gear/Flaps
if (ctrl.gear != -1)
{
setGEAR(0, ctrl.gear, 0); // Gear
}
if (ctrl.flaps < -999.5 || ctrl.flaps > -997.5) // Flaps
{
XPLMSetDataf(XPLMDataRefs[13][3], ctrl.flaps);
}
}
if ( flaps < -999.5 || flaps > -997.5 ) // Flaps
else //non-player aircraft
{
XPLMSetDataf(XPLMDataRefs[13][3],flaps);
}
// SET CONTROLS
XPLMSetDataf(multiplayer[ctrl.aircraft][14], ctrl.pitch);
XPLMSetDataf(multiplayer[ctrl.aircraft][15], ctrl.roll);
XPLMSetDataf(multiplayer[ctrl.aircraft][16], ctrl.yaw);
// SET Throttle
for (i = 0; i<8; i++)
{
thr[i] = ctrl.throttle;
}
XPLMSetDatavf(multiplayer[ctrl.aircraft][13], thr, 0, 8);
// SET Gear/Flaps
if (ctrl.gear != -1)
{
float gear[10];
for (int i = 0; i < 10; ++i)
{
gear[i] = ctrl.gear;
}
XPLMSetDatavf(multiplayer[ctrl.aircraft][6], gear, 0, 10);
}
if (ctrl.flaps < -999.5 || ctrl.flaps > -997.5) // Flaps
{
XPLMSetDataf(multiplayer[ctrl.aircraft][7], ctrl.flaps);
XPLMSetDataf(multiplayer[ctrl.aircraft][8], ctrl.flaps);
}
}
return 0;
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -32,7 +32,7 @@
#include "xpcPluginTools.h"
XPLMDataRef XPLMDataRefs[134][8];
XPLMDataRef multiplayer[19][8];
XPLMDataRef multiplayer[20][17];
XPLMDataRef AIswitch;
void readMessage(struct xpcSocket * recSocket, struct XPCMessage * pMessage)
@@ -234,22 +234,42 @@ void buildXPLMDataRefs()
// Multiplayer
for ( i = 0; i < 19; i++ )
for ( i = 1; i < 20; i++ )
{
sprintf(multi,"sim/multiplayer/position/plane%i_x",i); // X
sprintf(multi, "sim/multiplayer/position/plane%i_x", i); // X
multiplayer[i][0] = XPLMFindDataRef(multi);
sprintf(multi,"sim/multiplayer/position/plane%i_y",i); // Y
sprintf(multi, "sim/multiplayer/position/plane%i_y", i); // Y
multiplayer[i][1] = XPLMFindDataRef(multi);
sprintf(multi,"sim/multiplayer/position/plane%i_z",i); // Z
sprintf(multi,"sim/multiplayer/position/plane%i_z", i); // Z
multiplayer[i][2] = XPLMFindDataRef(multi);
sprintf(multi,"sim/multiplayer/position/plane%i_the",i); // Theta (Pitch)
sprintf(multi,"sim/multiplayer/position/plane%i_the", i); // Theta (Pitch)
multiplayer[i][3] = XPLMFindDataRef(multi);
sprintf(multi,"sim/multiplayer/position/plane%i_phi",i); // Phi (Roll)
sprintf(multi,"sim/multiplayer/position/plane%i_phi", i); // Phi (Roll)
multiplayer[i][4] = XPLMFindDataRef(multi);
sprintf(multi,"sim/multiplayer/position/plane%i_psi",i); // Psi (Heading-True)
multiplayer[i][5] = XPLMFindDataRef(multi);
sprintf(multi,"sim/multiplayer/position/plane%i_gear_deploy",i); // Landing Gear
multiplayer[i][6] = XPLMFindDataRef(multi);
sprintf(multi,"sim/multiplayer/position/plane%i_psi", i); // Psi (Heading-True)
multiplayer[i][5] = XPLMFindDataRef(multi);
sprintf(multi, "sim/multiplayer/position/plane%i_gear_deploy", i); // Landing Gear
multiplayer[i][6] = XPLMFindDataRef(multi);
sprintf(multi, "sim/multiplayer/position/plane%i_flap_ratio", i);
multiplayer[i][7] = XPLMFindDataRef(multi);
sprintf(multi, "sim/multiplayer/position/plane%i_flap_ratio2", i);
multiplayer[i][8] = XPLMFindDataRef(multi);
sprintf(multi, "sim/multiplayer/position/plane%i_spoiler_ratio", i);
multiplayer[i][9] = XPLMFindDataRef(multi);
sprintf(multi, "sim/multiplayer/position/plane%i_speedbrake_ratio", i);
multiplayer[i][10] = XPLMFindDataRef(multi);
sprintf(multi, "sim/multiplayer/position/plane%i_slat_ratio", i);
multiplayer[i][11] = XPLMFindDataRef(multi);
sprintf(multi, "sim/multiplayer/position/plane%i_wing_sweep", i);
multiplayer[i][12] = XPLMFindDataRef(multi);
sprintf(multi, "sim/multiplayer/position/plane%i_throttle", i);
multiplayer[i][13] = XPLMFindDataRef(multi);
sprintf(multi, "sim/multiplayer/position/plane%i_yolk_pitch", i);
multiplayer[i][14] = XPLMFindDataRef(multi);
sprintf(multi, "sim/multiplayer/position/plane%i_yolk_roll", i);
multiplayer[i][15] = XPLMFindDataRef(multi);
sprintf(multi, "sim/multiplayer/position/plane%i_yolk_yaw", i);
multiplayer[i][16] = XPLMFindDataRef(multi);
}
AIswitch = XPLMFindDataRef("sim/operation/override/override_plane_ai_autopilot");
}
@@ -358,12 +378,9 @@ int printBufferToLog(struct XPCMessage & msg)
}
else if (strncmp(msg.head,"CTRL",4)==0)
{// Header = CTRL (Control)
float flaps;
float controls[4];
short gear;
flaps = parseCTRL(msg.msg,controls,&gear);
xpcCtrl ctrl = parseCTRL(msg.msg);
sprintf(logmsg,"%s (%f %f %f) %f %hi %f",logmsg, controls[0], controls[1], controls[2], controls[3] , gear, flaps);
sprintf(logmsg,"%s (%f %f %f) %f %hi %f",logmsg, ctrl.pitch, ctrl.roll, ctrl.yaw, ctrl.throttle, ctrl.gear, ctrl.flaps);
updateLog(logmsg,strlen(logmsg));

View File

@@ -14,7 +14,7 @@
#include "XPLMDataAccess.h"
extern XPLMDataRef XPLMDataRefs[134][8];
extern XPLMDataRef multiplayer[19][8];
extern XPLMDataRef multiplayer[20][17];
extern XPLMDataRef AIswitch;
struct XPCMessage