Merge branch 'view-command' into develop

Resolves #68
This commit is contained in:
Jason Watkins
2015-05-08 14:39:44 -07:00
16 changed files with 380 additions and 5 deletions

View File

@@ -48,9 +48,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <time.h> #include <time.h>
void printError(char *functionName, char *format, ...) void printError(char *functionName, char *format, ...)
{ {
va_list args; va_list args;
@@ -694,3 +691,31 @@ int sendWYPT(XPCSocket sock, WYPT_OP op, float points[], int count)
/*****************************************************************************/ /*****************************************************************************/
/**** End Drawing functions ****/ /**** 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 ****/
/*****************************************************************************/

View File

@@ -61,6 +61,23 @@ typedef enum
XPC_WYPT_DEL = 2, XPC_WYPT_DEL = 2,
XPC_WYPT_CLR = 3 XPC_WYPT_CLR = 3
} WYPT_OP; } 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 // Low Level UDP Functions
@@ -214,6 +231,13 @@ int sendCTRL(XPCSocket sock, float values[], int size, char ac);
/// \returns 0 if successful, otherwise a negative value. /// \returns 0 if successful, otherwise a negative value.
int sendTEXT(XPCSocket sock, char* msg, int x, int y); int sendTEXT(XPCSocket sock, char* msg, int x, int y);
/// Sets the camera view in X-Plane.
///
/// \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 /// Adds, removes, or clears a set of waypoints. If the command is clear, the points are ignored
/// and all points are removed. /// and all points are removed.
/// ///

60
Java/src/ViewType.java Normal file
View 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;
}
}

View File

@@ -720,6 +720,26 @@ public class XPlaneConnect implements AutoCloseable
sendUDP(os.toByteArray()); 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 * Adds, removes, or clears a set of waypoints. If the command is clear, the points are ignored
* and all points are removed. * and all points are removed.

View 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

View File

@@ -326,6 +326,23 @@ class XPlaneConnect(object):
buffer = struct.pack("<4sxiiB" + str(msgLen) + "s", "TEXT", x, y, msgLen, msg) buffer = struct.pack("<4sxiiB" + str(msgLen) + "s", "TEXT", x, y, msgLen, msg)
self.sendUDP(buffer) 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): def sendWYPT(self, op, points):
'''Adds, removes, or clears waypoints. Waypoints are three dimensional points on or '''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 above the Earth's surface that are represented visually in the simulator. Each
@@ -350,3 +367,18 @@ class XPlaneConnect(object):
else: else:
buffer = struct.pack("<4sxBB" + str(len(points)) + "f", "WYPT", op, len(points), *points) buffer = struct.pack("<4sxBB" + str(len(points)) + "f", "WYPT", op, len(points), *points)
self.sendUDP(buffer) self.sendUDP(buffer)
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

View File

@@ -33,6 +33,7 @@
<ClInclude Include="..\C Tests\Test.h" /> <ClInclude Include="..\C Tests\Test.h" />
<ClInclude Include="..\C Tests\TextTests.h" /> <ClInclude Include="..\C Tests\TextTests.h" />
<ClInclude Include="..\C Tests\UDPTests.h" /> <ClInclude Include="..\C Tests\UDPTests.h" />
<ClInclude Include="..\C Tests\ViewTests.h" />
<ClInclude Include="..\C Tests\WyptTests.h" /> <ClInclude Include="..\C Tests\WyptTests.h" />
</ItemGroup> </ItemGroup>
<PropertyGroup Label="Globals"> <PropertyGroup Label="Globals">

View 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

View File

@@ -8,6 +8,7 @@
#include "PosiTests.h" #include "PosiTests.h"
#include "DataTests.h" #include "DataTests.h"
#include "TextTests.h" #include "TextTests.h"
#include "ViewTests.h"
#include "WyptTests.h" #include "WyptTests.h"
int main(int argc, const char * argv[]) int main(int argc, const char * argv[])
@@ -48,10 +49,14 @@ int main(int argc, const char * argv[])
runTest(testTEXT, "TEXT"); runTest(testTEXT, "TEXT");
// Waypoints // Waypoints
runTest(testWYPT, "WYPT"); runTest(testWYPT, "WYPT");
// View
runTest(testView, "VIEW");
// setConn // setConn
runTest(testCONN, "CONN"); runTest(testCONN, "CONN");
printf( "----------------\nTest Summary\n\tFailed: %i\n\tPassed: %i\n", testFailed, testPassed ); printf( "----------------\nTest Summary\n\tFailed: %i\n\tPassed: %i\n", testFailed, testPassed );
printf("Press any key to exit.");
getchar();
return 0; return 0;
} }

View File

@@ -1,5 +1,6 @@
package gov.nasa.xpc.test; package gov.nasa.xpc.test;
import gov.nasa.xpc.ViewType;
import gov.nasa.xpc.WaypointOp; import gov.nasa.xpc.WaypointOp;
import gov.nasa.xpc.XPlaneConnect; import gov.nasa.xpc.XPlaneConnect;
@@ -677,4 +678,24 @@ public class XPlaneConnectTest
fail(); 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);
}
}
} }

View 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

View File

@@ -18,6 +18,7 @@ theTests = {{@openCloseTest, 'Open/Close Test', 0},...
{@CTRLTest,'CTRL Test', 0},... {@CTRLTest,'CTRL Test', 0},...
{@POSITest,'POSI Test', 0},... {@POSITest,'POSI Test', 0},...
{@sendWYPTTest,'WYPT Test', 0},... {@sendWYPTTest,'WYPT Test', 0},...
{@sendVIEWTest,'VIEW Test', 0},...
{@pauseTest,'Pause Test', 0},... {@pauseTest,'Pause Test', 0},...
{@setConnTest, 'setConn Test', 0}}; {@setConnTest, 'setConn Test', 0}};

View File

@@ -319,6 +319,22 @@ class XPCTests(unittest.TestCase):
# Cleanup # Cleanup
client.close() 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): def test_sendWYPT(self):
# Setup # Setup
client = xpc.XPlaneConnect() client = xpc.XPlaneConnect()

View File

@@ -1,10 +1,26 @@
//Copyright (c) 2013-2015 United States Government as represented by the Administrator of the //Copyright (c) 2013-2015 United States Government as represented by the Administrator of the
//National Aeronautics and Space Administration. All Rights Reserved. //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 "MessageHandlers.h"
#include "DataManager.h" #include "DataManager.h"
#include "Drawing.h" #include "Drawing.h"
#include "Log.h" #include "Log.h"
#include "XPLMUtilities.h"
#include <cmath> #include <cmath>
#include <cstring> #include <cstring>
@@ -36,8 +52,7 @@ namespace XPC
handlers.insert(std::make_pair("SIMU", MessageHandlers::HandleSimu)); handlers.insert(std::make_pair("SIMU", MessageHandlers::HandleSimu));
handlers.insert(std::make_pair("TEXT", MessageHandlers::HandleText)); handlers.insert(std::make_pair("TEXT", MessageHandlers::HandleText));
handlers.insert(std::make_pair("WYPT", MessageHandlers::HandleWypt)); handlers.insert(std::make_pair("WYPT", MessageHandlers::HandleWypt));
// Not implemented messages handlers.insert(std::make_pair("VIEW", MessageHandlers::HandleView));
handlers.insert(std::make_pair("VIEW", MessageHandlers::HandleUnknown));
// X-Plane data messages // X-Plane data messages
handlers.insert(std::make_pair("DSEL", MessageHandlers::HandleXPlaneData)); handlers.insert(std::make_pair("DSEL", MessageHandlers::HandleXPlaneData));
handlers.insert(std::make_pair("USEL", MessageHandlers::HandleXPlaneData)); handlers.insert(std::make_pair("USEL", MessageHandlers::HandleXPlaneData));
@@ -623,6 +638,26 @@ namespace XPC
} }
} }
void MessageHandlers::HandleView(Message& msg)
{
// Update Log
#if LOG_VERBOSITY > 0
Log::FormatLine("[VIEW] Message Received (Conn %i)", connection.id);
#endif
const std::size_t size = msg.GetSize();
if (size != 9)
{
#if LOG_VERBOSITY > 1
Log::FormatLine("[VIEW] Error: Unexpected length. Message was %d bytes, expected 9.", size);
#endif
return;
}
const unsigned char* buffer = msg.GetBuffer();
int type = *((int*)(buffer + 5));
XPLMCommandKeyStroke(type);
}
void MessageHandlers::HandleWypt(Message& msg) void MessageHandlers::HandleWypt(Message& msg)
{ {
// Update Log // Update Log

View File

@@ -46,6 +46,7 @@ namespace XPC
static void HandleSimu(Message& msg); static void HandleSimu(Message& msg);
static void HandleText(Message& msg); static void HandleText(Message& msg);
static void HandleWypt(Message& msg); static void HandleWypt(Message& msg);
static void HandleView(Message& msg);
static void HandleXPlaneData(Message& msg); static void HandleXPlaneData(Message& msg);
static void HandleUnknown(Message& msg); static void HandleUnknown(Message& msg);