diff --git a/C/src/xplaneConnect.c b/C/src/xplaneConnect.c index 74b098d..f6f0a5d 100755 --- a/C/src/xplaneConnect.c +++ b/C/src/xplaneConnect.c @@ -48,9 +48,6 @@ #include #include - - - void printError(char *functionName, char *format, ...) { va_list args; @@ -694,3 +691,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 ****/ +/*****************************************************************************/ \ No newline at end of file diff --git a/C/src/xplaneConnect.h b/C/src/xplaneConnect.h index 391ec54..3827a68 100644 --- a/C/src/xplaneConnect.h +++ b/C/src/xplaneConnect.h @@ -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 @@ -214,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. /// diff --git a/Java/src/ViewType.java b/Java/src/ViewType.java new file mode 100644 index 0000000..2f24c3d --- /dev/null +++ b/Java/src/ViewType.java @@ -0,0 +1,60 @@ +//NOTICES: +// Copyright ã 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; + } +} diff --git a/Java/src/XPlaneConnect.java b/Java/src/XPlaneConnect.java index 2e1f336..ba545d5 100644 --- a/Java/src/XPlaneConnect.java +++ b/Java/src/XPlaneConnect.java @@ -720,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. diff --git a/MATLAB/+XPlaneConnect/XPlaneConnect.jar b/MATLAB/+XPlaneConnect/XPlaneConnect.jar index e4c0af5..c779711 100644 Binary files a/MATLAB/+XPlaneConnect/XPlaneConnect.jar and b/MATLAB/+XPlaneConnect/XPlaneConnect.jar differ diff --git a/MATLAB/+XPlaneConnect/sendVIEW.m b/MATLAB/+XPlaneConnect/sendVIEW.m new file mode 100644 index 0000000..d95814c --- /dev/null +++ b/MATLAB/+XPlaneConnect/sendVIEW.m @@ -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 + +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 + diff --git a/Python/src/xpc.py b/Python/src/xpc.py index 32b4d3c..c19bbdb 100644 --- a/Python/src/xpc.py +++ b/Python/src/xpc.py @@ -326,6 +326,23 @@ class XPlaneConnect(object): 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 @@ -350,3 +367,18 @@ class XPlaneConnect(object): 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 diff --git a/TestScripts/C Tests.win/CTests.vcxproj b/TestScripts/C Tests.win/CTests.vcxproj index b546a64..6c55744 100644 --- a/TestScripts/C Tests.win/CTests.vcxproj +++ b/TestScripts/C Tests.win/CTests.vcxproj @@ -33,6 +33,7 @@ + diff --git a/TestScripts/C Tests/ViewTests.h b/TestScripts/C Tests/ViewTests.h new file mode 100644 index 0000000..a25c14f --- /dev/null +++ b/TestScripts/C Tests/ViewTests.h @@ -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 \ No newline at end of file diff --git a/TestScripts/C Tests/main.c b/TestScripts/C Tests/main.c index ae01451..0f5cdd9 100644 --- a/TestScripts/C Tests/main.c +++ b/TestScripts/C Tests/main.c @@ -8,6 +8,7 @@ #include "PosiTests.h" #include "DataTests.h" #include "TextTests.h" +#include "ViewTests.h" #include "WyptTests.h" int main(int argc, const char * argv[]) @@ -48,10 +49,14 @@ int main(int argc, const char * argv[]) 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; } diff --git a/TestScripts/Java Tests/XPlaneConnectTest.java b/TestScripts/Java Tests/XPlaneConnectTest.java index e3caba5..fc7c76e 100644 --- a/TestScripts/Java Tests/XPlaneConnectTest.java +++ b/TestScripts/Java Tests/XPlaneConnectTest.java @@ -1,5 +1,6 @@ package gov.nasa.xpc.test; +import gov.nasa.xpc.ViewType; import gov.nasa.xpc.WaypointOp; import gov.nasa.xpc.XPlaneConnect; @@ -677,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); + } + + } } \ No newline at end of file diff --git a/TestScripts/MATLAB Tests/sendVIEWTest.m b/TestScripts/MATLAB Tests/sendVIEWTest.m new file mode 100644 index 0000000..4cfe29c --- /dev/null +++ b/TestScripts/MATLAB Tests/sendVIEWTest.m @@ -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 + diff --git a/TestScripts/MATLAB Tests/tests.m b/TestScripts/MATLAB Tests/tests.m index 6871686..11c8800 100644 --- a/TestScripts/MATLAB Tests/tests.m +++ b/TestScripts/MATLAB Tests/tests.m @@ -18,6 +18,7 @@ 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}}; diff --git a/TestScripts/Python Tests/Tests.py b/TestScripts/Python Tests/Tests.py index 558aa7c..2cdc825 100644 --- a/TestScripts/Python Tests/Tests.py +++ b/TestScripts/Python Tests/Tests.py @@ -319,6 +319,22 @@ class XPCTests(unittest.TestCase): # 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() diff --git a/xpcPlugin/MessageHandlers.cpp b/xpcPlugin/MessageHandlers.cpp index 1a94bf3..37c7e71 100644 --- a/xpcPlugin/MessageHandlers.cpp +++ b/xpcPlugin/MessageHandlers.cpp @@ -1,10 +1,26 @@ //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 "Drawing.h" #include "Log.h" +#include "XPLMUtilities.h" + #include #include @@ -36,8 +52,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)); @@ -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) { // Update Log diff --git a/xpcPlugin/MessageHandlers.h b/xpcPlugin/MessageHandlers.h index b7cfd25..123c39a 100644 --- a/xpcPlugin/MessageHandlers.h +++ b/xpcPlugin/MessageHandlers.h @@ -46,6 +46,7 @@ namespace XPC static void HandleSimu(Message& msg); static void HandleText(Message& msg); static void HandleWypt(Message& msg); + static void HandleView(Message& msg); static void HandleXPlaneData(Message& msg); static void HandleUnknown(Message& msg);