From fb8940583e4e8c985f2454da4ea7dd0376bb2e0b Mon Sep 17 00:00:00 2001 From: Jason Watkins Date: Thu, 17 Oct 2019 12:35:21 -0700 Subject: [PATCH 01/50] Make SetPosition and SetOrientation do nothing if all values are "default" placeholder --- xpcPlugin/DataManager.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/xpcPlugin/DataManager.cpp b/xpcPlugin/DataManager.cpp index 6e66abb4..09f57ed6 100644 --- a/xpcPlugin/DataManager.cpp +++ b/xpcPlugin/DataManager.cpp @@ -668,6 +668,11 @@ namespace XPC return; } + if (IsDefault(pos[0]) && IsDefault(pos[1]) && IsDefault(pos[2])) + { + Log::WriteLine(LOG_INFO, "DMAN", "Skipped SetPosition. All values were default"); + return; + } if (IsDefault(pos[0])) { pos[0] = GetDouble(DREF_Latitude, aircraft); @@ -718,6 +723,12 @@ namespace XPC return; } + + if (IsDefault(orient[0]) && IsDefault(orient[1]) && IsDefault(orient[2])) + { + Log::WriteLine(LOG_INFO, "DMAN", "Skipped SetPosition. All values were default"); + return; + } if (IsDefault(orient[0])) { orient[0] = GetFloat(DREF_Pitch, aircraft); From 2ff4497de5ebff14fd164dbde529a78014252d41 Mon Sep 17 00:00:00 2001 From: Jason Watkins Date: Thu, 17 Oct 2019 15:22:03 -0700 Subject: [PATCH 02/50] Fix incorrect gear read in HandlePosi --- xpcPlugin/Message.cpp | 22 +++++++++-- xpcPlugin/MessageHandlers.cpp | 72 ++++++++++++++++++----------------- 2 files changed, 56 insertions(+), 38 deletions(-) diff --git a/xpcPlugin/Message.cpp b/xpcPlugin/Message.cpp index f3401f0c..eb28fe40 100644 --- a/xpcPlugin/Message.cpp +++ b/xpcPlugin/Message.cpp @@ -141,11 +141,25 @@ namespace XPC else if (head == "POSI") { char aircraft = buffer[5]; - float gear = *((float*)(buffer + 30)); - float pos[3]; + float gear; + double pos[3]; float orient[3]; - memcpy(pos, buffer + 6, 12); - memcpy(orient, buffer + 18, 12); + if (size == 34) /* lat/lon/h as 32-bit float */ + { + float posd_32[3]; + memcpy(posd_32, buffer + 6, 12); + pos[0] = posd_32[0]; + pos[1] = posd_32[1]; + pos[2] = posd_32[2]; + memcpy(orient, buffer + 18, 12); + memcpy(&gear, buffer + 30, 4); + } + else if (size == 46) /* lat/lon/h as 64-bit double */ + { + memcpy(pos, buffer + 6, 24); + memcpy(orient, buffer + 30, 12); + memcpy(&gear, buffer + 42, 4); + } ss << " AC:" << (int)aircraft; ss << " Pos:(" << pos[0] << ' ' << pos[1] << ' ' << pos[2] << ") Orient:("; ss << orient[0] << ' ' << orient[1] << ' ' << orient[2] << ") Gear:"; diff --git a/xpcPlugin/MessageHandlers.cpp b/xpcPlugin/MessageHandlers.cpp index cc4ee18f..dc386fd5 100644 --- a/xpcPlugin/MessageHandlers.cpp +++ b/xpcPlugin/MessageHandlers.cpp @@ -39,7 +39,7 @@ namespace XPC std::string MessageHandlers::connectionKey; MessageHandlers::ConnectionInfo MessageHandlers::connection; UDPSocket* MessageHandlers::sock; - + static sockaddr multicast_address = UDPSocket::GetAddr(MULTICAST_GROUP, MULITCAST_PORT); void MessageHandlers::SetSocket(UDPSocket* socket) @@ -136,11 +136,11 @@ namespace XPC MessageHandlers::HandleUnknown(msg); } } - + void MessageHandlers::SendBeacon(const std::string& pluginVersion, unsigned short pluginReceivePort, int xplaneVersion) { - + unsigned char response[128] = "BECN"; - + std::size_t cur = 5; // 2 bytes plugin port @@ -150,12 +150,12 @@ namespace XPC // 4 bytes xplane version *((uint32_t*)(response + cur)) = xplaneVersion; cur += sizeof(uint32_t); - + // plugin version int len = pluginVersion.length(); memcpy(response + cur, pluginVersion.c_str(), len); cur += strlen(pluginVersion.c_str()) + len; - + sock->SendTo(response, cur, &multicast_address); } @@ -580,21 +580,25 @@ namespace XPC const std::size_t size = msg.GetSize(); char aircraftNumber = buffer[5]; - float gear = *((float*)(buffer + 42)); + float gear; double posd[3]; float orient[3]; if (size == 34) /* lat/lon/h as 32-bit float */ { - posd[0] = *((float*)&buffer[6]); - posd[1] = *((float*)&buffer[10]); - posd[2] = *((float*)&buffer[14]); + float posd_32[3]; + memcpy(posd_32, buffer + 6, 12); + posd[0] = posd_32[0]; + posd[1] = posd_32[1]; + posd[2] = posd_32[2]; memcpy(orient, buffer + 18, 12); + memcpy(&gear, buffer + 30, 4); } else if (size == 46) /* lat/lon/h as 64-bit double */ { - memcpy(posd, buffer + 6, 3*8); + memcpy(posd, buffer + 6, 24); memcpy(orient, buffer + 30, 12); + memcpy(&gear, buffer + 42, 4); } else { @@ -717,14 +721,14 @@ namespace XPC Log::WriteLine(LOG_INFO, "TEXT", "[TEXT] Text set"); } } - + void MessageHandlers::HandleView(const Message& msg) { // Update Log Log::FormatLine(LOG_TRACE, "VIEW", "Message Received(Conn %i)", connection.id); int enable_camera_location = 0; - + const std::size_t size = msg.GetSize(); if (size == 9) { @@ -743,11 +747,11 @@ namespace XPC const unsigned char* buffer = msg.GetBuffer(); int type = *((int*)(buffer + 5)); XPLMCommandKeyStroke(type); - + if(type == 79 && enable_camera_location == 1) // runway camera view { static struct CameraProperties campos; - + campos.loc[0] = *(double*)(buffer+9); campos.loc[1] = *(double*)(buffer+17); campos.loc[2] = *(double*)(buffer+25); @@ -755,60 +759,60 @@ namespace XPC campos.direction[1] = -998; campos.direction[2] = -998; campos.zoom = *(float*)(buffer+33); - + Log::FormatLine(LOG_TRACE, "VIEW", "Cam pos %f %f %f zoom %f", campos.loc[0], campos.loc[1], campos.loc[2],campos.zoom); - + XPLMControlCamera(xplm_ControlCameraUntilViewChanges, CamFunc, &campos); } } - + int MessageHandlers::CamFunc( XPLMCameraPosition_t * outCameraPosition, int inIsLosingControl, void *inRefcon) { if (outCameraPosition && !inIsLosingControl) { struct CameraProperties* campos = (struct CameraProperties*)inRefcon; - + // camera position double clat = campos->loc[0]; double clon = campos->loc[1]; double calt = campos->loc[2]; - + double cX, cY, cZ; XPLMWorldToLocal(clat, clon, calt, &cX, &cY, &cZ); - + outCameraPosition->x = cX; outCameraPosition->y = cY; outCameraPosition->z = cZ; - + // Log::FormatLine(LOG_TRACE, "CAM", "Cam pos %f %f %f", clat, clon, calt); - + if(campos->direction[0] == -998) // calculate camera direction { // aircraft position double x = XPC::DataManager::GetDouble(XPC::DREF_LocalX, 0); double y = XPC::DataManager::GetDouble(XPC::DREF_LocalY, 0); double z = XPC::DataManager::GetDouble(XPC::DREF_LocalZ, 0); - + // relative position vector cam to plane double dx = x - cX; double dy = y - cY; double dz = z - cZ; - + // Log::FormatLine(LOG_TRACE, "CAM", "Cam vect %f %f %f", dx, dy, dz); - + double pi = 3.141592653589793; - + // horizontal distance double dist = sqrt(dx*dx + dz*dz); - + outCameraPosition->pitch = atan2(dy, dist) * 180.0/pi; - + double angle = atan2(dz, dx) * 180.0/pi; // rel to pos right (pos X) - + outCameraPosition->heading = 90 + angle; // rel to north - + // Log::FormatLine(LOG_TRACE, "CAM", "Cam p %f hdg %f ", outCameraPosition->pitch, outCameraPosition->heading); - + outCameraPosition->roll = 0; } else @@ -817,10 +821,10 @@ namespace XPC outCameraPosition->pitch = campos->direction[1]; outCameraPosition->heading = campos->direction[2]; } - + outCameraPosition->zoom = campos->zoom; } - + return 1; } From 662ec2bf207221cfa790b3606ffbedbbc7f743b5 Mon Sep 17 00:00:00 2001 From: Jason Watkins Date: Wed, 6 Nov 2019 08:23:51 -0800 Subject: [PATCH 03/50] Fix macOS azure builds (#187) - Updated SDK version to 10.15 --- azure-pipelines.yml | 265 ++++++++++++++++++++++---------------------- 1 file changed, 132 insertions(+), 133 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index d04d24ac..120c06b6 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -6,11 +6,11 @@ trigger: branches: include: - # Build all branches starting with 'ms-' This is useful when making and testing chanes made to this file - - ms-* + # Build all branches starting with 'ms-' This is useful when making and testing chanes made to this file + - ms-* tags: include: - - '*' + - "*" # pr: # - '*' variables: @@ -27,139 +27,138 @@ variables: # https://docs.microsoft.com/en-us/azure/devops/pipelines/library/service-endpoints?view=azure-devops&tabs=yaml#sep-github xpcGitHubConnection: XPC-Azure - stages: - stage: Build jobs: - - job: macOS - pool: - vmImage: 'macos-latest' - - steps: - - task: Xcode@5 - inputs: - actions: 'build' - scheme: '' - sdk: 'macosx10.14' - configuration: 'Release' - xcWorkspacePath: 'xpcPlugin/xpcPlugin.xcodeproj' - xcodeVersion: 'default' # Options: 8, 9, 10, default, specifyPath - - task: PublishPipelineArtifact@0 - inputs: - artifactName: '$(xpcArtifactNameMac)' - targetPath: '$(xpcBuildOutputPath)' - - - job: Linux - pool: - vmImage: 'ubuntu-latest' - - steps: - - script: | - sudo add-apt-repository ppa:ubuntu-toolchain-r/test - sudo apt-get update - sudo apt-get install -y g++-5 mesa-common-dev g++-multilib g++-5-multilib - displayName: 'apt install' - - - script: | - cd xpcPlugin - cmake . - make - displayName: 'make' - - - task: PublishPipelineArtifact@0 - inputs: - artifactName: 'xpc-linux' - targetPath: '$(xpcBuildOutputPath)' - - - job: Windows - pool: - vmImage: 'vs2017-win2016' - - variables: - solution: 'xpcPlugin/xpcPlugin/xpcPlugin.sln' - buildPlatform: 'Win32|x64' - buildConfiguration: 'Release' - appxPackageDir: '$(build.artifactStagingDirectory)\AppxPackages\\' - - steps: - - task: NuGetToolInstaller@0 - - - task: NuGetCommand@2 - inputs: - restoreSolution: '$(solution)' - - - task: VSBuild@1 - inputs: - platform: 'Win32' - solution: '$(solution)' - configuration: '$(buildConfiguration)' - msbuildArgs: '/p:AppxBundlePlatforms="$(buildPlatform)" /p:AppxPackageDir="$(appxPackageDir)" /p:AppxBundle=Always /p:UapAppxPackageBuildMode=StoreUpload' - - - task: VSBuild@1 - inputs: - platform: 'x64' - solution: '$(solution)' - configuration: '$(buildConfiguration)' - msbuildArgs: '/p:AppxBundlePlatforms="$(buildPlatform)" /p:AppxPackageDir="$(appxPackageDir)" /p:AppxBundle=Always /p:UapAppxPackageBuildMode=StoreUpload' - - - task: Bash@3 - inputs: - targetType: 'inline' - script: | - rm $(xpcBuildOutputPath)/win.exp - rm $(xpcBuildOutputPath)/win.lib - rm $(xpcBuildOutputPath)/64/win.exp - rm $(xpcBuildOutputPath)/64/win.lib - - - task: PublishPipelineArtifact@0 - inputs: - artifactName: '$(xpcArtifactNameWindows)' - targetPath: '$(xpcBuildOutputPath)' + - job: macOS + pool: + vmImage: "macos-latest" + + steps: + - task: Xcode@5 + inputs: + actions: "build" + scheme: "" + sdk: "macosx10.15" + configuration: "Release" + xcWorkspacePath: "xpcPlugin/xpcPlugin.xcodeproj" + xcodeVersion: "default" # Options: 8, 9, 10, default, specifyPath + - task: PublishPipelineArtifact@0 + inputs: + artifactName: "$(xpcArtifactNameMac)" + targetPath: "$(xpcBuildOutputPath)" + + - job: Linux + pool: + vmImage: "ubuntu-latest" + + steps: + - script: | + sudo add-apt-repository ppa:ubuntu-toolchain-r/test + sudo apt-get update + sudo apt-get install -y g++-5 mesa-common-dev g++-multilib g++-5-multilib + displayName: "apt install" + + - script: | + cd xpcPlugin + cmake . + make + displayName: "make" + + - task: PublishPipelineArtifact@0 + inputs: + artifactName: "xpc-linux" + targetPath: "$(xpcBuildOutputPath)" + + - job: Windows + pool: + vmImage: "vs2017-win2016" + + variables: + solution: "xpcPlugin/xpcPlugin/xpcPlugin.sln" + buildPlatform: "Win32|x64" + buildConfiguration: "Release" + appxPackageDir: '$(build.artifactStagingDirectory)\AppxPackages\\' + + steps: + - task: NuGetToolInstaller@0 + + - task: NuGetCommand@2 + inputs: + restoreSolution: "$(solution)" + + - task: VSBuild@1 + inputs: + platform: "Win32" + solution: "$(solution)" + configuration: "$(buildConfiguration)" + msbuildArgs: '/p:AppxBundlePlatforms="$(buildPlatform)" /p:AppxPackageDir="$(appxPackageDir)" /p:AppxBundle=Always /p:UapAppxPackageBuildMode=StoreUpload' + + - task: VSBuild@1 + inputs: + platform: "x64" + solution: "$(solution)" + configuration: "$(buildConfiguration)" + msbuildArgs: '/p:AppxBundlePlatforms="$(buildPlatform)" /p:AppxPackageDir="$(appxPackageDir)" /p:AppxBundle=Always /p:UapAppxPackageBuildMode=StoreUpload' + + - task: Bash@3 + inputs: + targetType: "inline" + script: | + rm $(xpcBuildOutputPath)/win.exp + rm $(xpcBuildOutputPath)/win.lib + rm $(xpcBuildOutputPath)/64/win.exp + rm $(xpcBuildOutputPath)/64/win.lib + + - task: PublishPipelineArtifact@0 + inputs: + artifactName: "$(xpcArtifactNameWindows)" + targetPath: "$(xpcBuildOutputPath)" - stage: Deploy jobs: - - job: Package_Binaries - displayName: 'Package Binaries' - pool: - vmImage: 'ubuntu-latest' - - steps: - - task: DownloadPipelineArtifact@0 - inputs: - artifactName: '$(xpcArtifactNameMac)' - targetPath: $(System.DefaultWorkingDirectory)/$(xpcPackageName) - - task: DownloadPipelineArtifact@0 - inputs: - artifactName: '$(xpcArtifactNameLinux)' - targetPath: $(System.DefaultWorkingDirectory)/$(xpcPackageName) - - - task: DownloadPipelineArtifact@0 - inputs: - artifactName: '$(xpcArtifactNameWindows)' - targetPath: $(System.DefaultWorkingDirectory)/$(xpcPackageName) - - - task: PublishPipelineArtifact@0 - inputs: - artifactName: '$(xpcPackageName)' - targetPath: $(System.DefaultWorkingDirectory)/$(xpcPackageName) - - # Archive Files - - task: ArchiveFiles@2 - inputs: - rootFolderOrFile: '$(System.DefaultWorkingDirectory)/$(xpcPackageName)' - includeRootFolder: true - archiveType: 'zip' - archiveFile: '$(Build.ArtifactStagingDirectory)/$(xpcPackageName).zip' - - # Uploads the .zip to GitHub and creates a new "Release" with the commit tag - # This tasks runs only on pushed tags - - task: GitHubRelease@0 - inputs: - gitHubConnection: '$(xpcGitHubConnection)' - repositoryName: '$(Build.Repository.Name)' - action: 'create' - target: '$(Build.SourceVersion)' - tagSource: 'auto' - tag: $(tagName) - assets: '$(Build.ArtifactStagingDirectory)/$(xpcPackageName).zip' - isPreRelease: true + - job: Package_Binaries + displayName: "Package Binaries" + pool: + vmImage: "ubuntu-latest" + + steps: + - task: DownloadPipelineArtifact@0 + inputs: + artifactName: "$(xpcArtifactNameMac)" + targetPath: $(System.DefaultWorkingDirectory)/$(xpcPackageName) + - task: DownloadPipelineArtifact@0 + inputs: + artifactName: "$(xpcArtifactNameLinux)" + targetPath: $(System.DefaultWorkingDirectory)/$(xpcPackageName) + + - task: DownloadPipelineArtifact@0 + inputs: + artifactName: "$(xpcArtifactNameWindows)" + targetPath: $(System.DefaultWorkingDirectory)/$(xpcPackageName) + + - task: PublishPipelineArtifact@0 + inputs: + artifactName: "$(xpcPackageName)" + targetPath: $(System.DefaultWorkingDirectory)/$(xpcPackageName) + + # Archive Files + - task: ArchiveFiles@2 + inputs: + rootFolderOrFile: "$(System.DefaultWorkingDirectory)/$(xpcPackageName)" + includeRootFolder: true + archiveType: "zip" + archiveFile: "$(Build.ArtifactStagingDirectory)/$(xpcPackageName).zip" + + # Uploads the .zip to GitHub and creates a new "Release" with the commit tag + # This tasks runs only on pushed tags + - task: GitHubRelease@0 + inputs: + gitHubConnection: "$(xpcGitHubConnection)" + repositoryName: "$(Build.Repository.Name)" + action: "create" + target: "$(Build.SourceVersion)" + tagSource: "auto" + tag: $(tagName) + assets: "$(Build.ArtifactStagingDirectory)/$(xpcPackageName).zip" + isPreRelease: true From 1fd6400a98a2840b05bde7574a278739c95672e8 Mon Sep 17 00:00:00 2001 From: Kai Lehmkuehler Date: Wed, 6 Nov 2019 17:45:54 +0100 Subject: [PATCH 04/50] Terrain height probe (#186) * ignore binaries * Add terrain probe * requested changes part 1 * try mac os build check * Revert "try mac os build check" This reverts commit 46fa8adde4f825c3a7f2a8bea7f543ad55a79765. * update debug message label --- .gitignore | 3 +- xpcPlugin/Message.cpp | 2 +- xpcPlugin/MessageHandlers.cpp | 116 ++++++++++++++++-- xpcPlugin/MessageHandlers.h | 1 + xpcPlugin/xpcPlugin.xcodeproj/project.pbxproj | 8 ++ 5 files changed, 116 insertions(+), 14 deletions(-) diff --git a/.gitignore b/.gitignore index d77d8313..8c184fe9 100644 --- a/.gitignore +++ b/.gitignore @@ -92,4 +92,5 @@ out/ # Internal Docs # ################# -Docs/~$Capability Matrix.xlsx \ No newline at end of file +Docs/~$Capability Matrix.xlsx +*.xpl diff --git a/xpcPlugin/Message.cpp b/xpcPlugin/Message.cpp index eb28fe40..c1eb4483 100644 --- a/xpcPlugin/Message.cpp +++ b/xpcPlugin/Message.cpp @@ -121,7 +121,7 @@ namespace XPC } Log::WriteLine(LOG_DEBUG, "DBUG", ss.str()); } - else if (head == "GETC" || head == "GETP") + else if (head == "GETC" || head == "GETP" || head == "GETT") { ss << " Aircraft:" << (int)buffer[5]; Log::WriteLine(LOG_DEBUG, "DBUG", ss.str()); diff --git a/xpcPlugin/MessageHandlers.cpp b/xpcPlugin/MessageHandlers.cpp index dc386fd5..c6e70539 100644 --- a/xpcPlugin/MessageHandlers.cpp +++ b/xpcPlugin/MessageHandlers.cpp @@ -8,21 +8,21 @@ // 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. +// * 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 "XPLMScenery.h" #include "XPLMGraphics.h" - #include #include #include @@ -41,6 +41,9 @@ namespace XPC UDPSocket* MessageHandlers::sock; static sockaddr multicast_address = UDPSocket::GetAddr(MULTICAST_GROUP, MULITCAST_PORT); + + // define a static terrain probe handler (do not re-create probe for each query) + XPLMProbeRef Terrain_probe = nullptr; void MessageHandlers::SetSocket(UDPSocket* socket) { @@ -66,6 +69,7 @@ namespace XPC handlers.insert(std::make_pair("VIEW", MessageHandlers::HandleView)); handlers.insert(std::make_pair("GETC", MessageHandlers::HandleGetC)); handlers.insert(std::make_pair("GETP", MessageHandlers::HandleGetP)); + handlers.insert(std::make_pair("GETT", MessageHandlers::HandleGetT)); // X-Plane data messages handlers.insert(std::make_pair("DSEL", MessageHandlers::HandleXPlaneData)); handlers.insert(std::make_pair("USEL", MessageHandlers::HandleXPlaneData)); @@ -626,6 +630,94 @@ namespace XPC } } } + + void MessageHandlers::HandleGetT(const Message& msg) + { + const unsigned char* buffer = msg.GetBuffer(); + std::size_t size = msg.GetSize(); + if (size != 30) + { + Log::FormatLine(LOG_ERROR, "GETT", "Unexpected message length: %u", size); + return; + } + unsigned char aircraft = buffer[5]; + Log::FormatLine(LOG_TRACE, "GETT", "Getting terrain information for aircraft %u", aircraft); + + double loc[3]; + double X; + double Y; + double Z; + memcpy(loc, buffer + 6, 24); + + if(loc[0] == -998 || loc[1] == -998 || loc[2] == -998) + { + // get terrain properties at aircraft location + // probe needs to be below terrain to work... + X = DataManager::GetDouble(DREF_LocalX, aircraft); + Z = DataManager::GetDouble(DREF_LocalZ, aircraft); + Y = -100.0; + } + else + { + // terrain probe at specified location + XPLMWorldToLocal(loc[0], loc[1], loc[2], &X, &Y, &Z); + } + + // Init terrain probe (if required) and probe data struct + XPLMProbeInfo_t probe_data; + probe_data.structSize = sizeof(XPLMProbeInfo_t); + + if(Terrain_probe == nullptr) + { + Log::FormatLine(LOG_TRACE, "GETT", "Create terrain probe for aircraft %u", aircraft); + Terrain_probe = XPLMCreateProbe(0); + } + + // query probe + int rc = XPLMProbeTerrainXYZ(Terrain_probe, X, Y, Z, &probe_data); + + // transform probe location to world coordinates + double lat; + double lon; + double alt; + + if(rc == 0) + { + XPLMLocalToWorld(probe_data.locationX, probe_data.locationY, probe_data.locationZ, &lat, &lon, &alt); + + Log::FormatLine(LOG_TRACE, "GETT", "Probe LLA %lf %lf %lf", lat, lon, alt); + } + else + { + lat = -998; + lon = -998; + alt = -998; + + Log::FormatLine(LOG_TRACE, "GETT", "Probe failed. Return Value %u", rc); + } + + // keep probe for next query + // XPLMDestroyProbe(probe); + + // Assemble response message + unsigned char response[50] = "TERR"; + response[5] = aircraft; + // terrain height over msl at lat/lon point + memcpy(response + 6, &lat, 8); + memcpy(response + 14, &lon, 8); + memcpy(response + 22, &alt, 8); + // terrain incidence + memcpy(response + 30, &probe_data.normalX, 4); + memcpy(response + 34, &probe_data.normalY, 4); + memcpy(response + 38, &probe_data.normalZ, 4); + // terrain type + memcpy(response + 42, &probe_data.is_wet, 4); + // probe status + memcpy(response + 46, &rc, 4); + + sock->SendTo(response, 50, &connection.addr); + } + void MessageHandlers::HandleSimu(const Message& msg) { @@ -798,7 +890,7 @@ namespace XPC double dy = y - cY; double dz = z - cZ; -// Log::FormatLine(LOG_TRACE, "CAM", "Cam vect %f %f %f", dx, dy, dz); +// Log::FormatLine(LOG_TRACE, "CAM", "Cam vect %f %f %f", dx, dy, dz); double pi = 3.141592653589793; @@ -811,15 +903,15 @@ namespace XPC outCameraPosition->heading = 90 + angle; // rel to north -// Log::FormatLine(LOG_TRACE, "CAM", "Cam p %f hdg %f ", outCameraPosition->pitch, outCameraPosition->heading); +// Log::FormatLine(LOG_TRACE, "CAM", "Cam p %f hdg %f ", outCameraPosition->pitch, outCameraPosition->heading); outCameraPosition->roll = 0; } else { - outCameraPosition->roll = campos->direction[0]; - outCameraPosition->pitch = campos->direction[1]; - outCameraPosition->heading = campos->direction[2]; + outCameraPosition->roll = campos->direction[0]; + outCameraPosition->pitch = campos->direction[1]; + outCameraPosition->heading = campos->direction[2]; } outCameraPosition->zoom = campos->zoom; diff --git a/xpcPlugin/MessageHandlers.h b/xpcPlugin/MessageHandlers.h index a065c966..8753d006 100644 --- a/xpcPlugin/MessageHandlers.h +++ b/xpcPlugin/MessageHandlers.h @@ -56,6 +56,7 @@ namespace XPC static void HandleText(const Message& msg); static void HandleWypt(const Message& msg); static void HandleView(const Message& msg); + static void HandleGetT(const Message& msg); static void HandleXPlaneData(const Message& msg); static void HandleUnknown(const Message& msg); diff --git a/xpcPlugin/xpcPlugin.xcodeproj/project.pbxproj b/xpcPlugin/xpcPlugin.xcodeproj/project.pbxproj index 4a4fe23c..a8889115 100755 --- a/xpcPlugin/xpcPlugin.xcodeproj/project.pbxproj +++ b/xpcPlugin/xpcPlugin.xcodeproj/project.pbxproj @@ -230,6 +230,10 @@ MACH_O_TYPE = mh_bundle; MACOSX_DEPLOYMENT_TARGET = 10.7; ONLY_ACTIVE_ARCH = YES; + OTHER_CPLUSPLUSFLAGS = ( + "$(OTHER_CFLAGS)", + "-DXPLM200", + ); OTHER_LDFLAGS = ( "$(OTHER_LDFLAGS)", "-Wl,-exported_symbol", @@ -278,6 +282,10 @@ ); MACH_O_TYPE = mh_bundle; MACOSX_DEPLOYMENT_TARGET = 10.7; + OTHER_CPLUSPLUSFLAGS = ( + "$(OTHER_CFLAGS)", + "-DXPLM200", + ); OTHER_LDFLAGS = ( "$(OTHER_LDFLAGS)", "-Wl,-exported_symbol", From c0abcf729f550eab59f25fca71dff68120cf03b8 Mon Sep 17 00:00:00 2001 From: Kai Lehmkuehler Date: Fri, 15 Nov 2019 16:02:54 +0100 Subject: [PATCH 05/50] Configurable Chase Camera (#188) * ignore binaries * Add terrain probe * update camera system * change to tabs * formatting * compiles on windows 10 * use local view type enum * basic view type must always be changed * Code formatting --- xpcPlugin/CameraCallbacks.cpp | 173 +++++++ xpcPlugin/MessageHandlers.cpp | 137 ++---- xpcPlugin/MessageHandlers.h | 20 +- xpcPlugin/xpcPlugin.xcodeproj/project.pbxproj | 6 +- xpcPlugin/xpcPlugin/xpcPlugin.vcxproj | 463 +++++++++--------- xpcPlugin/xpcPlugin/xpcPlugin.vcxproj.filters | 155 +++--- 6 files changed, 557 insertions(+), 397 deletions(-) create mode 100644 xpcPlugin/CameraCallbacks.cpp diff --git a/xpcPlugin/CameraCallbacks.cpp b/xpcPlugin/CameraCallbacks.cpp new file mode 100644 index 00000000..bb839b2b --- /dev/null +++ b/xpcPlugin/CameraCallbacks.cpp @@ -0,0 +1,173 @@ +// +// support.cpp +// xpcPlugin +// +// Created by Kai Lehmkuehler on 14/01/2019. +// + +#include + +#include "MessageHandlers.h" +#include "DataManager.h" +#include "Log.h" + +#include "XPLMUtilities.h" +#include "XPLMGraphics.h" + + +#include +#include + +namespace XPC +{ + // Runway Camera Callback: Places the camera at campos.loc and points it at the aircraft, similar to a remote piloting experience. + // Optionally, the direction of the camera can be specified by the user. + int MessageHandlers::CamCallback_RunwayCam( XPLMCameraPosition_t * outCameraPosition, int inIsLosingControl, void *inRefcon) + { + if (outCameraPosition && !inIsLosingControl) + { + struct CameraProperties* campos = (struct CameraProperties*)inRefcon; + + // camera position + double clat = campos->loc[0]; + double clon = campos->loc[1]; + double calt = campos->loc[2]; + + double cX; + double cY; + double cZ; + XPLMWorldToLocal(clat, clon, calt, &cX, &cY, &cZ); + + outCameraPosition->x = cX; + outCameraPosition->y = cY; + outCameraPosition->z = cZ; + + // Log::FormatLine(LOG_TRACE, "CAM", "Cam pos %f %f %f", clat, clon, calt); + + // calculate camera direction to point at the aircraft + if(campos->direction[0] < -180) + { + // local aircraft position + double x = XPC::DataManager::GetDouble(XPC::DREF_LocalX, 0); + double y = XPC::DataManager::GetDouble(XPC::DREF_LocalY, 0); + double z = XPC::DataManager::GetDouble(XPC::DREF_LocalZ, 0); + + // relative position vector camera to aircraft + double dx = x - cX; + double dy = y - cY; + double dz = z - cZ; + + // Log::FormatLine(LOG_TRACE, "CAM", "Cam vect %f %f %f", dx, dy, dz); + + double pi = 3.141592653589793; + + // horizontal distance + double dist = sqrt(dx*dx + dz*dz); + + outCameraPosition->pitch = atan2(dy, dist) * 180.0/pi; + + double angle = atan2(dz, dx) * 180.0/pi; // rel to pos right (pos X) + + outCameraPosition->heading = 90 + angle; // rel to north + + // Log::FormatLine(LOG_TRACE, "CAM", "Cam p %f hdg %f ", outCameraPosition->pitch, outCameraPosition->heading); + + outCameraPosition->roll = 0; + } + // point camera at specified direction + else + { + outCameraPosition->roll = campos->direction[0]; + outCameraPosition->pitch = campos->direction[1]; + outCameraPosition->heading = campos->direction[2]; + } + + outCameraPosition->zoom = campos->zoom; + } + + return 1; + } + + // Chase Camera Callback: Places the camera at campos.loc RELATIVE to and MOVING with the aircraft, pointing at the specified + // direction. + int MessageHandlers::CamCallback_ChaseCam( XPLMCameraPosition_t * outCameraPosition, int inIsLosingControl, void *inRefcon) + { + if (outCameraPosition && !inIsLosingControl) + { + double DTR = 3.141592653589793 / 180.0; + + struct CameraProperties* campos = (struct CameraProperties*)inRefcon; + + // Camera location relative to aircraft (local axes) + + // local aircraft position + double x = XPC::DataManager::GetDouble(XPC::DREF_LocalX, 0); // +east + double y = XPC::DataManager::GetDouble(XPC::DREF_LocalY, 0); // +up + double z = XPC::DataManager::GetDouble(XPC::DREF_LocalZ, 0); // +south + + // aircraft attitude - degrees + double phi = XPC::DataManager::GetFloat(XPC::DREF_Roll, 0); + double the = XPC::DataManager::GetFloat(XPC::DREF_Pitch, 0); + double psi = XPC::DataManager::GetFloat(XPC::DREF_HeadingTrue, 0); + + // camera position vector with respect to aircraft CG [m] (body axes) + double c_x = campos->loc[0]; // back + double c_y = campos->loc[1]; // right + double c_z = campos->loc[2]; // up + + // camera position vector in local axes - will move with aircraft if not along principal axes + // cLocal = Leb * cBody + // http://www.xsquawkbox.net/xpsdk/mediawiki/ScreenCoordinates + + double x_phi=c_y*cos(phi*DTR) + c_z*sin(phi*DTR); + double y_phi=c_z*cos(phi*DTR) - c_y*sin(phi*DTR); + double z_phi=c_x; + + double x_the=x_phi; + double y_the=y_phi*cos(the*DTR) - z_phi*sin(the*DTR); + double z_the=z_phi*cos(the*DTR) + y_phi*sin(the*DTR); + + double x_wrl=x_the*cos(psi*DTR) - z_the*sin(psi*DTR); + double y_wrl=y_the ; + double z_wrl=z_the*cos(psi*DTR) + x_the*sin(psi*DTR); + + outCameraPosition->x = x + x_wrl; + outCameraPosition->y = y + y_wrl; + outCameraPosition->z = z + z_wrl; + + // set direction value to -998 to keep camera pointing straight along that axis + if(campos->direction[0] < -180) + { + outCameraPosition->roll = 0; + } + else + { + outCameraPosition->roll = phi + campos->direction[0]; + } + + if(campos->direction[1] < -180) + { + outCameraPosition->pitch = 0; + } + else + { + outCameraPosition->pitch = the + campos->direction[1]; + } + + if(campos->direction[2] < -180) + { + outCameraPosition->heading = 0; + } + else + { + outCameraPosition->heading = psi + campos->direction[2]; + } + + outCameraPosition->zoom = campos->zoom; + } + + return 1; + + } + +} diff --git a/xpcPlugin/MessageHandlers.cpp b/xpcPlugin/MessageHandlers.cpp index c6e70539..2556feff 100644 --- a/xpcPlugin/MessageHandlers.cpp +++ b/xpcPlugin/MessageHandlers.cpp @@ -14,6 +14,7 @@ // 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" @@ -23,6 +24,7 @@ #include "XPLMScenery.h" #include "XPLMGraphics.h" + #include #include #include @@ -643,10 +645,10 @@ namespace XPC unsigned char aircraft = buffer[5]; Log::FormatLine(LOG_TRACE, "GETT", "Getting terrain information for aircraft %u", aircraft); - double loc[3]; - double X; - double Y; - double Z; + double loc[3]; + double X; + double Y; + double Z; memcpy(loc, buffer + 6, 24); if(loc[0] == -998 || loc[1] == -998 || loc[2] == -998) @@ -677,9 +679,9 @@ namespace XPC int rc = XPLMProbeTerrainXYZ(Terrain_probe, X, Y, Z, &probe_data); // transform probe location to world coordinates - double lat; - double lon; - double alt; + double lat; + double lon; + double alt; if(rc == 0) { @@ -818,106 +820,61 @@ namespace XPC { // Update Log Log::FormatLine(LOG_TRACE, "VIEW", "Message Received(Conn %i)", connection.id); - - int enable_camera_location = 0; - + + bool enable_advanced_camera = false; + const std::size_t size = msg.GetSize(); if (size == 9) { // default view switcher as before } - else if (size == 37) + else if (size == 49) { // Allow camera location control - enable_camera_location = 1; + enable_advanced_camera = true; } else { - Log::FormatLine(LOG_ERROR, "VIEW", "Error: Unexpected length. Message was %d bytes, expected 9 or 37.", size); + Log::FormatLine(LOG_ERROR, "VIEW", "Error: Unexpected length. Message was %d bytes, expected 9 or 49.", size); return; } + + // get msg data const unsigned char* buffer = msg.GetBuffer(); - int type = *((int*)(buffer + 5)); - XPLMCommandKeyStroke(type); - - if(type == 79 && enable_camera_location == 1) // runway camera view + + // get view type + int view_type; + memcpy(&view_type, buffer + 5, 4); + + // set view by calling the corresponding key stroke + XPLMCommandKeyStroke(view_type); + + + VIEW_TYPE viewRunway = VIEW_TYPE::XPC_VIEW_RUNWAY; + VIEW_TYPE viewChase = VIEW_TYPE::XPC_VIEW_CHASE; + + // advanced runway camera view + if(view_type == static_cast(viewRunway) && enable_advanced_camera == true) { - static struct CameraProperties campos; - - campos.loc[0] = *(double*)(buffer+9); - campos.loc[1] = *(double*)(buffer+17); - campos.loc[2] = *(double*)(buffer+25); - campos.direction[0] = -998; - campos.direction[1] = -998; - campos.direction[2] = -998; - campos.zoom = *(float*)(buffer+33); - - Log::FormatLine(LOG_TRACE, "VIEW", "Cam pos %f %f %f zoom %f", campos.loc[0], campos.loc[1], campos.loc[2],campos.zoom); - - XPLMControlCamera(xplm_ControlCameraUntilViewChanges, CamFunc, &campos); + static struct CameraProperties campos; // static variable for continuous callback access + + memcpy(&campos, buffer+9 , sizeof(struct CameraProperties)); + + Log::FormatLine(LOG_TRACE, "VIEW", "Cam pos %f %f %f zoom %f", campos.loc[0], campos.loc[1], campos.loc[2], campos.zoom); + + XPLMControlCamera(xplm_ControlCameraUntilViewChanges, CamCallback_RunwayCam, &campos); } - } - - int MessageHandlers::CamFunc( XPLMCameraPosition_t * outCameraPosition, int inIsLosingControl, void *inRefcon) - { - if (outCameraPosition && !inIsLosingControl) + // advanced chase camera view + else if(view_type == static_cast(viewChase) && enable_advanced_camera == true) { - struct CameraProperties* campos = (struct CameraProperties*)inRefcon; - - // camera position - double clat = campos->loc[0]; - double clon = campos->loc[1]; - double calt = campos->loc[2]; - - double cX, cY, cZ; - XPLMWorldToLocal(clat, clon, calt, &cX, &cY, &cZ); - - outCameraPosition->x = cX; - outCameraPosition->y = cY; - outCameraPosition->z = cZ; - -// Log::FormatLine(LOG_TRACE, "CAM", "Cam pos %f %f %f", clat, clon, calt); - - if(campos->direction[0] == -998) // calculate camera direction - { - // aircraft position - double x = XPC::DataManager::GetDouble(XPC::DREF_LocalX, 0); - double y = XPC::DataManager::GetDouble(XPC::DREF_LocalY, 0); - double z = XPC::DataManager::GetDouble(XPC::DREF_LocalZ, 0); - - // relative position vector cam to plane - double dx = x - cX; - double dy = y - cY; - double dz = z - cZ; - -// Log::FormatLine(LOG_TRACE, "CAM", "Cam vect %f %f %f", dx, dy, dz); - - double pi = 3.141592653589793; - - // horizontal distance - double dist = sqrt(dx*dx + dz*dz); - - outCameraPosition->pitch = atan2(dy, dist) * 180.0/pi; - - double angle = atan2(dz, dx) * 180.0/pi; // rel to pos right (pos X) - - outCameraPosition->heading = 90 + angle; // rel to north - -// Log::FormatLine(LOG_TRACE, "CAM", "Cam p %f hdg %f ", outCameraPosition->pitch, outCameraPosition->heading); - - outCameraPosition->roll = 0; - } - else - { - outCameraPosition->roll = campos->direction[0]; - outCameraPosition->pitch = campos->direction[1]; - outCameraPosition->heading = campos->direction[2]; - } - - outCameraPosition->zoom = campos->zoom; + static struct CameraProperties campos; // static variable for continuous callback access + + memcpy(&campos, buffer+9 , sizeof(struct CameraProperties)); + + Log::FormatLine(LOG_TRACE, "VIEW", "Cam pos %f %f %f zoom %f", campos.loc[0], campos.loc[1], campos.loc[2], campos.zoom); + + XPLMControlCamera(xplm_ControlCameraUntilViewChanges, CamCallback_ChaseCam, &campos); } - - return 1; } void MessageHandlers::HandleWypt(const Message& msg) diff --git a/xpcPlugin/MessageHandlers.h b/xpcPlugin/MessageHandlers.h index 8753d006..096a4b6d 100644 --- a/xpcPlugin/MessageHandlers.h +++ b/xpcPlugin/MessageHandlers.h @@ -14,6 +14,23 @@ namespace XPC { /// A function that handles a message. typedef void(*MessageHandler)(const Message&); + + enum class VIEW_TYPE + { + 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, + }; /// Handles incoming messages and manages connections. /// @@ -61,7 +78,8 @@ namespace XPC static void HandleXPlaneData(const Message& msg); static void HandleUnknown(const Message& msg); - static int CamFunc( XPLMCameraPosition_t * outCameraPosition, int inIsLosingControl, void *inRefcon); + static int CamCallback_RunwayCam( XPLMCameraPosition_t * outCameraPosition, int inIsLosingControl, void *inRefcon); + static int CamCallback_ChaseCam( XPLMCameraPosition_t * outCameraPosition, int inIsLosingControl, void *inRefcon); struct CameraProperties{ double loc[3]; diff --git a/xpcPlugin/xpcPlugin.xcodeproj/project.pbxproj b/xpcPlugin/xpcPlugin.xcodeproj/project.pbxproj index a8889115..9112e869 100755 --- a/xpcPlugin/xpcPlugin.xcodeproj/project.pbxproj +++ b/xpcPlugin/xpcPlugin.xcodeproj/project.pbxproj @@ -8,6 +8,7 @@ /* Begin PBXBuildFile section */ 3D0F44CE21C6D3E7008A0655 /* Timer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D0F44CD21C6D3E7008A0655 /* Timer.cpp */; }; + 5B36040D23731E4A003ACE12 /* CameraCallbacks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5B36040C23731E4A003ACE12 /* CameraCallbacks.cpp */; }; 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 */; }; @@ -39,6 +40,7 @@ /* Begin PBXFileReference section */ 3D0F44CC21C6D3E7008A0655 /* Timer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Timer.h; sourceTree = ""; }; 3D0F44CD21C6D3E7008A0655 /* Timer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Timer.cpp; sourceTree = ""; }; + 5B36040C23731E4A003ACE12 /* CameraCallbacks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CameraCallbacks.cpp; sourceTree = ""; }; 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 = ""; }; BEABAD2C1AE041A3007BA7DA /* DataManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DataManager.h; sourceTree = ""; }; @@ -53,7 +55,6 @@ BEABAD3D1AE0498D007BA7DA /* UDPSocket.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UDPSocket.cpp; sourceTree = ""; }; BEABAD3E1AE0498D007BA7DA /* UDPSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UDPSocket.h; sourceTree = ""; }; BEDC620218EDF1A7005DB364 /* xplaneConnect.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = xplaneConnect.c; path = ../C/src/xplaneConnect.c; sourceTree = ""; }; - BEDC620318EDF1A7005DB364 /* xplaneConnect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = xplaneConnect.h; path = ../C/src/xplaneConnect.h; sourceTree = ""; }; D607B19909A556E400699BC3 /* mac.xpl */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = mac.xpl; sourceTree = BUILT_PRODUCTS_DIR; }; D6A7BDA916A1DEA200D1426A /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; D6A7BDC016A1DEC000D1426A /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; @@ -79,6 +80,7 @@ AC4E46B809C2E0B3006B7E1B /* src */ = { isa = PBXGroup; children = ( + 5B36040C23731E4A003ACE12 /* CameraCallbacks.cpp */, 3D0F44CD21C6D3E7008A0655 /* Timer.cpp */, BE37D95E187C8B0F0033B082 /* XPCPlugin.cpp */, BEDC620218EDF1A7005DB364 /* xplaneConnect.c */, @@ -96,7 +98,6 @@ isa = PBXGroup; children = ( 3D0F44CC21C6D3E7008A0655 /* Timer.h */, - BEDC620318EDF1A7005DB364 /* xplaneConnect.h */, BEABAD2C1AE041A3007BA7DA /* DataManager.h */, BEABAD301AE041A3007BA7DA /* Drawing.h */, BEABAD321AE041A3007BA7DA /* Log.h */, @@ -191,6 +192,7 @@ files = ( BEABAD3A1AE041A3007BA7DA /* Log.cpp in Sources */, BEABAD3B1AE041A3007BA7DA /* Message.cpp in Sources */, + 5B36040D23731E4A003ACE12 /* CameraCallbacks.cpp in Sources */, BEABAD3C1AE041A3007BA7DA /* MessageHandlers.cpp in Sources */, BEDC620418EDF1A7005DB364 /* xplaneConnect.c in Sources */, BEABAD371AE041A3007BA7DA /* DataManager.cpp in Sources */, diff --git a/xpcPlugin/xpcPlugin/xpcPlugin.vcxproj b/xpcPlugin/xpcPlugin/xpcPlugin.vcxproj index 2c2c85b7..a8de464e 100644 --- a/xpcPlugin/xpcPlugin/xpcPlugin.vcxproj +++ b/xpcPlugin/xpcPlugin/xpcPlugin.vcxproj @@ -1,231 +1,232 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {6AEF5D28-2701-44FF-AE10-1DEF07C5CAEA} - Win32Proj - xpcPlugin - 8.1 - - - - DynamicLibrary - true - $(DefaultPlatformToolset) - MultiByte - - - DynamicLibrary - true - $(DefaultPlatformToolset) - MultiByte - - - DynamicLibrary - true - $(DefaultPlatformToolset) - MultiByte - - - DynamicLibrary - true - $(DefaultPlatformToolset) - MultiByte - - - - - - - - - - - - - - - - - - - true - ..\XPlaneConnect\ - .xpl - ..\SDK\CHeaders\XPLM;$(IncludePath) - ..\xpcPlugin\SDK\Libraries\Win;$(LibraryPath) - win - - - true - ..\XPlaneConnect\ - .xpl - ..\SDK\CHeaders\XPLM;$(IncludePath) - ..\xpcPlugin\SDK\Libraries\Win;$(LibraryPath) - win - - - .xpl - ..\xpcPlugin\SDK\CHeaders\XPLM;..\SDK\CHeaders\XPLM;..\..\C\src;$(IncludePath) - ..\xpcPlugin\SDK\Libraries\Win;$(LibraryPath) - win - true - ..\XPlaneConnect\64\ - - - .xpl - ..\xpcPlugin\SDK\CHeaders\XPLM;..\SDK\CHeaders\XPLM;..\..\C\src;$(IncludePath) - ..\xpcPlugin\SDK\Libraries\Win;$(LibraryPath) - win - true - ..\XPlaneConnect\64\ - - - - NotUsing - Level3 - Disabled - IBM=1;XPLM200;_DEBUG;_WINDOWS;_USRDLL;XPCPLUGIN_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - OldStyle - true - - false - - - false - MultiThreadedDebug - - - Windows - true - Opengl32.lib;%(AdditionalDependencies) - - - - - NotUsing - Level3 - Full - IBM=1;XPLM200;%(PreprocessorDefinitions) - OldStyle - true - - - false - - - false - MultiThreaded - Default - true - false - - - Windows - false - Opengl32.lib;%(AdditionalDependencies) - UseLinkTimeCodeGeneration - true - - - - - NotUsing - Level3 - Disabled - IBM=1;XPLM200;_DEBUG;_WINDOWS;_USRDLL;XPCPLUGIN_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - - - OldStyle - true - - - false - 4996 - false - MultiThreadedDebug - - - Windows - true - OpenGL32.lib;%(AdditionalDependencies) - - - - - NotUsing - Level3 - Full - IBM=1;XPLM200;%(PreprocessorDefinitions) - - - OldStyle - true - - - false - - - false - MultiThreaded - Default - true - - false - - - Windows - false - OpenGL32.lib;%(AdditionalDependencies) - UseLinkTimeCodeGeneration - - - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {6AEF5D28-2701-44FF-AE10-1DEF07C5CAEA} + Win32Proj + xpcPlugin + 10.0.17134.0 + + + + DynamicLibrary + true + $(DefaultPlatformToolset) + MultiByte + + + DynamicLibrary + true + $(DefaultPlatformToolset) + MultiByte + + + DynamicLibrary + true + $(DefaultPlatformToolset) + MultiByte + + + DynamicLibrary + true + $(DefaultPlatformToolset) + MultiByte + + + + + + + + + + + + + + + + + + + true + ..\XPlaneConnect\ + .xpl + ..\SDK\CHeaders\XPLM;$(IncludePath) + ..\xpcPlugin\SDK\Libraries\Win;$(LibraryPath) + win + + + true + ..\XPlaneConnect\ + .xpl + ..\SDK\CHeaders\XPLM;$(IncludePath) + ..\xpcPlugin\SDK\Libraries\Win;$(LibraryPath) + win + + + .xpl + ..\xpcPlugin\SDK\CHeaders\XPLM;..\SDK\CHeaders\XPLM;..\..\C\src;$(IncludePath) + ..\xpcPlugin\SDK\Libraries\Win;$(LibraryPath) + win + true + ..\XPlaneConnect\64\ + + + .xpl + ..\xpcPlugin\SDK\CHeaders\XPLM;..\SDK\CHeaders\XPLM;..\..\C\src;$(IncludePath) + ..\xpcPlugin\SDK\Libraries\Win;$(LibraryPath) + win + true + ..\XPlaneConnect\64\ + + + + NotUsing + Level3 + Disabled + IBM=1;XPLM200;_DEBUG;_WINDOWS;_USRDLL;XPCPLUGIN_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + OldStyle + true + + false + + + false + MultiThreadedDebug + + + Windows + true + Opengl32.lib;%(AdditionalDependencies) + + + + + NotUsing + Level3 + Full + IBM=1;XPLM200;%(PreprocessorDefinitions) + OldStyle + true + + + false + + + false + MultiThreaded + Default + true + false + + + Windows + false + Opengl32.lib;%(AdditionalDependencies) + UseLinkTimeCodeGeneration + true + + + + + NotUsing + Level3 + Disabled + IBM=1;XPLM200;_DEBUG;_WINDOWS;_USRDLL;XPCPLUGIN_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + OldStyle + true + + + false + 4996 + false + MultiThreadedDebug + + + Windows + true + OpenGL32.lib;%(AdditionalDependencies) + + + + + NotUsing + Level3 + Full + IBM=1;XPLM200;%(PreprocessorDefinitions) + + + OldStyle + true + + + false + + + false + MultiThreaded + Default + true + + false + + + Windows + false + OpenGL32.lib;%(AdditionalDependencies) + UseLinkTimeCodeGeneration + + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/xpcPlugin/xpcPlugin/xpcPlugin.vcxproj.filters b/xpcPlugin/xpcPlugin/xpcPlugin.vcxproj.filters index e62f3d6d..5b9a6312 100644 --- a/xpcPlugin/xpcPlugin/xpcPlugin.vcxproj.filters +++ b/xpcPlugin/xpcPlugin/xpcPlugin.vcxproj.filters @@ -1,74 +1,83 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + \ No newline at end of file From 5d31544476efaf950709f45b747a0b26117ddff1 Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sat, 18 Apr 2020 11:30:36 -0700 Subject: [PATCH 06/50] Changed Lat/Lon/h to double in GetP --- xpcPlugin/MessageHandlers.cpp | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/xpcPlugin/MessageHandlers.cpp b/xpcPlugin/MessageHandlers.cpp index 2556feff..5163edc4 100644 --- a/xpcPlugin/MessageHandlers.cpp +++ b/xpcPlugin/MessageHandlers.cpp @@ -24,7 +24,6 @@ #include "XPLMScenery.h" #include "XPLMGraphics.h" - #include #include #include @@ -32,7 +31,6 @@ #define MULTICAST_GROUP "239.255.1.1" #define MULITCAST_PORT 49710 - namespace XPC { std::map MessageHandlers::connections; @@ -560,21 +558,20 @@ namespace XPC unsigned char aircraft = buffer[5]; Log::FormatLine(LOG_TRACE, "GPOS", "Getting position information for aircraft %u", aircraft); - unsigned char response[34] = "POSI"; + unsigned char response[46] = "POSI"; response[5] = (char)DataManager::GetInt(DREF_GearHandle, aircraft); - // TODO change lat/lon/h to double? - *((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); + *((double*)(response + 6)) = DataManager::GetDouble(DREF_Latitude, aircraft); + *((double*)(response + 14)) = DataManager::GetDouble(DREF_Longitude, aircraft); + *((double*)(response + 22)) = DataManager::GetDouble(DREF_Elevation, aircraft); + *((float*)(response + 30)) = DataManager::GetFloat(DREF_Pitch, aircraft); + *((float*)(response + 34)) = DataManager::GetFloat(DREF_Roll, aircraft); + *((float*)(response + 38)) = DataManager::GetFloat(DREF_HeadingTrue, aircraft); float gear[10]; DataManager::GetFloatArray(DREF_GearDeploy, gear, 10, aircraft); - *((float*)(response + 30)) = gear[0]; + *((float*)(response + 42)) = gear[0]; - sock->SendTo(response, 34, &connection.addr); + sock->SendTo(response, 46, &connection.addr); } void MessageHandlers::HandlePosi(const Message& msg) @@ -594,6 +591,7 @@ namespace XPC { float posd_32[3]; memcpy(posd_32, buffer + 6, 12); + /* convert float to double */ posd[0] = posd_32[0]; posd[1] = posd_32[1]; posd[2] = posd_32[2]; @@ -612,7 +610,6 @@ namespace XPC return; } - /* convert float to double */ DataManager::SetPosition(posd, aircraftNumber); DataManager::SetOrientation(orient, aircraftNumber); if (gear >= 0) @@ -632,7 +629,7 @@ namespace XPC } } } - + void MessageHandlers::HandleGetT(const Message& msg) { const unsigned char* buffer = msg.GetBuffer(); From 113d664bfe6ebc3197534d42485a5566ee332761 Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sat, 18 Apr 2020 11:48:17 -0700 Subject: [PATCH 07/50] Changed getPOSI to double values --- C/src/xplaneConnect.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/C/src/xplaneConnect.h b/C/src/xplaneConnect.h index 8cfb06fc..4a62b17c 100644 --- a/C/src/xplaneConnect.h +++ b/C/src/xplaneConnect.h @@ -201,8 +201,9 @@ int getDREFs(XPCSocket sock, const char* drefs[], float* values[], unsigned char /// \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] +/// \param ac The aircraft number to get the position of. 0 for the main/user's aircraft. /// \returns 0 if successful, otherwise a negative value. -int getPOSI(XPCSocket sock, float values[7], char ac); +int getPOSI(XPCSocket sock, double values[7], char ac); /// Sets the position and orientation of the specified aircraft. /// @@ -211,7 +212,7 @@ int getPOSI(XPCSocket sock, float values[7], char ac); /// [Lat, Lon, Alt, Pitch, Roll, Yaw, Gear]. If less than 7 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 position of. 0 for the player aircraft. +/// \param ac The aircraft number to set the position of. 0 for the main/user's aircraft. /// \returns 0 if successful, otherwise a negative value. int sendPOSI(XPCSocket sock, double values[], int size, char ac); @@ -223,7 +224,7 @@ int sendPOSI(XPCSocket sock, double values[], int size, char ac); /// \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. +/// \param ac The aircraft to set the control surfaces of. 0 is the main/user's aircraft. /// \returns 0 if successful, otherwise a negative value. int getCTRL(XPCSocket sock, float values[7], char ac); @@ -234,7 +235,7 @@ int getCTRL(XPCSocket sock, float values[7], char ac); /// [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. +/// \param ac The aircraft to set the control surfaces of. 0 for the main/user's aircraft. /// \returns 0 if successful, otherwise a negative value. int sendCTRL(XPCSocket sock, float values[], int size, char ac); @@ -246,7 +247,7 @@ int sendCTRL(XPCSocket sock, float values[], int size, char ac); /// \param msg The message to print of the screen. /// \param x The distance in pixels from the left edge of the screen to print the text. /// \param y The distance in pixels from the bottom edge of the screen to print the top line of text. -/// \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); /// Sets the camera view in X-Plane. From 915e0591acf19f900bba26616d75bf92026a7078 Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sat, 18 Apr 2020 12:44:19 -0700 Subject: [PATCH 08/50] Changed getPOSI to double values Also fixed compiler warnings due to unsigned char for buffers. Changed to char. --- C/src/xplaneConnect.c | 51 +++++++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/C/src/xplaneConnect.c b/C/src/xplaneConnect.c index ed984fbd..9425c946 100755 --- a/C/src/xplaneConnect.c +++ b/C/src/xplaneConnect.c @@ -387,7 +387,7 @@ int sendDREFs(XPCSocket sock, const char* drefs[], float* values[], int sizes[], { // Setup command // Max size is technically unlimited. - unsigned char buffer[65536] = "DREF"; + char buffer[65536] = "DREF"; int pos = 5; int i; // Iterator for (i = 0; i < count; ++i) @@ -433,7 +433,7 @@ int sendDREFRequest(XPCSocket sock, const char* drefs[], unsigned char count) // Setup command // 6 byte header + potentially 255 drefs, each 256 chars long. // Easiest to just round to an even 2^16. - unsigned char buffer[65536] = "GETD"; + char buffer[65536] = "GETD"; buffer[5] = count; int len = 6; int i; // iterator @@ -460,7 +460,7 @@ int sendDREFRequest(XPCSocket sock, const char* drefs[], unsigned char count) int getDREFResponse(XPCSocket sock, float* values[], unsigned char count, int sizes[]) { - unsigned char buffer[65536]; + char buffer[65536]; int result = readUDP(sock, buffer, 65536); if (result < 0) @@ -537,10 +537,10 @@ int getDREFs(XPCSocket sock, const char* drefs[], float* values[], unsigned char /*****************************************************************************/ /**** POSI functions ****/ /*****************************************************************************/ -int getPOSI(XPCSocket sock, float values[7], char ac) +int getPOSI(XPCSocket sock, double values[7], char ac) { // Setup send command - unsigned char buffer[6] = "GETP"; + char buffer[6] = "GETP"; buffer[5] = ac; // Send command @@ -551,22 +551,41 @@ int getPOSI(XPCSocket sock, float values[7], char ac) } // Get response - unsigned char readBuffer[34]; - int readResult = readUDP(sock, readBuffer, 34); + char readBuffer[46]; + float f[7]; + int readResult = readUDP(sock, readBuffer, 46); + + // Copy response into values if (readResult < 0) { printError("getPOSI", "Failed to read response."); return -2; } - if (readResult != 34) + else if (readResult == 34) /* lat/lon/h as 32-bit float */ + { + memcpy(f, readBuffer + 6, 7 * sizeof(float)); + values[0] = (double)f[0]; + values[1] = (double)f[1]; + values[2] = (double)f[2]; + values[3] = (double)f[3]; + values[4] = (double)f[4]; + values[5] = (double)f[5]; + values[6] = (double)f[6]; + } + else if (readResult == 46) /* lat/lon/h as 64-bit double */ + { + memcpy(values, readBuffer + 6, 3 * sizeof(double)); + memcpy(f, readBuffer + 30, 4 * sizeof(float)); + values[3] = (double)f[0]; + values[4] = (double)f[1]; + values[5] = (double)f[2]; + values[6] = (double)f[3]; + } + else { printError("getPOSI", "Unexpected response length."); return -3; } - // TODO: change this to the 64-bit lat/lon/h - - // Copy response into values - memcpy(values, readBuffer + 6, 7 * sizeof(float)); return 0; } @@ -585,7 +604,7 @@ int sendPOSI(XPCSocket sock, double values[], int size, char ac) } // Setup command - unsigned char buffer[46] = "POSI"; + char buffer[46] = "POSI"; buffer[4] = 0xff; //Placeholder for message length buffer[5] = ac; int i; // iterator @@ -627,7 +646,7 @@ int sendPOSI(XPCSocket sock, double values[], int size, char ac) int getCTRL(XPCSocket sock, float values[7], char ac) { // Setup send command - unsigned char buffer[6] = "GETC"; + char buffer[6] = "GETC"; buffer[5] = ac; // Send command @@ -638,7 +657,7 @@ int getCTRL(XPCSocket sock, float values[7], char ac) } // Get response - unsigned char readBuffer[31]; + char readBuffer[31]; int readResult = readUDP(sock, readBuffer, 31); if (readResult < 0) { @@ -675,7 +694,7 @@ int sendCTRL(XPCSocket sock, float values[], int size, char ac) // Setup Command // 5 byte header + 5 float values * 4 + 2 byte values - unsigned char buffer[31] = "CTRL"; + char buffer[31] = "CTRL"; int cur = 5; int i; // iterator for (i = 0; i < 6; i++) From 32bff7ffe47f00edb6f1f765929fda3ec66a4688 Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sat, 18 Apr 2020 12:55:55 -0700 Subject: [PATCH 09/50] Changed getPOSI to double posi Also fixed compiler error for timeval struct tv not defined for WIN32. --- C/monitorExample/main.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/C/monitorExample/main.c b/C/monitorExample/main.c index e6d2e626..e0af2913 100644 --- a/C/monitorExample/main.c +++ b/C/monitorExample/main.c @@ -26,6 +26,8 @@ #include #include "stdio.h" +struct timeval tv; + #ifdef WIN32 HANDLE hStdIn = NULL; INPUT_RECORD buffer; @@ -51,7 +53,6 @@ int waitForInput() #else int fdstdin = 0; fd_set fds; -struct timeval tv; int waitForInput() { @@ -67,10 +68,10 @@ int main(void) { XPCSocket client = openUDP("127.0.0.1"); const int aircraftNum = 0; - tv.tv_usec = 100 * 1000; + tv.tv_usec = 100 * 1000; while (1) { - float posi[7]; // FIXME: change this to the 64-bit lat/lon/h + double posi[7]; int result = getPOSI(client, posi, aircraftNum); if (result < 0) // Error in getPOSI { From 53154e5908a5dabab38c80ae754948291d63270f Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sat, 18 Apr 2020 12:59:49 -0700 Subject: [PATCH 10/50] Changed getPOSI to double posi --- C/playbackExample/src/playback.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/C/playbackExample/src/playback.c b/C/playbackExample/src/playback.c index 4d2e594f..dd92e45d 100644 --- a/C/playbackExample/src/playback.c +++ b/C/playbackExample/src/playback.c @@ -65,7 +65,7 @@ void record(char* path, int interval, int duration) XPCSocket sock = openUDP("127.0.0.1"); for (int i = 0; i < count; ++i) { - float posi[7]; + double posi[7]; int result = getPOSI(sock, posi, 0); playbackSleep(interval); if (result < 0) From 79110a6f9102e408bd3285e20b926841a4854547 Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sat, 18 Apr 2020 15:05:35 -0700 Subject: [PATCH 11/50] getPOSI and sendPOSI fix to handle Lat/Lon/h doubles getPOSI now can interpret either float or double Lat/Lon/h messages. sendPOSI now sends double Lat/Lon/h messages. Also fixed integer conversion bug in sendCTRL. --- Python3/src/xpc.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/Python3/src/xpc.py b/Python3/src/xpc.py index ddf2be98..9c85942e 100644 --- a/Python3/src/xpc.py +++ b/Python3/src/xpc.py @@ -1,7 +1,6 @@ import socket import struct - class XPlaneConnect(object): """XPlaneConnect (XPC) facilitates communication to and from the XPCPlugin.""" socket = None @@ -158,10 +157,13 @@ def getPOSI(self, ac=0): # Read response resultBuf = self.readUDP() - if len(resultBuf) != 34: + if len(resultBuf) == 34: + result = struct.unpack(b"<4sxBfffffff", resultBuf) + elif len(resultBuf) == 46: + result = struct.unpack(b"<4sxBdddffff", resultBuf) + else: raise ValueError("Unexpected response length.") - result = struct.unpack(b"<4sxBfffffff", resultBuf) if result[0] != b"POSI": raise ValueError("Unexpected header: " + result[0]) @@ -197,7 +199,10 @@ def sendPOSI(self, values, ac=0): val = -998 if i < len(values): val = values[i] - buffer += struct.pack(b" Date: Sat, 18 Apr 2020 15:24:54 -0700 Subject: [PATCH 12/50] Python3 Tests created Created a Python3 compatible version of Tests.py --- TestScripts/Python3 Tests/Tests.py | 434 +++++++++++++++++++++++++++++ 1 file changed, 434 insertions(+) create mode 100644 TestScripts/Python3 Tests/Tests.py diff --git a/TestScripts/Python3 Tests/Tests.py b/TestScripts/Python3 Tests/Tests.py new file mode 100644 index 00000000..41e2bd4e --- /dev/null +++ b/TestScripts/Python3 Tests/Tests.py @@ -0,0 +1,434 @@ +import random +import unittest +import importlib +import time + +from importlib.machinery import SourceFileLoader +xpc = SourceFileLoader('xpc', '../../Python3/src/xpc.py').load_module() + +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.encode()) + buf = receiver.readUDP() + + # Cleanup + sender.close() + receiver.close() + + # Tests + for a, b in zip(test, buf.decode()): + 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_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 + 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_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",\ + "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() From 0713a9553939274b3d250bef0f304551c1c037bc Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sat, 18 Apr 2020 15:26:54 -0700 Subject: [PATCH 13/50] Tests.pyproj copied from Python Tests --- TestScripts/Python3 Tests/Tests.pyproj | 45 ++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 TestScripts/Python3 Tests/Tests.pyproj diff --git a/TestScripts/Python3 Tests/Tests.pyproj b/TestScripts/Python3 Tests/Tests.pyproj new file mode 100644 index 00000000..c1626b5c --- /dev/null +++ b/TestScripts/Python3 Tests/Tests.pyproj @@ -0,0 +1,45 @@ + + + + Debug + 2.0 + 6931ebb2-4e01-4c5a-86b6-668c0e75051b + . + Tests.py + ..\..\Python\src\ + . + . + Tests + Tests + {9a7a9026-48c1-4688-9d5d-e5699d47d074} + 2.7 + + + true + false + + + true + false + + + + + + + + + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Python Tools\Microsoft.PythonTools.targets + + + + + + + + + + \ No newline at end of file From 132978b53dbcbbd78010fa7a1ad9863b95001b26 Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sat, 18 Apr 2020 22:19:53 -0700 Subject: [PATCH 14/50] Changed drefs to const char* to fix compiler warnings --- TestScripts/C Tests/CtrlTests.h | 38 ++++++++++++++++----------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/TestScripts/C Tests/CtrlTests.h b/TestScripts/C Tests/CtrlTests.h index 83e7d369..f000f4ee 100644 --- a/TestScripts/C Tests/CtrlTests.h +++ b/TestScripts/C Tests/CtrlTests.h @@ -6,7 +6,7 @@ #include "Test.h" #include "xplaneConnect.h" -int doCTRLTest(XPCSocket *sock, char* drefs[7], float values[], int size, int ac, float expected[7]) +int doCTRLTest(XPCSocket *sock, const char* drefs[7], float values[], int size, int ac, float expected[7]) { float* data[7]; int sizes[7]; @@ -18,7 +18,7 @@ int doCTRLTest(XPCSocket *sock, char* drefs[7], float values[], int size, int ac // Execute command int result = sendCTRL(*sock, values, size, ac); - int d = 0.0f; + int d = 0.0f; if (result >= 0) { result = getDREFs(*sock, drefs, data, 7, sizes); @@ -66,19 +66,19 @@ int doGETCTest(float values[7], int ac, float expected[7]) return 0; } -int basicCTRLTest(char** drefs, int ac) +int basicCTRLTest(const 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 }; - XPCSocket sock = openUDP(IP); - pauseSim(sock, 1); // Pause so the controls wont change between 2 and 3 + XPCSocket sock = openUDP(IP); + pauseSim(sock, 1); // Pause so the controls wont change between 2 and 3 int result = doCTRLTest(&sock, drefs, CTRL, 3, ac, expected); if (result < 0) { return -10000 + result; } - crossPlatformUSleep(SLEEP_AMOUNT); + crossPlatformUSleep(SLEEP_AMOUNT); // Test control surfaces and set other values to known state. expected[0] = CTRL[0] = 0.2F; @@ -92,19 +92,19 @@ int basicCTRLTest(char** drefs, int ac) { return -20000 + result; } - crossPlatformUSleep(SLEEP_AMOUNT); + crossPlatformUSleep(SLEEP_AMOUNT); // Test other values and verify control surfaces unchanged. expected[0] = CTRL[0] = 0.15F; expected[1] = CTRL[1] = 0.15F; expected[2] = CTRL[2] = 0.15F; expected[3] = CTRL[3] = 0.9F; - CTRL[4] = -998; + CTRL[4] = -998; CTRL[5] = -998; result = doCTRLTest(&sock, drefs, CTRL, 6, ac, expected); - pauseSim(sock, 0); - closeUDP(sock); + pauseSim(sock, 0); + closeUDP(sock); if (result < 0) { if (result == -1004) { @@ -112,12 +112,12 @@ int basicCTRLTest(char** drefs, int ac) } return -30000 + result; } - return 0; + return 0; } int testCTRL_Player() { - char* drefs[] = + const char* drefs[] = { "sim/cockpit2/controls/yoke_pitch_ratio", "sim/cockpit2/controls/yoke_roll_ratio", @@ -132,7 +132,7 @@ int testCTRL_Player() int testCTRL_NonPlayer() { - char* drefs[] = + const char* drefs[] = { "sim/multiplayer/position/plane1_yolk_pitch", "sim/multiplayer/position/plane1_yolk_roll", @@ -147,7 +147,7 @@ int testCTRL_NonPlayer() int testCTRL_Speedbrakes() { - char* drefs[] = + const char* drefs[] = { "sim/cockpit2/controls/yoke_pitch_ratio", "sim/cockpit2/controls/yoke_roll_ratio", @@ -161,8 +161,8 @@ int testCTRL_Speedbrakes() // Arm float CTRL[7] = { -998, -998, -998, -998, -998, -998, -0.5F }; float expected[7] = { NAN, NAN, NAN, NAN, NAN, NAN, -0.5F }; - XPCSocket sock = openUDP(IP); - pauseSim(sock, 1); // Pause so the controls wont change between 2 and 3 + XPCSocket sock = openUDP(IP); + pauseSim(sock, 1); // Pause so the controls wont change between 2 and 3 int result = doCTRLTest(&sock, drefs, CTRL, 7, 0, expected); if (result < 0) { @@ -180,13 +180,13 @@ int testCTRL_Speedbrakes() // Retract expected[6] = CTRL[6] = 0.0F; result = doCTRLTest(&sock, drefs, CTRL, 7, 0, expected); - pauseSim(sock, 0); - closeUDP(sock); + pauseSim(sock, 0); + closeUDP(sock); if (result < 0) { return -30000 + result; } - return 0; + return 0; } int testGETC() From 1ff2e1b93eb11509eea7c235d8c747368f08a17d Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sat, 18 Apr 2020 22:23:36 -0700 Subject: [PATCH 15/50] Changed drefs to const char* to fix compiler warnings --- TestScripts/C Tests/DataTests.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TestScripts/C Tests/DataTests.h b/TestScripts/C Tests/DataTests.h index 4fde0abb..233602cb 100644 --- a/TestScripts/C Tests/DataTests.h +++ b/TestScripts/C Tests/DataTests.h @@ -10,7 +10,7 @@ int testDATA() { // Initialize int i, j; // Iterator - char* drefs[100] = + const char* drefs[100] = { "sim/aircraft/parts/acf_gear_deploy" }; From 38ddc0adb28d46bfeb5ecc8d21a9a296215d6981 Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sat, 18 Apr 2020 22:29:17 -0700 Subject: [PATCH 16/50] Changed drefs to const char* to fix compiler warnings Also changed actual [7] to a double in doGETPTEST to fix compiler warning --- TestScripts/C Tests/PosiTests.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/TestScripts/C Tests/PosiTests.h b/TestScripts/C Tests/PosiTests.h index fc084ecf..1b3983a6 100644 --- a/TestScripts/C Tests/PosiTests.h +++ b/TestScripts/C Tests/PosiTests.h @@ -6,7 +6,7 @@ #include "Test.h" #include "xplaneConnect.h" -int doPOSITest(char* drefs[7], double values[], int size, int ac, double expected[7]) +int doPOSITest(const char* drefs[7], double values[], int size, int ac, double expected[7]) { float* data[7]; int sizes[7]; @@ -43,7 +43,7 @@ int doPOSITest(char* drefs[7], double values[], int size, int ac, double expecte int doGETPTest(double values[7], int ac, double expected[7]) { // Execute Test - float actual[7]; + double actual[7]; XPCSocket sock = openUDP(IP); int result = sendPOSI(sock, values, 7, ac); if (result >= 0) @@ -67,7 +67,7 @@ int doGETPTest(double values[7], int ac, double expected[7]) return 0; } -int basicPOSITest(char** drefs, int ac) +int basicPOSITest(const char** drefs, int ac) { // Set psoition and initial orientation double POSI[7] = { 37.524, -122.06899, 2500, 0, 0, 0, 1 }; @@ -110,12 +110,12 @@ int basicPOSITest(char** drefs, int ac) { return -20000 + result; } - return 0; + return 0; } int testPOSI_Player() { - char* drefs[] = + const char* drefs[] = { "sim/flightmodel/position/latitude", "sim/flightmodel/position/longitude", @@ -130,7 +130,7 @@ int testPOSI_Player() int testPOSI_NonPlayer() { - char* drefs[] = + const char* drefs[] = { "sim/multiplayer/position/plane1_lat", "sim/multiplayer/position/plane1_lon", From f17844565beb90e9c7cc85ef0a87bbed0ea5f9c5 Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sat, 18 Apr 2020 22:35:09 -0700 Subject: [PATCH 17/50] Changed drefs to const char* to fix compiler warnings Also fixed compiler warning related to doGETDTEST on line 108 --- TestScripts/C Tests/DrefTests.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/TestScripts/C Tests/DrefTests.h b/TestScripts/C Tests/DrefTests.h index c64ce6d5..586b4081 100644 --- a/TestScripts/C Tests/DrefTests.h +++ b/TestScripts/C Tests/DrefTests.h @@ -6,7 +6,7 @@ #include "Test.h" #include "xplaneConnect.h" -int doGETDTest(char* drefs[], float* expected[], int count, int sizes[]) +int doGETDTest(const char* drefs[], float* expected[], int count, int sizes[]) { // Setup memory int* asizes = (int*)malloc(sizeof(int) * count); @@ -37,7 +37,7 @@ int doGETDTest(char* drefs[], float* expected[], int count, int sizes[]) return result; } -int doDREFTest(char* drefs[], float* values[], float* expected[], int count, int sizes[]) +int doDREFTest(const char* drefs[], float* values[], float* expected[], int count, int sizes[]) { // Setup memory int* asizes = (int*)malloc(sizeof(int) * count); @@ -74,7 +74,7 @@ int doDREFTest(char* drefs[], float* values[], float* expected[], int count, int int testGETD_Basic() { - char* drefs[] = + const char* drefs[] = { "sim/cockpit/switches/gear_handle_status", //int "sim/cockpit/autopilot/altitude", //float @@ -99,20 +99,20 @@ int testGETD_Basic() int testGETD_TestFloat() { - char* dref = "sim/test/test_float"; + const 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); + int result = doGETDTest(&dref, expected, 1, &size); free(expected[0]); return result; } int testGETD_Types() { - char* drefs[] = + const char* drefs[] = { "sim/cockpit/switches/gear_handle_status", //int "sim/cockpit/autopilot/altitude", //float @@ -173,7 +173,7 @@ int testGETD_Types() int testDREF() { - char* drefs[] = + const char* drefs[] = { "sim/cockpit/switches/gear_handle_status", //int "sim/cockpit/autopilot/altitude", //float From ab9d0b7ea795a3cd20ec7d578b55135676058b2b Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sun, 19 Apr 2020 00:34:46 -0700 Subject: [PATCH 18/50] Added getTERR function --- C/src/xplaneConnect.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/C/src/xplaneConnect.h b/C/src/xplaneConnect.h index 4a62b17c..9fa5faa2 100644 --- a/C/src/xplaneConnect.h +++ b/C/src/xplaneConnect.h @@ -216,6 +216,24 @@ int getPOSI(XPCSocket sock, double values[7], char ac); /// \returns 0 if successful, otherwise a negative value. int sendPOSI(XPCSocket sock, double values[], int size, char ac); +// Terrain + +/// Gets the terrain information of the specified aircraft. +/// +/// \param sock The socket to use to send the command. +/// \param posi A double array representing position data about the aircraft. The format of values is +/// [Lat, Lon, Alt]. +/// -998 used for [Lat, Lon, Alt] to request terrain info at the current aircraft position. +/// \param values A double array with the information for the terrain output. The format of values is +/// [Lat, Lon, Alt, Nx, Ny, Nz, Vx, Vy, Vz, wet, result]. The first three are for output of +/// the Lat and Lon of the aircraft with the terrain height directly below. The next three +/// represent the terrain normal. The next three represent the velocity of the terrain. +/// The wet variable is 0.0 if the terrain is dry and 1.0 if wet. +/// The last output is the terrain probe result parameter. +/// \param ac The aircraft number to set the position of. 0 for the main/user's aircraft. +/// \returns 0 if successful, otherwise a negative value. +int getTERR(XPCSocket sock, double posi[3], double values[11], char ac); + // Controls /// Gets the control surface information for the specified aircraft. From 377e19f4c416e6d4936032ca804491722125fc31 Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sun, 19 Apr 2020 01:04:20 -0700 Subject: [PATCH 19/50] Added getTERR function --- C/src/xplaneConnect.c | 111 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 95 insertions(+), 16 deletions(-) diff --git a/C/src/xplaneConnect.c b/C/src/xplaneConnect.c index 9425c946..3aa34cb3 100755 --- a/C/src/xplaneConnect.c +++ b/C/src/xplaneConnect.c @@ -58,6 +58,8 @@ 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[]); +int sendTERRRequest(XPCSocket sock, double posi[3], char ac); +int getTERRResponse(XPCSocket sock, double values[11], char ac); void printError(char *functionName, char *format, ...) { @@ -314,7 +316,7 @@ int sendDATA(XPCSocket sock, float data[][9], int rows) char buffer[4829] = "DATA"; int len = 5 + rows * 9 * sizeof(float); unsigned short step = 9 * sizeof(float); - int i; // iterator + int i; // iterator for (i = 0; i < rows; i++) { buffer[5 + i * step] = (char)data[i][0]; @@ -363,7 +365,7 @@ int readDATA(XPCSocket sock, float data[][9], int rows) } // Parse data - int i; // iterator + int i; // iterator for (i = 0; i < rows; ++i) { data[i][0] = buffer[5 + i * 36]; @@ -389,7 +391,7 @@ int sendDREFs(XPCSocket sock, const char* drefs[], float* values[], int sizes[], // Max size is technically unlimited. char buffer[65536] = "DREF"; int pos = 5; - int i; // Iterator + int i; // Iterator for (i = 0; i < count; ++i) { int drefLen = strnlen(drefs[i], 256); @@ -436,7 +438,7 @@ int sendDREFRequest(XPCSocket sock, const char* drefs[], unsigned char count) char buffer[65536] = "GETD"; buffer[5] = count; int len = 6; - int i; // iterator + int i; // iterator for (i = 0; i < count; ++i) { size_t drefLen = strnlen(drefs[i], 256); @@ -463,15 +465,15 @@ int getDREFResponse(XPCSocket sock, float* values[], unsigned char count, int si char buffer[65536]; int result = readUDP(sock, buffer, 65536); - if (result < 0) - { + if (result < 0) + { #ifdef _WIN32 - printError("getDREFs", "Read operation failed. (%d)", WSAGetLastError()); + printError("getDREFs", "Read operation failed. (%d)", WSAGetLastError()); #else - printError("getDREFs", "Read operation failed."); + printError("getDREFs", "Read operation failed."); #endif - return -1; - } + return -1; + } if (result < 6) { @@ -485,7 +487,7 @@ int getDREFResponse(XPCSocket sock, float* values[], unsigned char count, int si } int cur = 6; - int i; // Iterator + int i; // Iterator for (i = 0; i < count; ++i) { int l = buffer[cur++]; @@ -607,8 +609,8 @@ int sendPOSI(XPCSocket sock, double values[], int size, char ac) char buffer[46] = "POSI"; buffer[4] = 0xff; //Placeholder for message length buffer[5] = ac; - int i; // iterator - + + int i; // iterator for (i = 0; i < 7; i++) // double for lat/lon/h { double val = -998; @@ -623,8 +625,8 @@ int sendPOSI(XPCSocket sock, double values[], int size, char ac) } else /* attitude and gear */ { - float f = (float)val; - memcpy(&buffer[18 + i*4], &f, sizeof(float)); + float f = (float)val; + memcpy(&buffer[18 + i*4], &f, sizeof(float)); } } @@ -640,6 +642,83 @@ int sendPOSI(XPCSocket sock, double values[], int size, char ac) /**** End POSI functions ****/ /*****************************************************************************/ +/*****************************************************************************/ +/**** TERR functions ****/ +/*****************************************************************************/ +int sendTERRRequest(XPCSocket sock, double posi[3], char ac) +{ + // Setup send command + char buffer[30] = "GETT"; + buffer[5] = ac; + memcpy(&buffer[6], posi, 3 * sizeof(double)); + + // Send command + if (sendUDP(sock, buffer, 30) < 0) + { + printError("getTERR", "Failed to send command."); + return -1; + } + return 0; +} + +int getTERRResponse(XPCSocket sock, double values[11], char ac) +{ + // Get response + char readBuffer[62]; + int readResult = readUDP(sock, readBuffer, 62); + if (readResult < 0) + { + printError("getTERR", "Failed to read response."); + return -2; + } + if (readResult != 62) + { + printError("getTERR", "Unexpected response length."); + return -3; + } + + // Copy response into outputs + float f[8]; + ac = readBuffer[5]; + memcpy(values, readBuffer + 6, 3 * sizeof(double)); + memcpy(f, readBuffer + 30, 8 * sizeof(float)); + values[ 3] = (double)f[0]; + values[ 4] = (double)f[1]; + values[ 5] = (double)f[2]; + values[ 6] = (double)f[3]; + values[ 7] = (double)f[4]; + values[ 8] = (double)f[5]; + values[ 9] = (double)f[6]; + values[10] = (double)f[7]; + + return 0; +} + +int getTERR(XPCSocket sock, double posi[3], double values[11], char ac) +{ + // Send Command + int result = sendTERRRequest(sock, posi, ac); + if (result < 0) + { + // An error ocurred while sending. + // sendTERRRequest will print an error message, so just return. + return result; + } + + // Read Response + result = getTERRResponse(sock, values, ac); + if (result < 0) + { + // An error ocurred while reading the response. + // getTERRResponse will print an error message, so just return. + return result; + } + return 0; +} +/*****************************************************************************/ +/**** End TERR functions ****/ +/*****************************************************************************/ + /*****************************************************************************/ /**** CTRL functions ****/ /*****************************************************************************/ @@ -696,7 +775,7 @@ int sendCTRL(XPCSocket sock, float values[], int size, char ac) // 5 byte header + 5 float values * 4 + 2 byte values char buffer[31] = "CTRL"; int cur = 5; - int i; // iterator + int i; // iterator for (i = 0; i < 6; i++) { float val = -998; From d61f70faad6e72774c8eb6769ca45da4b3720bac Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sun, 19 Apr 2020 10:03:58 -0700 Subject: [PATCH 20/50] Improved HandleGetT accuracy Also added the ground velocity output to TERR message so can handle landing on aircraft carrier (moving ground). --- xpcPlugin/MessageHandlers.cpp | 90 ++++++++++++++++++++++------------- 1 file changed, 56 insertions(+), 34 deletions(-) diff --git a/xpcPlugin/MessageHandlers.cpp b/xpcPlugin/MessageHandlers.cpp index 5163edc4..05879d7f 100644 --- a/xpcPlugin/MessageHandlers.cpp +++ b/xpcPlugin/MessageHandlers.cpp @@ -642,81 +642,103 @@ namespace XPC unsigned char aircraft = buffer[5]; Log::FormatLine(LOG_TRACE, "GETT", "Getting terrain information for aircraft %u", aircraft); - double loc[3]; - double X; - double Y; - double Z; - memcpy(loc, buffer + 6, 24); + double pos[3]; + memcpy(pos, buffer + 6, 24); - if(loc[0] == -998 || loc[1] == -998 || loc[2] == -998) + if(pos[0] == -998 || pos[1] == -998 || pos[2] == -998) { // get terrain properties at aircraft location - // probe needs to be below terrain to work... - X = DataManager::GetDouble(DREF_LocalX, aircraft); - Z = DataManager::GetDouble(DREF_LocalZ, aircraft); - Y = -100.0; - } - else - { - // terrain probe at specified location - XPLMWorldToLocal(loc[0], loc[1], loc[2], &X, &Y, &Z); + pos[0] = DataManager::GetDouble(DREF_Latitude, aircraft); + pos[1] = DataManager::GetDouble(DREF_Longitude, aircraft); + pos[2] = 0.0; } + MessageHandlers::SendTerr(pos, aircraft); + } + + void MessageHandlers::SendTerr(double pos[3], char aircraft) + { + double lat, lon, alt, X, Y, Z; // Init terrain probe (if required) and probe data struct - XPLMProbeInfo_t probe_data; + static XPLMProbeInfo_t probe_data; probe_data.structSize = sizeof(XPLMProbeInfo_t); if(Terrain_probe == nullptr) { - Log::FormatLine(LOG_TRACE, "GETT", "Create terrain probe for aircraft %u", aircraft); + Log::FormatLine(LOG_TRACE, "TERR", "Create terrain probe for aircraft %u", aircraft); Terrain_probe = XPLMCreateProbe(0); } + // terrain probe at specified location + // Follow the process in the following post to get accurate results + // https://forums.x-plane.org/index.php?/forums/topic/38688-how-do-i-use-xplmprobeterrainxyz/&page=2 + + // transform probe location to local coordinates + // Step 1. Convert initial lat/lon/alt to XYZ + XPLMWorldToLocal(pos[0], pos[1], pos[2], &X, &Y, &Z); + // query probe + // Step 2. Probe XYZ to get a new Y int rc = XPLMProbeTerrainXYZ(Terrain_probe, X, Y, Z, &probe_data); - + if(rc > 0) + { + Log::FormatLine(LOG_ERROR, "TERR", "Probe failed. Return Value %u", rc); + XPLMDestroyProbe(Terrain_probe); + return; + } + // transform probe location to world coordinates - double lat; - double lon; - double alt; - + // Step 3. Convert that new XYZ back to LLE + XPLMLocalToWorld(probe_data.locationX, probe_data.locationY, probe_data.locationZ, &lat, &lon, &alt); + Log::FormatLine(LOG_TRACE, "TERR", "Conv LLA=%f, %f, %f", lat, lon, alt); + + // transform probe location to local coordinates + // Step 4. NOW convert your origina lat/lon with the elevation from step 3 to XYZ + XPLMWorldToLocal(pos[0], pos[1], alt, &X, &Y, &Z); + + // query probe + // Step 5. Re-probe with the NEW XYZ + rc = XPLMProbeTerrainXYZ(Terrain_probe, X, Y, Z, &probe_data); if(rc == 0) { + // transform probe location to world coordinates + // Step 6. You now have a new Y, and your XYZ will be closer to correct for high elevations far from the origin. XPLMLocalToWorld(probe_data.locationX, probe_data.locationY, probe_data.locationZ, &lat, &lon, &alt); - - Log::FormatLine(LOG_TRACE, "GETT", "Probe LLA %lf %lf %lf", lat, lon, alt); + Log::FormatLine(LOG_TRACE, "TERR", "Probe LLA %lf %lf %lf", lat, lon, alt); } else { lat = -998; lon = -998; alt = -998; - - Log::FormatLine(LOG_TRACE, "GETT", "Probe failed. Return Value %u", rc); + Log::FormatLine(LOG_TRACE, "TERR", "Probe failed. Return Value %u", rc); } // keep probe for next query - // XPLMDestroyProbe(probe); + // XPLMDestroyProbe(Terrain_probe); // Assemble response message - unsigned char response[50] = "TERR"; + unsigned char response[62] = "TERR"; response[5] = aircraft; // terrain height over msl at lat/lon point memcpy(response + 6, &lat, 8); memcpy(response + 14, &lon, 8); memcpy(response + 22, &alt, 8); - // terrain incidence + // terrain normal vector memcpy(response + 30, &probe_data.normalX, 4); memcpy(response + 34, &probe_data.normalY, 4); memcpy(response + 38, &probe_data.normalZ, 4); + // terrain velocity + memcpy(response + 42, &probe_data.velocityX, 4); + memcpy(response + 46, &probe_data.velocityY, 4); + memcpy(response + 50, &probe_data.velocityZ, 4); // terrain type - memcpy(response + 42, &probe_data.is_wet, 4); + memcpy(response + 54, &probe_data.is_wet, 4); // probe status - memcpy(response + 46, &rc, 4); - - sock->SendTo(response, 50, &connection.addr); - } + memcpy(response + 58, &rc, 4); + sock->SendTo(response, 62, &connection.addr); + } void MessageHandlers::HandleSimu(const Message& msg) { From 6a483db8cc4a94415a84e43d1eb1a78756e7f265 Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sun, 19 Apr 2020 10:46:59 -0700 Subject: [PATCH 21/50] Python3 demos using Python2 syntax were run through 2to3, fixes nasa#191 --- Python3/src/basicExample.py | 30 ++++++++++----------- Python3/src/monitorExample.py | 4 +-- Python3/src/playbackExample.py | 48 +++++++++++++++++----------------- 3 files changed, 41 insertions(+), 41 deletions(-) diff --git a/Python3/src/basicExample.py b/Python3/src/basicExample.py index f381e5df..b42f2c19 100644 --- a/Python3/src/basicExample.py +++ b/Python3/src/basicExample.py @@ -2,8 +2,8 @@ import xpc def ex(): - print "X-Plane Connect example script" - print "Setting up simulation" + print("X-Plane Connect example script") + print("Setting up simulation") with xpc.XPlaneConnect() as client: # Verify connection try: @@ -11,24 +11,24 @@ def ex(): # will be raised. client.getDREF("sim/test/test_float") except: - print "Error establishing connection to X-Plane." - print "Exiting..." + print("Error establishing connection to X-Plane.") + print("Exiting...") return # Set position of the player aircraft - print "Setting position" + 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" + 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" + print("Setting orientation") data = [\ [18, 0, -998, 0, -998, -998, -998, -998, -998],\ [ 3, 130, 130, 130, 130, -998, -998, -998, -998],\ @@ -37,21 +37,21 @@ def ex(): client.sendDATA(data) # Set control surfaces and throttle of the player aircraft using sendCTRL - print "Setting controls" + print("Setting controls") ctrl = [0.0, 0.0, 0.0, 0.8] client.sendCTRL(ctrl) # Pause the sim - print "Pausing" + print("Pausing") client.pauseSim(True) sleep(2) # Toggle pause state to resume - print "Resuming" + print("Resuming") client.pauseSim(False) # Stow landing gear using a dataref - print "Stowing gear" + print("Stowing gear") gear_dref = "sim/cockpit/switches/gear_handle_status" client.sendDREF(gear_dref, 0) @@ -61,12 +61,12 @@ def ex(): # Make sure gear was stowed successfully gear_status = client.getDREF(gear_dref) if gear_status[0] == 0: - print "Gear stowed" + print("Gear stowed") else: - print "Error stowing gear" + print("Error stowing gear") - print "End of Python client example" - raw_input("Press any key to exit...") + print("End of Python client example") + input("Press any key to exit...") if __name__ == "__main__": ex() \ No newline at end of file diff --git a/Python3/src/monitorExample.py b/Python3/src/monitorExample.py index c4cdb480..562ac53f 100644 --- a/Python3/src/monitorExample.py +++ b/Python3/src/monitorExample.py @@ -8,8 +8,8 @@ def monitor(): posi = client.getPOSI(); ctrl = client.getCTRL(); - print "Loc: (%4f, %4f, %4f) Aileron:%2f Elevator:%2f Rudder:%2f\n"\ - % (posi[0], posi[1], posi[2], ctrl[1], ctrl[0], ctrl[2]) + print("Loc: (%4f, %4f, %4f) Aileron:%2f Elevator:%2f Rudder:%2f\n"\ + % (posi[0], posi[1], posi[2], ctrl[1], ctrl[0], ctrl[2])) if __name__ == "__main__": diff --git a/Python3/src/playbackExample.py b/Python3/src/playbackExample.py index dfa4f522..17eb2f14 100644 --- a/Python3/src/playbackExample.py +++ b/Python3/src/playbackExample.py @@ -5,78 +5,78 @@ def record(path, interval = 0.1, duration = 60): try: fd = open(path, "w") except: - print "Unable to open file." + print("Unable to open file.") return count = int(duration / interval) if count < 1: - print "duration is less than a single frame." + print("duration is less than a single frame.") return with xpc.XPlaneConnect("localhost", 49009, 0, 1000) as client: - print "Recording..." + print("Recording...") for i in range(0, count): try: posi = client.getPOSI() fd.write("{0}, {1}, {2}, {3}, {4}, {5}, {6}\n".format(*posi)) except: - print "Error reading position" + print("Error reading position") continue sleep(interval); - print "Recording Complete" + print("Recording Complete") fd.close() def playback(path, interval): try: fd = open(path, "r") except: - print "Unable to open file." + print("Unable to open file.") return with xpc.XPlaneConnect("localhost", 49009, 0, 1000) as client: - print "Starting Playback..." + print("Starting Playback...") for line in fd: try: posi = [ float(x) for x in line.split(',') ] posi = client.sendPOSI(posi) except: - print "Error sending position" + print("Error sending position") continue sleep(interval); - print "Playback Complete" + print("Playback Complete") fd.close() def printMenu(title, opts): - print "\n+---------------------------------------------- +" - print "| {0:42} |\n".format(title) - print "+---------------------------------------------- +" + print("\n+---------------------------------------------- +") + print("| {0:42} |\n".format(title)) + print("+---------------------------------------------- +") for i in range(0,len(opts)): - print "| {0:2}. {1:40} |".format(i + 1, opts[i]) - print "+---------------------------------------------- +" - return int(raw_input("Please select and option: ")) + print("| {0:2}. {1:40} |".format(i + 1, opts[i])) + print("+---------------------------------------------- +") + return int(input("Please select and option: ")) def ex(): - print "X-Plane Connect Playback Example [Version 1.2.0]" - print "(c) 2013-2015 United States Government as represented by the Administrator" - print "of the National Aeronautics and Space Administration. All Rights Reserved." + print("X-Plane Connect Playback Example [Version 1.2.0]") + print("(c) 2013-2015 United States Government as represented by the Administrator") + print("of the National Aeronautics and Space Administration. All Rights Reserved.") mainOpts = [ "Record X-Plane", "Playback File", "Exit" ] while True: opt = printMenu("What would you like to do?", mainOpts) if opt == 1: - path = raw_input("Enter save file path: ") - interval = float(raw_input("Enter interval between frames (seconds): ")) - duration = float(raw_input("Enter duration to record for (seconds): ")) + path = input("Enter save file path: ") + interval = float(input("Enter interval between frames (seconds): ")) + duration = float(input("Enter duration to record for (seconds): ")) record(path, interval, duration) elif opt == 2: - path = raw_input("Enter save file path: ") - interval = float(raw_input("Enter interval between frames (seconds): ")) + path = input("Enter save file path: ") + interval = float(input("Enter interval between frames (seconds): ")) playback(path, interval) elif opt == 3: return; else: - print "Unrecognized option." + print("Unrecognized option.") if __name__ == "__main__": ex() \ No newline at end of file From f37f4a4aaebd410065cf5d638fbdcc4a6cd59346 Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sun, 19 Apr 2020 11:36:51 -0700 Subject: [PATCH 22/50] Revert "Improved HandleGetT accuracy" This reverts commit d61f70faad6e72774c8eb6769ca45da4b3720bac. --- xpcPlugin/MessageHandlers.cpp | 90 +++++++++++++---------------------- 1 file changed, 34 insertions(+), 56 deletions(-) diff --git a/xpcPlugin/MessageHandlers.cpp b/xpcPlugin/MessageHandlers.cpp index 05879d7f..5163edc4 100644 --- a/xpcPlugin/MessageHandlers.cpp +++ b/xpcPlugin/MessageHandlers.cpp @@ -642,104 +642,82 @@ namespace XPC unsigned char aircraft = buffer[5]; Log::FormatLine(LOG_TRACE, "GETT", "Getting terrain information for aircraft %u", aircraft); - double pos[3]; - memcpy(pos, buffer + 6, 24); + double loc[3]; + double X; + double Y; + double Z; + memcpy(loc, buffer + 6, 24); - if(pos[0] == -998 || pos[1] == -998 || pos[2] == -998) + if(loc[0] == -998 || loc[1] == -998 || loc[2] == -998) { // get terrain properties at aircraft location - pos[0] = DataManager::GetDouble(DREF_Latitude, aircraft); - pos[1] = DataManager::GetDouble(DREF_Longitude, aircraft); - pos[2] = 0.0; + // probe needs to be below terrain to work... + X = DataManager::GetDouble(DREF_LocalX, aircraft); + Z = DataManager::GetDouble(DREF_LocalZ, aircraft); + Y = -100.0; + } + else + { + // terrain probe at specified location + XPLMWorldToLocal(loc[0], loc[1], loc[2], &X, &Y, &Z); } - MessageHandlers::SendTerr(pos, aircraft); - } - - void MessageHandlers::SendTerr(double pos[3], char aircraft) - { - double lat, lon, alt, X, Y, Z; // Init terrain probe (if required) and probe data struct - static XPLMProbeInfo_t probe_data; + XPLMProbeInfo_t probe_data; probe_data.structSize = sizeof(XPLMProbeInfo_t); if(Terrain_probe == nullptr) { - Log::FormatLine(LOG_TRACE, "TERR", "Create terrain probe for aircraft %u", aircraft); + Log::FormatLine(LOG_TRACE, "GETT", "Create terrain probe for aircraft %u", aircraft); Terrain_probe = XPLMCreateProbe(0); } - // terrain probe at specified location - // Follow the process in the following post to get accurate results - // https://forums.x-plane.org/index.php?/forums/topic/38688-how-do-i-use-xplmprobeterrainxyz/&page=2 - - // transform probe location to local coordinates - // Step 1. Convert initial lat/lon/alt to XYZ - XPLMWorldToLocal(pos[0], pos[1], pos[2], &X, &Y, &Z); - // query probe - // Step 2. Probe XYZ to get a new Y int rc = XPLMProbeTerrainXYZ(Terrain_probe, X, Y, Z, &probe_data); - if(rc > 0) - { - Log::FormatLine(LOG_ERROR, "TERR", "Probe failed. Return Value %u", rc); - XPLMDestroyProbe(Terrain_probe); - return; - } - + // transform probe location to world coordinates - // Step 3. Convert that new XYZ back to LLE - XPLMLocalToWorld(probe_data.locationX, probe_data.locationY, probe_data.locationZ, &lat, &lon, &alt); - Log::FormatLine(LOG_TRACE, "TERR", "Conv LLA=%f, %f, %f", lat, lon, alt); - - // transform probe location to local coordinates - // Step 4. NOW convert your origina lat/lon with the elevation from step 3 to XYZ - XPLMWorldToLocal(pos[0], pos[1], alt, &X, &Y, &Z); - - // query probe - // Step 5. Re-probe with the NEW XYZ - rc = XPLMProbeTerrainXYZ(Terrain_probe, X, Y, Z, &probe_data); + double lat; + double lon; + double alt; + if(rc == 0) { - // transform probe location to world coordinates - // Step 6. You now have a new Y, and your XYZ will be closer to correct for high elevations far from the origin. XPLMLocalToWorld(probe_data.locationX, probe_data.locationY, probe_data.locationZ, &lat, &lon, &alt); - Log::FormatLine(LOG_TRACE, "TERR", "Probe LLA %lf %lf %lf", lat, lon, alt); + + Log::FormatLine(LOG_TRACE, "GETT", "Probe LLA %lf %lf %lf", lat, lon, alt); } else { lat = -998; lon = -998; alt = -998; - Log::FormatLine(LOG_TRACE, "TERR", "Probe failed. Return Value %u", rc); + + Log::FormatLine(LOG_TRACE, "GETT", "Probe failed. Return Value %u", rc); } // keep probe for next query - // XPLMDestroyProbe(Terrain_probe); + // XPLMDestroyProbe(probe); // Assemble response message - unsigned char response[62] = "TERR"; + unsigned char response[50] = "TERR"; response[5] = aircraft; // terrain height over msl at lat/lon point memcpy(response + 6, &lat, 8); memcpy(response + 14, &lon, 8); memcpy(response + 22, &alt, 8); - // terrain normal vector + // terrain incidence memcpy(response + 30, &probe_data.normalX, 4); memcpy(response + 34, &probe_data.normalY, 4); memcpy(response + 38, &probe_data.normalZ, 4); - // terrain velocity - memcpy(response + 42, &probe_data.velocityX, 4); - memcpy(response + 46, &probe_data.velocityY, 4); - memcpy(response + 50, &probe_data.velocityZ, 4); // terrain type - memcpy(response + 54, &probe_data.is_wet, 4); + memcpy(response + 42, &probe_data.is_wet, 4); // probe status - memcpy(response + 58, &rc, 4); - - sock->SendTo(response, 62, &connection.addr); + memcpy(response + 46, &rc, 4); + + sock->SendTo(response, 50, &connection.addr); } + void MessageHandlers::HandleSimu(const Message& msg) { // Update log From 97c87b48b86d831a0e33c5e748c87f8eafdec2ce Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sun, 19 Apr 2020 11:37:07 -0700 Subject: [PATCH 23/50] Revert "Added getTERR function" This reverts commit 377e19f4c416e6d4936032ca804491722125fc31. --- C/src/xplaneConnect.c | 111 ++++++------------------------------------ 1 file changed, 16 insertions(+), 95 deletions(-) diff --git a/C/src/xplaneConnect.c b/C/src/xplaneConnect.c index 3aa34cb3..9425c946 100755 --- a/C/src/xplaneConnect.c +++ b/C/src/xplaneConnect.c @@ -58,8 +58,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[]); -int sendTERRRequest(XPCSocket sock, double posi[3], char ac); -int getTERRResponse(XPCSocket sock, double values[11], char ac); void printError(char *functionName, char *format, ...) { @@ -316,7 +314,7 @@ int sendDATA(XPCSocket sock, float data[][9], int rows) char buffer[4829] = "DATA"; int len = 5 + rows * 9 * sizeof(float); unsigned short step = 9 * sizeof(float); - int i; // iterator + int i; // iterator for (i = 0; i < rows; i++) { buffer[5 + i * step] = (char)data[i][0]; @@ -365,7 +363,7 @@ int readDATA(XPCSocket sock, float data[][9], int rows) } // Parse data - int i; // iterator + int i; // iterator for (i = 0; i < rows; ++i) { data[i][0] = buffer[5 + i * 36]; @@ -391,7 +389,7 @@ int sendDREFs(XPCSocket sock, const char* drefs[], float* values[], int sizes[], // Max size is technically unlimited. char buffer[65536] = "DREF"; int pos = 5; - int i; // Iterator + int i; // Iterator for (i = 0; i < count; ++i) { int drefLen = strnlen(drefs[i], 256); @@ -438,7 +436,7 @@ int sendDREFRequest(XPCSocket sock, const char* drefs[], unsigned char count) char buffer[65536] = "GETD"; buffer[5] = count; int len = 6; - int i; // iterator + int i; // iterator for (i = 0; i < count; ++i) { size_t drefLen = strnlen(drefs[i], 256); @@ -465,15 +463,15 @@ int getDREFResponse(XPCSocket sock, float* values[], unsigned char count, int si char buffer[65536]; int result = readUDP(sock, buffer, 65536); - if (result < 0) - { + if (result < 0) + { #ifdef _WIN32 - printError("getDREFs", "Read operation failed. (%d)", WSAGetLastError()); + printError("getDREFs", "Read operation failed. (%d)", WSAGetLastError()); #else - printError("getDREFs", "Read operation failed."); + printError("getDREFs", "Read operation failed."); #endif - return -1; - } + return -1; + } if (result < 6) { @@ -487,7 +485,7 @@ int getDREFResponse(XPCSocket sock, float* values[], unsigned char count, int si } int cur = 6; - int i; // Iterator + int i; // Iterator for (i = 0; i < count; ++i) { int l = buffer[cur++]; @@ -609,8 +607,8 @@ int sendPOSI(XPCSocket sock, double values[], int size, char ac) char buffer[46] = "POSI"; buffer[4] = 0xff; //Placeholder for message length buffer[5] = ac; - - int i; // iterator + int i; // iterator + for (i = 0; i < 7; i++) // double for lat/lon/h { double val = -998; @@ -625,8 +623,8 @@ int sendPOSI(XPCSocket sock, double values[], int size, char ac) } else /* attitude and gear */ { - float f = (float)val; - memcpy(&buffer[18 + i*4], &f, sizeof(float)); + float f = (float)val; + memcpy(&buffer[18 + i*4], &f, sizeof(float)); } } @@ -642,83 +640,6 @@ int sendPOSI(XPCSocket sock, double values[], int size, char ac) /**** End POSI functions ****/ /*****************************************************************************/ -/*****************************************************************************/ -/**** TERR functions ****/ -/*****************************************************************************/ -int sendTERRRequest(XPCSocket sock, double posi[3], char ac) -{ - // Setup send command - char buffer[30] = "GETT"; - buffer[5] = ac; - memcpy(&buffer[6], posi, 3 * sizeof(double)); - - // Send command - if (sendUDP(sock, buffer, 30) < 0) - { - printError("getTERR", "Failed to send command."); - return -1; - } - return 0; -} - -int getTERRResponse(XPCSocket sock, double values[11], char ac) -{ - // Get response - char readBuffer[62]; - int readResult = readUDP(sock, readBuffer, 62); - if (readResult < 0) - { - printError("getTERR", "Failed to read response."); - return -2; - } - if (readResult != 62) - { - printError("getTERR", "Unexpected response length."); - return -3; - } - - // Copy response into outputs - float f[8]; - ac = readBuffer[5]; - memcpy(values, readBuffer + 6, 3 * sizeof(double)); - memcpy(f, readBuffer + 30, 8 * sizeof(float)); - values[ 3] = (double)f[0]; - values[ 4] = (double)f[1]; - values[ 5] = (double)f[2]; - values[ 6] = (double)f[3]; - values[ 7] = (double)f[4]; - values[ 8] = (double)f[5]; - values[ 9] = (double)f[6]; - values[10] = (double)f[7]; - - return 0; -} - -int getTERR(XPCSocket sock, double posi[3], double values[11], char ac) -{ - // Send Command - int result = sendTERRRequest(sock, posi, ac); - if (result < 0) - { - // An error ocurred while sending. - // sendTERRRequest will print an error message, so just return. - return result; - } - - // Read Response - result = getTERRResponse(sock, values, ac); - if (result < 0) - { - // An error ocurred while reading the response. - // getTERRResponse will print an error message, so just return. - return result; - } - return 0; -} -/*****************************************************************************/ -/**** End TERR functions ****/ -/*****************************************************************************/ - /*****************************************************************************/ /**** CTRL functions ****/ /*****************************************************************************/ @@ -775,7 +696,7 @@ int sendCTRL(XPCSocket sock, float values[], int size, char ac) // 5 byte header + 5 float values * 4 + 2 byte values char buffer[31] = "CTRL"; int cur = 5; - int i; // iterator + int i; // iterator for (i = 0; i < 6; i++) { float val = -998; From ba9e8b0eee1c06b3c5e0326527f06293db87b60b Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sun, 19 Apr 2020 11:37:14 -0700 Subject: [PATCH 24/50] Revert "Added getTERR function" This reverts commit ab9d0b7ea795a3cd20ec7d578b55135676058b2b. --- C/src/xplaneConnect.h | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/C/src/xplaneConnect.h b/C/src/xplaneConnect.h index 9fa5faa2..4a62b17c 100644 --- a/C/src/xplaneConnect.h +++ b/C/src/xplaneConnect.h @@ -216,24 +216,6 @@ int getPOSI(XPCSocket sock, double values[7], char ac); /// \returns 0 if successful, otherwise a negative value. int sendPOSI(XPCSocket sock, double values[], int size, char ac); -// Terrain - -/// Gets the terrain information of the specified aircraft. -/// -/// \param sock The socket to use to send the command. -/// \param posi A double array representing position data about the aircraft. The format of values is -/// [Lat, Lon, Alt]. -/// -998 used for [Lat, Lon, Alt] to request terrain info at the current aircraft position. -/// \param values A double array with the information for the terrain output. The format of values is -/// [Lat, Lon, Alt, Nx, Ny, Nz, Vx, Vy, Vz, wet, result]. The first three are for output of -/// the Lat and Lon of the aircraft with the terrain height directly below. The next three -/// represent the terrain normal. The next three represent the velocity of the terrain. -/// The wet variable is 0.0 if the terrain is dry and 1.0 if wet. -/// The last output is the terrain probe result parameter. -/// \param ac The aircraft number to set the position of. 0 for the main/user's aircraft. -/// \returns 0 if successful, otherwise a negative value. -int getTERR(XPCSocket sock, double posi[3], double values[11], char ac); - // Controls /// Gets the control surface information for the specified aircraft. From a3175a81809686ec1729e52245fdb88316c289ad Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sun, 19 Apr 2020 13:02:25 -0700 Subject: [PATCH 25/50] Added getTERR function Also corrected minor typos in comments. --- C/src/xplaneConnect.c | 87 ++++++++++++++++++++++++++++++++++++++++--- C/src/xplaneConnect.h | 46 ++++++++++++++++------- 2 files changed, 114 insertions(+), 19 deletions(-) diff --git a/C/src/xplaneConnect.c b/C/src/xplaneConnect.c index 9425c946..fdcba8e6 100755 --- a/C/src/xplaneConnect.c +++ b/C/src/xplaneConnect.c @@ -185,7 +185,7 @@ int sendUDP(XPCSocket sock, char buffer[], int len) /// \param sock The socket to read from. /// \param buffer A pointer to the location to store the data. /// \param len The number of bytes to read. -/// \returns If an error occurs, a negative number. Otehrwise, the number of bytes read. +/// \returns If an error occurs, a negative number. Otherwise, the number of bytes read. int readUDP(XPCSocket sock, char buffer[], int len) { #ifdef _WIN32 @@ -378,9 +378,9 @@ int readDATA(XPCSocket sock, float data[][9], int rows) /*****************************************************************************/ /**** DREF functions ****/ /*****************************************************************************/ -int sendDREF(XPCSocket sock, const char* dref, float value[], int size) +int sendDREF(XPCSocket sock, const char* dref, float values[], int size) { - return sendDREFs(sock, &dref, &value, &size, 1); + return sendDREFs(sock, &dref, &values, &size, 1); } int sendDREFs(XPCSocket sock, const char* drefs[], float* values[], int sizes[], int count) @@ -516,7 +516,7 @@ int getDREFs(XPCSocket sock, const char* drefs[], float* values[], unsigned char int result = sendDREFRequest(sock, drefs, count); if (result < 0) { - // A error ocurred while sending. + // An error ocurred while sending. // sendDREFRequest will print an error message, so just return. return -1; } @@ -524,7 +524,7 @@ int getDREFs(XPCSocket sock, const char* drefs[], float* values[], unsigned char // Read Response if (getDREFResponse(sock, values, count, sizes) < 0) { - // A error ocurred while reading the response. + // An error ocurred while reading the response. // getDREFResponse will print an error message, so just return. return -2; } @@ -640,6 +640,83 @@ int sendPOSI(XPCSocket sock, double values[], int size, char ac) /**** End POSI functions ****/ /*****************************************************************************/ +/*****************************************************************************/ +/**** TERR functions ****/ +/*****************************************************************************/ +int sendTERRRequest(XPCSocket sock, double posi[3], char ac) +{ + // Setup send command + char buffer[30] = "GETT"; + buffer[5] = ac; + memcpy(&buffer[6], posi, 3 * sizeof(double)); + + // Send command + if (sendUDP(sock, buffer, 30) < 0) + { + printError("getTERR", "Failed to send command."); + return -1; + } + return 0; +} + +int getTERRResponse(XPCSocket sock, double values[11], char ac) +{ + // Get response + char readBuffer[62]; + int readResult = readUDP(sock, readBuffer, 62); + if (readResult < 0) + { + printError("getTERR", "Failed to read response."); + return -2; + } + if (readResult != 62) + { + printError("getTERR", "Unexpected response length."); + return -3; + } + + // Copy response into outputs + float f[8]; + ac = readBuffer[5]; + memcpy(values, readBuffer + 6, 3 * sizeof(double)); + memcpy(f, readBuffer + 30, 8 * sizeof(float)); + values[ 3] = (double)f[0]; + values[ 4] = (double)f[1]; + values[ 5] = (double)f[2]; + values[ 6] = (double)f[3]; + values[ 7] = (double)f[4]; + values[ 8] = (double)f[5]; + values[ 9] = (double)f[6]; + values[10] = (double)f[7]; + + return 0; +} + +int getTERR(XPCSocket sock, double posi[3], double values[11], char ac) +{ + // Send Command + int result = sendTERRRequest(sock, posi, ac); + if (result < 0) + { + // An error ocurred while sending. + // sendTERRRequest will print an error message, so just return. + return result; + } + + // Read Response + result = getTERRResponse(sock, values, ac); + if (result < 0) + { + // An error ocurred while reading the response. + // getTERRResponse will print an error message, so just return. + return result; + } + return 0; +} +/*****************************************************************************/ +/**** End TERR functions ****/ +/*****************************************************************************/ + /*****************************************************************************/ /**** CTRL functions ****/ /*****************************************************************************/ diff --git a/C/src/xplaneConnect.h b/C/src/xplaneConnect.h index 4a62b17c..67eafba8 100644 --- a/C/src/xplaneConnect.h +++ b/C/src/xplaneConnect.h @@ -113,7 +113,7 @@ int setCONN(XPCSocket* sock, unsigned short port); /// /// \param sock The socket to use to send the command. /// \param pause 0 to unpause the sim; 1 to pause, 100:119 to pause a/c 0:19, 200:219 to unpause a/c 0:19. -/// \returns 0 if successful, otherwise a negative value. +/// \returns 0 if successful, otherwise a negative value. int pauseSim(XPCSocket sock, char pause); // X-Plane UDP DATA @@ -122,7 +122,7 @@ int pauseSim(XPCSocket sock, char pause); /// /// \details This command is compatible with the X-Plane data API. /// \param sock The socket to use to send the command. -/// \param data A 2D array of data rows to read into. +/// \param data A 2D array of data rows to read into. /// \param rows The number of rows in dataRef. /// \returns 0 if successful, otherwise a negative value. int readDATA(XPCSocket sock, float data[][9], int rows); @@ -131,7 +131,7 @@ int readDATA(XPCSocket sock, float data[][9], int rows); /// /// \details This command is compatible with the X-Plane data API. /// \param sock The socket to use to send the command. -/// \param data A 2D array of data rows to send. +/// \param data A 2D array of data rows to send. /// \param rows The number of rows in dataRef. /// \returns 0 if successful, otherwise a negative value. int sendDATA(XPCSocket sock, float data[][9], int rows); @@ -144,12 +144,12 @@ 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 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); +/// \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. +int sendDREF(XPCSocket sock, const char* dref, float values[], int size); /// Sets the specified datarefs to the specified values. /// @@ -159,7 +159,7 @@ int sendDREF(XPCSocket sock, const char* dref, float value[], int size); /// 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 values A 2D array 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. @@ -173,13 +173,13 @@ int sendDREFs(XPCSocket sock, const char* drefs[], float* values[], int sizes[], /// 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 get. -/// \param values The array in which the value of the dataref will be stored. +/// \param values The array in which the values of the dataref will be stored. /// \param size The number of elements in values. The actual number of elements copied in will /// be set when the function returns. /// \returns 0 if successful, otherwise a negative value. int getDREF(XPCSocket sock, const char* dref, float values[], int* size); -/// Gets the value of the specified dataref. +/// Gets the values of the specified datarefs. /// /// \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 @@ -189,7 +189,7 @@ int getDREF(XPCSocket sock, const char* dref, float values[], int* size); /// \param drefs The names of the datarefs to get. /// \param values A 2D array in which the values of the datarefs will be stored. /// \param count The number of datarefs being requested. -/// \param size The number of elements in each row of values. The size of each row will be set +/// \param sizes The number of elements in each row of values. The size of each row will be set /// to the actual number of elements copied in for that row. /// \returns 0 if successful, otherwise a negative value. int getDREFs(XPCSocket sock, const char* drefs[], float* values[], unsigned char count, int sizes[]); @@ -216,6 +216,24 @@ int getPOSI(XPCSocket sock, double values[7], char ac); /// \returns 0 if successful, otherwise a negative value. int sendPOSI(XPCSocket sock, double values[], int size, char ac); +// Terrain + +/// Gets the terrain information of the specified aircraft. +/// +/// \param sock The socket to use to send the command. +/// \param posi A double array representing position data about the aircraft. The format of values is +/// [Lat, Lon, Alt]. +/// -998 used for [Lat, Lon, Alt] to request terrain info at the current aircraft position. +/// \param values A double array with the information for the terrain output. The format of values is +/// [Lat, Lon, Alt, Nx, Ny, Nz, Vx, Vy, Vz, wet, result]. The first three are for output of +/// the Lat and Lon of the aircraft with the terrain height directly below. The next three +/// represent the terrain normal. The next three represent the velocity of the terrain. +/// The wet variable is 0.0 if the terrain is dry and 1.0 if wet. +/// The last output is the terrain probe result parameter. +/// \param ac The aircraft number to get the terrain data of. 0 for the main/user's aircraft. +/// \returns 0 if successful, otherwise a negative value. +int getTERR(XPCSocket sock, double posi[3], double values[11], char ac); + // Controls /// Gets the control surface information for the specified aircraft. @@ -224,7 +242,7 @@ int sendPOSI(XPCSocket sock, double values[], int size, char ac); /// \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/user's aircraft. +/// \param ac The aircraft to get the control surfaces of. 0 is the main/user's aircraft. /// \returns 0 if successful, otherwise a negative value. int getCTRL(XPCSocket sock, float values[7], char ac); From f630dbdf07b020484f0c3ace6631d5d68deda736 Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sun, 19 Apr 2020 13:33:00 -0700 Subject: [PATCH 26/50] Improved accuracy of HandleGetT terrain probe Follow the process in the following post to get accurate results: // https://forums.x-plane.org/index.php?/forums/topic/38688-how-do-i-use-xplmprobeterrainxyz/&page=2 Also added the ground velocity vector to the output. This is used for carrier landing where "ground" is moving. --- xpcPlugin/MessageHandlers.cpp | 88 ++++++++++++++++++++++------------- 1 file changed, 56 insertions(+), 32 deletions(-) diff --git a/xpcPlugin/MessageHandlers.cpp b/xpcPlugin/MessageHandlers.cpp index 5163edc4..453811b5 100644 --- a/xpcPlugin/MessageHandlers.cpp +++ b/xpcPlugin/MessageHandlers.cpp @@ -642,49 +642,70 @@ namespace XPC unsigned char aircraft = buffer[5]; Log::FormatLine(LOG_TRACE, "GETT", "Getting terrain information for aircraft %u", aircraft); - double loc[3]; - double X; - double Y; - double Z; - memcpy(loc, buffer + 6, 24); + double pos[3]; + memcpy(pos, buffer + 6, 24); - if(loc[0] == -998 || loc[1] == -998 || loc[2] == -998) { // get terrain properties at aircraft location - // probe needs to be below terrain to work... - X = DataManager::GetDouble(DREF_LocalX, aircraft); - Z = DataManager::GetDouble(DREF_LocalZ, aircraft); - Y = -100.0; - } - else - { - // terrain probe at specified location - XPLMWorldToLocal(loc[0], loc[1], loc[2], &X, &Y, &Z); + pos[0] = DataManager::GetDouble(DREF_Latitude, aircraft); + pos[1] = DataManager::GetDouble(DREF_Longitude, aircraft); + pos[2] = 0.0; } + + MessageHandlers::SendTerr(pos, aircraft); + } + + void MessageHandlers::SendTerr(double pos[3], char aircraft) + { + double lat, lon, alt, X, Y, Z; // Init terrain probe (if required) and probe data struct - XPLMProbeInfo_t probe_data; + static XPLMProbeInfo_t probe_data; probe_data.structSize = sizeof(XPLMProbeInfo_t); if(Terrain_probe == nullptr) { - Log::FormatLine(LOG_TRACE, "GETT", "Create terrain probe for aircraft %u", aircraft); + Log::FormatLine(LOG_TRACE, "TERR", "Create terrain probe for aircraft %u", aircraft); Terrain_probe = XPLMCreateProbe(0); } + // terrain probe at specified location + // Follow the process in the following post to get accurate results + // https://forums.x-plane.org/index.php?/forums/topic/38688-how-do-i-use-xplmprobeterrainxyz/&page=2 + + // transform probe location to local coordinates + // Step 1. Convert lat/lon/0 to XYZ + XPLMWorldToLocal(pos[0], pos[1], pos[2], &X, &Y, &Z); + // query probe + // Step 2. Probe XYZ to get a new Y int rc = XPLMProbeTerrainXYZ(Terrain_probe, X, Y, Z, &probe_data); + if(rc > 0) + { + Log::FormatLine(LOG_ERROR, "TERR", "Probe failed. Return Value %u", rc); + XPLMDestroyProbe(Terrain_probe); + return; + } // transform probe location to world coordinates - double lat; - double lon; - double alt; - + // Step 3. Convert that new XYZ back to LLE + XPLMLocalToWorld(probe_data.locationX, probe_data.locationY, probe_data.locationZ, &lat, &lon, &alt); + Log::FormatLine(LOG_TRACE, "TERR", "Conv LLA=%f, %f, %f", lat, lon, alt); + + // transform probe location to local coordinates + // Step 4. NOW convert your origina lat/lon with the elevation from step 3 to XYZ + XPLMWorldToLocal(pos[0], pos[1], alt, &X, &Y, &Z); + + // query probe + // Step 5. Re-probe with the NEW XYZ + rc = XPLMProbeTerrainXYZ(Terrain_probe, X, Y, Z, &probe_data); if(rc == 0) { + // transform probe location to world coordinates + // Step 6. You now have a new Y, and your XYZ will be closer to correct for high elevations far from the origin. XPLMLocalToWorld(probe_data.locationX, probe_data.locationY, probe_data.locationZ, &lat, &lon, &alt); - Log::FormatLine(LOG_TRACE, "GETT", "Probe LLA %lf %lf %lf", lat, lon, alt); + Log::FormatLine(LOG_TRACE, "TERR", "Probe LLA %lf %lf %lf", lat, lon, alt); } else { @@ -692,31 +713,34 @@ namespace XPC lon = -998; alt = -998; - Log::FormatLine(LOG_TRACE, "GETT", "Probe failed. Return Value %u", rc); + Log::FormatLine(LOG_TRACE, "TERR", "Probe failed. Return Value %u", rc); } - + // keep probe for next query - // XPLMDestroyProbe(probe); + // XPLMDestroyProbe(Terrain_probe); // Assemble response message - unsigned char response[50] = "TERR"; + unsigned char response[62] = "TERR"; response[5] = aircraft; // terrain height over msl at lat/lon point memcpy(response + 6, &lat, 8); memcpy(response + 14, &lon, 8); memcpy(response + 22, &alt, 8); - // terrain incidence + // terrain normal vector memcpy(response + 30, &probe_data.normalX, 4); memcpy(response + 34, &probe_data.normalY, 4); memcpy(response + 38, &probe_data.normalZ, 4); + // terrain velocity + memcpy(response + 42, &probe_data.velocityX, 4); + memcpy(response + 46, &probe_data.velocityY, 4); + memcpy(response + 50, &probe_data.velocityZ, 4); // terrain type - memcpy(response + 42, &probe_data.is_wet, 4); + memcpy(response + 54, &probe_data.is_wet, 4); // probe status - memcpy(response + 46, &rc, 4); - - sock->SendTo(response, 50, &connection.addr); - } + memcpy(response + 58, &rc, 4); + sock->SendTo(response, 62, &connection.addr); + } void MessageHandlers::HandleSimu(const Message& msg) { From 54f5e43ddc7117dc044d39982da2754f6d7d55f8 Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sun, 19 Apr 2020 13:43:55 -0700 Subject: [PATCH 27/50] Revert "Improved accuracy of HandleGetT terrain probe" This reverts commit f630dbdf07b020484f0c3ace6631d5d68deda736. --- xpcPlugin/MessageHandlers.cpp | 88 +++++++++++++---------------------- 1 file changed, 32 insertions(+), 56 deletions(-) diff --git a/xpcPlugin/MessageHandlers.cpp b/xpcPlugin/MessageHandlers.cpp index 453811b5..5163edc4 100644 --- a/xpcPlugin/MessageHandlers.cpp +++ b/xpcPlugin/MessageHandlers.cpp @@ -642,70 +642,49 @@ namespace XPC unsigned char aircraft = buffer[5]; Log::FormatLine(LOG_TRACE, "GETT", "Getting terrain information for aircraft %u", aircraft); - double pos[3]; - memcpy(pos, buffer + 6, 24); + double loc[3]; + double X; + double Y; + double Z; + memcpy(loc, buffer + 6, 24); + if(loc[0] == -998 || loc[1] == -998 || loc[2] == -998) { // get terrain properties at aircraft location - pos[0] = DataManager::GetDouble(DREF_Latitude, aircraft); - pos[1] = DataManager::GetDouble(DREF_Longitude, aircraft); - pos[2] = 0.0; + // probe needs to be below terrain to work... + X = DataManager::GetDouble(DREF_LocalX, aircraft); + Z = DataManager::GetDouble(DREF_LocalZ, aircraft); + Y = -100.0; + } + else + { + // terrain probe at specified location + XPLMWorldToLocal(loc[0], loc[1], loc[2], &X, &Y, &Z); } - - MessageHandlers::SendTerr(pos, aircraft); - } - - void MessageHandlers::SendTerr(double pos[3], char aircraft) - { - double lat, lon, alt, X, Y, Z; // Init terrain probe (if required) and probe data struct - static XPLMProbeInfo_t probe_data; + XPLMProbeInfo_t probe_data; probe_data.structSize = sizeof(XPLMProbeInfo_t); if(Terrain_probe == nullptr) { - Log::FormatLine(LOG_TRACE, "TERR", "Create terrain probe for aircraft %u", aircraft); + Log::FormatLine(LOG_TRACE, "GETT", "Create terrain probe for aircraft %u", aircraft); Terrain_probe = XPLMCreateProbe(0); } - // terrain probe at specified location - // Follow the process in the following post to get accurate results - // https://forums.x-plane.org/index.php?/forums/topic/38688-how-do-i-use-xplmprobeterrainxyz/&page=2 - - // transform probe location to local coordinates - // Step 1. Convert lat/lon/0 to XYZ - XPLMWorldToLocal(pos[0], pos[1], pos[2], &X, &Y, &Z); - // query probe - // Step 2. Probe XYZ to get a new Y int rc = XPLMProbeTerrainXYZ(Terrain_probe, X, Y, Z, &probe_data); - if(rc > 0) - { - Log::FormatLine(LOG_ERROR, "TERR", "Probe failed. Return Value %u", rc); - XPLMDestroyProbe(Terrain_probe); - return; - } // transform probe location to world coordinates - // Step 3. Convert that new XYZ back to LLE - XPLMLocalToWorld(probe_data.locationX, probe_data.locationY, probe_data.locationZ, &lat, &lon, &alt); - Log::FormatLine(LOG_TRACE, "TERR", "Conv LLA=%f, %f, %f", lat, lon, alt); - - // transform probe location to local coordinates - // Step 4. NOW convert your origina lat/lon with the elevation from step 3 to XYZ - XPLMWorldToLocal(pos[0], pos[1], alt, &X, &Y, &Z); - - // query probe - // Step 5. Re-probe with the NEW XYZ - rc = XPLMProbeTerrainXYZ(Terrain_probe, X, Y, Z, &probe_data); + double lat; + double lon; + double alt; + if(rc == 0) { - // transform probe location to world coordinates - // Step 6. You now have a new Y, and your XYZ will be closer to correct for high elevations far from the origin. XPLMLocalToWorld(probe_data.locationX, probe_data.locationY, probe_data.locationZ, &lat, &lon, &alt); - Log::FormatLine(LOG_TRACE, "TERR", "Probe LLA %lf %lf %lf", lat, lon, alt); + Log::FormatLine(LOG_TRACE, "GETT", "Probe LLA %lf %lf %lf", lat, lon, alt); } else { @@ -713,35 +692,32 @@ namespace XPC lon = -998; alt = -998; - Log::FormatLine(LOG_TRACE, "TERR", "Probe failed. Return Value %u", rc); + Log::FormatLine(LOG_TRACE, "GETT", "Probe failed. Return Value %u", rc); } - + // keep probe for next query - // XPLMDestroyProbe(Terrain_probe); + // XPLMDestroyProbe(probe); // Assemble response message - unsigned char response[62] = "TERR"; + unsigned char response[50] = "TERR"; response[5] = aircraft; // terrain height over msl at lat/lon point memcpy(response + 6, &lat, 8); memcpy(response + 14, &lon, 8); memcpy(response + 22, &alt, 8); - // terrain normal vector + // terrain incidence memcpy(response + 30, &probe_data.normalX, 4); memcpy(response + 34, &probe_data.normalY, 4); memcpy(response + 38, &probe_data.normalZ, 4); - // terrain velocity - memcpy(response + 42, &probe_data.velocityX, 4); - memcpy(response + 46, &probe_data.velocityY, 4); - memcpy(response + 50, &probe_data.velocityZ, 4); // terrain type - memcpy(response + 54, &probe_data.is_wet, 4); + memcpy(response + 42, &probe_data.is_wet, 4); // probe status - memcpy(response + 58, &rc, 4); - - sock->SendTo(response, 62, &connection.addr); + memcpy(response + 46, &rc, 4); + + sock->SendTo(response, 50, &connection.addr); } + void MessageHandlers::HandleSimu(const Message& msg) { // Update log From 70b4af90b21177e375ae153a1a5b1459851edb58 Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sun, 19 Apr 2020 13:47:18 -0700 Subject: [PATCH 28/50] Improved accuracy of HandleGetT terrain probe Follow the process in the following post to get accurate results: // https://forums.x-plane.org/index.php?/forums/topic/38688-how-do-i-use-xplmprobeterrainxyz/&page=2 Also added the ground velocity vector to the output. This is used for carrier landing where "ground" is moving. --- xpcPlugin/MessageHandlers.cpp | 89 ++++++++++++++++++++++------------- 1 file changed, 57 insertions(+), 32 deletions(-) diff --git a/xpcPlugin/MessageHandlers.cpp b/xpcPlugin/MessageHandlers.cpp index 5163edc4..c8de4fd1 100644 --- a/xpcPlugin/MessageHandlers.cpp +++ b/xpcPlugin/MessageHandlers.cpp @@ -642,49 +642,71 @@ namespace XPC unsigned char aircraft = buffer[5]; Log::FormatLine(LOG_TRACE, "GETT", "Getting terrain information for aircraft %u", aircraft); - double loc[3]; - double X; - double Y; - double Z; - memcpy(loc, buffer + 6, 24); + double pos[3]; + memcpy(pos, buffer + 6, 24); - if(loc[0] == -998 || loc[1] == -998 || loc[2] == -998) + if(pos[0] == -998 || pos[1] == -998 || pos[2] == -998) { // get terrain properties at aircraft location - // probe needs to be below terrain to work... - X = DataManager::GetDouble(DREF_LocalX, aircraft); - Z = DataManager::GetDouble(DREF_LocalZ, aircraft); - Y = -100.0; - } - else - { - // terrain probe at specified location - XPLMWorldToLocal(loc[0], loc[1], loc[2], &X, &Y, &Z); + pos[0] = DataManager::GetDouble(DREF_Latitude, aircraft); + pos[1] = DataManager::GetDouble(DREF_Longitude, aircraft); + pos[2] = 0.0; } + + MessageHandlers::SendTerr(pos, aircraft); + } + + void MessageHandlers::SendTerr(double pos[3], char aircraft) + { + double lat, lon, alt, X, Y, Z; // Init terrain probe (if required) and probe data struct - XPLMProbeInfo_t probe_data; + static XPLMProbeInfo_t probe_data; probe_data.structSize = sizeof(XPLMProbeInfo_t); if(Terrain_probe == nullptr) { - Log::FormatLine(LOG_TRACE, "GETT", "Create terrain probe for aircraft %u", aircraft); + Log::FormatLine(LOG_TRACE, "TERR", "Create terrain probe for aircraft %u", aircraft); Terrain_probe = XPLMCreateProbe(0); } + // terrain probe at specified location + // Follow the process in the following post to get accurate results + // https://forums.x-plane.org/index.php?/forums/topic/38688-how-do-i-use-xplmprobeterrainxyz/&page=2 + + // transform probe location to local coordinates + // Step 1. Convert lat/lon/0 to XYZ + XPLMWorldToLocal(pos[0], pos[1], pos[2], &X, &Y, &Z); + // query probe + // Step 2. Probe XYZ to get a new Y int rc = XPLMProbeTerrainXYZ(Terrain_probe, X, Y, Z, &probe_data); + if(rc > 0) + { + Log::FormatLine(LOG_ERROR, "TERR", "Probe failed. Return Value %u", rc); + XPLMDestroyProbe(Terrain_probe); + return; + } // transform probe location to world coordinates - double lat; - double lon; - double alt; - + // Step 3. Convert that new XYZ back to LLE + XPLMLocalToWorld(probe_data.locationX, probe_data.locationY, probe_data.locationZ, &lat, &lon, &alt); + Log::FormatLine(LOG_TRACE, "TERR", "Conv LLA=%f, %f, %f", lat, lon, alt); + + // transform probe location to local coordinates + // Step 4. NOW convert your origina lat/lon with the elevation from step 3 to XYZ + XPLMWorldToLocal(pos[0], pos[1], alt, &X, &Y, &Z); + + // query probe + // Step 5. Re-probe with the NEW XYZ + rc = XPLMProbeTerrainXYZ(Terrain_probe, X, Y, Z, &probe_data); if(rc == 0) { + // transform probe location to world coordinates + // Step 6. You now have a new Y, and your XYZ will be closer to correct for high elevations far from the origin. XPLMLocalToWorld(probe_data.locationX, probe_data.locationY, probe_data.locationZ, &lat, &lon, &alt); - Log::FormatLine(LOG_TRACE, "GETT", "Probe LLA %lf %lf %lf", lat, lon, alt); + Log::FormatLine(LOG_TRACE, "TERR", "Probe LLA %lf %lf %lf", lat, lon, alt); } else { @@ -692,31 +714,34 @@ namespace XPC lon = -998; alt = -998; - Log::FormatLine(LOG_TRACE, "GETT", "Probe failed. Return Value %u", rc); + Log::FormatLine(LOG_TRACE, "TERR", "Probe failed. Return Value %u", rc); } - + // keep probe for next query - // XPLMDestroyProbe(probe); + // XPLMDestroyProbe(Terrain_probe); // Assemble response message - unsigned char response[50] = "TERR"; + unsigned char response[62] = "TERR"; response[5] = aircraft; // terrain height over msl at lat/lon point memcpy(response + 6, &lat, 8); memcpy(response + 14, &lon, 8); memcpy(response + 22, &alt, 8); - // terrain incidence + // terrain normal vector memcpy(response + 30, &probe_data.normalX, 4); memcpy(response + 34, &probe_data.normalY, 4); memcpy(response + 38, &probe_data.normalZ, 4); + // terrain velocity + memcpy(response + 42, &probe_data.velocityX, 4); + memcpy(response + 46, &probe_data.velocityY, 4); + memcpy(response + 50, &probe_data.velocityZ, 4); // terrain type - memcpy(response + 42, &probe_data.is_wet, 4); + memcpy(response + 54, &probe_data.is_wet, 4); // probe status - memcpy(response + 46, &rc, 4); - - sock->SendTo(response, 50, &connection.addr); - } + memcpy(response + 58, &rc, 4); + sock->SendTo(response, 62, &connection.addr); + } void MessageHandlers::HandleSimu(const Message& msg) { From c49168d8156deb366304d90bfd62012e558dc6dd Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Fri, 1 May 2020 04:59:43 -0700 Subject: [PATCH 29/50] Improved accuracy of HandleGetT terrain probe and requested changes --- xpcPlugin/MessageHandlers.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xpcPlugin/MessageHandlers.cpp b/xpcPlugin/MessageHandlers.cpp index c8de4fd1..43e90afb 100644 --- a/xpcPlugin/MessageHandlers.cpp +++ b/xpcPlugin/MessageHandlers.cpp @@ -685,6 +685,7 @@ namespace XPC { Log::FormatLine(LOG_ERROR, "TERR", "Probe failed. Return Value %u", rc); XPLMDestroyProbe(Terrain_probe); + Terrain_probe = nullptr; return; } @@ -694,7 +695,7 @@ namespace XPC Log::FormatLine(LOG_TRACE, "TERR", "Conv LLA=%f, %f, %f", lat, lon, alt); // transform probe location to local coordinates - // Step 4. NOW convert your origina lat/lon with the elevation from step 3 to XYZ + // Step 4. NOW convert your original lat/lon with the elevation from step 3 to XYZ XPLMWorldToLocal(pos[0], pos[1], alt, &X, &Y, &Z); // query probe From 6dcbec89746e912097349b98f73e32190d6c6d07 Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Fri, 1 May 2020 05:04:05 -0700 Subject: [PATCH 30/50] Added SendTerr function --- xpcPlugin/MessageHandlers.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/xpcPlugin/MessageHandlers.h b/xpcPlugin/MessageHandlers.h index 096a4b6d..76c8468e 100644 --- a/xpcPlugin/MessageHandlers.h +++ b/xpcPlugin/MessageHandlers.h @@ -57,6 +57,8 @@ namespace XPC static void SetSocket(UDPSocket* socket); static void SendBeacon(const std::string& pluginVersion, unsigned short pluginReceivePort, int xplaneVersion); + + static void SendTerr(double pos[3], char aircraft); private: // One handler per message type. Message types are descripbed on the From 9185424daa5dd82c5ec9cd4acebab22a44d5b055 Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sat, 2 May 2020 10:06:42 -0700 Subject: [PATCH 31/50] Added sendPOST function combining sendPOSI and getTERR --- C/src/xplaneConnect.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/C/src/xplaneConnect.h b/C/src/xplaneConnect.h index 67eafba8..f3c86754 100644 --- a/C/src/xplaneConnect.h +++ b/C/src/xplaneConnect.h @@ -234,6 +234,23 @@ int sendPOSI(XPCSocket sock, double values[], int size, char ac); /// \returns 0 if successful, otherwise a negative value. int getTERR(XPCSocket sock, double posi[3], double values[11], char ac); +/// Sets the position and orientation and gets the terrain information of the specified aircraft. +/// +/// \param sock The socket to use to send the command. +/// \param posi A double array representing position data about the aircraft. The format of values is +/// [Lat, Lon, Alt, Pitch, Roll, Yaw, Gear]. If less than 7 values are specified, +/// the unspecified values will be left unchanged. +/// \param size The number of elements in posi. +/// \param values A double array with the information for the terrain output. The format of values is +/// [Lat, Lon, Alt, Nx, Ny, Nz, Vx, Vy, Vz, wet, result]. The first three are for output of +/// the Lat and Lon of the aircraft with the terrain height directly below. The next three +/// represent the terrain normal. The next three represent the velocity of the terrain. +/// The wet variable is 0.0 if the terrain is dry and 1.0 if wet. +/// The last output is the terrain probe result parameter. +/// \param ac The aircraft number to set the position of. 0 for the main/user's aircraft. +/// \returns 0 if successful, otherwise a negative value. +int sendPOST(XPCSocket sock, double posi[], int size, double values[11], char ac); + // Controls /// Gets the control surface information for the specified aircraft. From 0a50735ebcdb0c93e0432bba6a0807c4406bff8b Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sat, 2 May 2020 10:13:14 -0700 Subject: [PATCH 32/50] Added sendPOST function combining sendPOSI and getTERR --- C/src/xplaneConnect.c | 57 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/C/src/xplaneConnect.c b/C/src/xplaneConnect.c index fdcba8e6..81bfdedb 100755 --- a/C/src/xplaneConnect.c +++ b/C/src/xplaneConnect.c @@ -713,6 +713,63 @@ int getTERR(XPCSocket sock, double posi[3], double values[11], char ac) } return 0; } + +int sendPOST(XPCSocket sock, double posi[], int size, double values[11], char ac) +{ + // Validate input + if (ac < 0 || ac > 20) + { + printError("sendPOST", "aircraft should be a value between 0 and 20."); + return -1; + } + if (size < 1 || size > 7) + { + printError("sendPOST", "size should be a value between 1 and 7."); + return -2; + } + + // Setup command + char buffer[46] = "POST"; + buffer[4] = 0xff; //Placeholder for message length + buffer[5] = ac; + int i; // iterator + + for (i = 0; i < 7; i++) // double for lat/lon/h + { + double val = -998; + + if (i < size) + { + val = posi[i]; + } + if (i < 3) /* lat/lon/h */ + { + memcpy(&buffer[6 + i*8], &val, sizeof(double)); + } + else /* attitude and gear */ + { + float f = (float)val; + memcpy(&buffer[18 + i*4], &f, sizeof(float)); + } + } + + // Send Command + if (sendUDP(sock, buffer, 46) < 0) + { + printError("sendPOST", "Failed to send command"); + return -3; + } + + // Read Response + int result = getTERRResponse(sock, values, ac); + if (result < 0) + { + // A error ocurred while reading the response. + // getTERRResponse will print an error message, so just return. + return result; + } + return 0; +} /*****************************************************************************/ /**** End TERR functions ****/ /*****************************************************************************/ From 0473b5ea231f8cf6a9a97db5787fdfb805852c2b Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sat, 2 May 2020 13:58:50 -0700 Subject: [PATCH 33/50] Added HandlePosT function --- xpcPlugin/MessageHandlers.h | 1 + 1 file changed, 1 insertion(+) diff --git a/xpcPlugin/MessageHandlers.h b/xpcPlugin/MessageHandlers.h index 76c8468e..d360286a 100644 --- a/xpcPlugin/MessageHandlers.h +++ b/xpcPlugin/MessageHandlers.h @@ -76,6 +76,7 @@ namespace XPC static void HandleWypt(const Message& msg); static void HandleView(const Message& msg); static void HandleGetT(const Message& msg); + static void HandlePosT(const Message& msg); static void HandleXPlaneData(const Message& msg); static void HandleUnknown(const Message& msg); From 9869a448d8c90f263b378d4343617dc27786ec4a Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sat, 2 May 2020 14:07:10 -0700 Subject: [PATCH 34/50] Added HandlePosT function that combines HandlePosi with HandleGetT --- xpcPlugin/MessageHandlers.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/xpcPlugin/MessageHandlers.cpp b/xpcPlugin/MessageHandlers.cpp index 43e90afb..0008f8f3 100644 --- a/xpcPlugin/MessageHandlers.cpp +++ b/xpcPlugin/MessageHandlers.cpp @@ -70,6 +70,7 @@ namespace XPC handlers.insert(std::make_pair("GETC", MessageHandlers::HandleGetC)); handlers.insert(std::make_pair("GETP", MessageHandlers::HandleGetP)); handlers.insert(std::make_pair("GETT", MessageHandlers::HandleGetT)); + handlers.insert(std::make_pair("POST", MessageHandlers::HandlePosT)); // X-Plane data messages handlers.insert(std::make_pair("DSEL", MessageHandlers::HandleXPlaneData)); handlers.insert(std::make_pair("USEL", MessageHandlers::HandleXPlaneData)); @@ -630,6 +631,21 @@ namespace XPC } } + void MessageHandlers::HandlePosT(const Message& msg) + { + MessageHandlers::HandlePosi(msg); + + const unsigned char* buffer = msg.GetBuffer(); + char aircraftNumber = buffer[5]; + Log::FormatLine(LOG_TRACE, "POST", "Getting terrain information for aircraft %u", aircraftNumber); + + double pos[3]; + pos[0] = DataManager::GetDouble(DREF_Latitude, aircraftNumber); + pos[1] = DataManager::GetDouble(DREF_Longitude, aircraftNumber); + pos[2] = 0.0; + MessageHandlers::SendTerr(pos, aircraftNumber); + } + void MessageHandlers::HandleGetT(const Message& msg) { const unsigned char* buffer = msg.GetBuffer(); From 2d3e9ccc243357f30f76c417f3e9fbaeb2ea457a Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sat, 2 May 2020 14:10:37 -0700 Subject: [PATCH 35/50] Added handling of the POST message --- xpcPlugin/Message.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xpcPlugin/Message.cpp b/xpcPlugin/Message.cpp index c1eb4483..3dcaf3bb 100644 --- a/xpcPlugin/Message.cpp +++ b/xpcPlugin/Message.cpp @@ -138,7 +138,7 @@ namespace XPC cur += 1 + buffer[cur]; } } - else if (head == "POSI") + else if (head == "POSI" || head == "POST") { char aircraft = buffer[5]; float gear; From 9b6d0986be7fab9c967d0105de09b6c903a44a65 Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sat, 2 May 2020 14:33:21 -0700 Subject: [PATCH 36/50] Added sendPOST function combining functions of sendPOSI and getTERR --- C/src/xplaneConnect.h | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/C/src/xplaneConnect.h b/C/src/xplaneConnect.h index f3c86754..842a2158 100644 --- a/C/src/xplaneConnect.h +++ b/C/src/xplaneConnect.h @@ -159,7 +159,7 @@ int sendDREF(XPCSocket sock, const char* dref, float values[], int size); /// 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 2D array array containing the values for each dataref to set. +/// \param values A 2D 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. @@ -208,7 +208,7 @@ int getPOSI(XPCSocket sock, double values[7], char ac); /// Sets the position and orientation of the specified aircraft. /// /// \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 +/// \param values A double array representing position data about the aircraft. The format of values is /// [Lat, Lon, Alt, Pitch, Roll, Yaw, Gear]. If less than 7 values are specified, /// the unspecified values will be left unchanged. /// \param size The number of elements in values. @@ -218,38 +218,38 @@ int sendPOSI(XPCSocket sock, double values[], int size, char ac); // Terrain -/// Gets the terrain information of the specified aircraft. +/// Sets the position and orientation and gets the terrain information of the specified aircraft. /// /// \param sock The socket to use to send the command. /// \param posi A double array representing position data about the aircraft. The format of values is -/// [Lat, Lon, Alt]. -/// -998 used for [Lat, Lon, Alt] to request terrain info at the current aircraft position. +/// [Lat, Lon, Alt, Pitch, Roll, Yaw, Gear]. If less than 7 values are specified, +/// the unspecified values will be left unchanged. +/// \param size The number of elements in posi. /// \param values A double array with the information for the terrain output. The format of values is /// [Lat, Lon, Alt, Nx, Ny, Nz, Vx, Vy, Vz, wet, result]. The first three are for output of /// the Lat and Lon of the aircraft with the terrain height directly below. The next three /// represent the terrain normal. The next three represent the velocity of the terrain. /// The wet variable is 0.0 if the terrain is dry and 1.0 if wet. /// The last output is the terrain probe result parameter. -/// \param ac The aircraft number to get the terrain data of. 0 for the main/user's aircraft. +/// \param ac The aircraft number to set the position of. 0 for the main/user's aircraft. /// \returns 0 if successful, otherwise a negative value. -int getTERR(XPCSocket sock, double posi[3], double values[11], char ac); +int sendPOST(XPCSocket sock, double posi[], int size, double values[11], char ac); -/// Sets the position and orientation and gets the terrain information of the specified aircraft. +/// Gets the terrain information of the specified aircraft. /// /// \param sock The socket to use to send the command. /// \param posi A double array representing position data about the aircraft. The format of values is -/// [Lat, Lon, Alt, Pitch, Roll, Yaw, Gear]. If less than 7 values are specified, -/// the unspecified values will be left unchanged. -/// \param size The number of elements in posi. +/// [Lat, Lon, Alt]. +/// -998 used for [Lat, Lon, Alt] to request terrain info at the current aircraft position. /// \param values A double array with the information for the terrain output. The format of values is /// [Lat, Lon, Alt, Nx, Ny, Nz, Vx, Vy, Vz, wet, result]. The first three are for output of /// the Lat and Lon of the aircraft with the terrain height directly below. The next three /// represent the terrain normal. The next three represent the velocity of the terrain. /// The wet variable is 0.0 if the terrain is dry and 1.0 if wet. /// The last output is the terrain probe result parameter. -/// \param ac The aircraft number to set the position of. 0 for the main/user's aircraft. +/// \param ac The aircraft number to get the terrain data of. 0 for the main/user's aircraft. /// \returns 0 if successful, otherwise a negative value. -int sendPOST(XPCSocket sock, double posi[], int size, double values[11], char ac); +int getTERR(XPCSocket sock, double posi[3], double values[11], char ac); // Controls From be4e799f8df5c1da27c0ded206455a4ec4e32901 Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sat, 2 May 2020 14:38:48 -0700 Subject: [PATCH 37/50] Added sendPOST function combining functions of sendPOSI and getTERR --- C/src/xplaneConnect.c | 44 +++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/C/src/xplaneConnect.c b/C/src/xplaneConnect.c index 81bfdedb..d48ac02e 100755 --- a/C/src/xplaneConnect.c +++ b/C/src/xplaneConnect.c @@ -692,28 +692,6 @@ int getTERRResponse(XPCSocket sock, double values[11], char ac) return 0; } -int getTERR(XPCSocket sock, double posi[3], double values[11], char ac) -{ - // Send Command - int result = sendTERRRequest(sock, posi, ac); - if (result < 0) - { - // An error ocurred while sending. - // sendTERRRequest will print an error message, so just return. - return result; - } - - // Read Response - result = getTERRResponse(sock, values, ac); - if (result < 0) - { - // An error ocurred while reading the response. - // getTERRResponse will print an error message, so just return. - return result; - } - return 0; -} - int sendPOST(XPCSocket sock, double posi[], int size, double values[11], char ac) { // Validate input @@ -770,6 +748,28 @@ int sendPOST(XPCSocket sock, double posi[], int size, double values[11], char ac } return 0; } + +int getTERR(XPCSocket sock, double posi[3], double values[11], char ac) +{ + // Send Command + int result = sendTERRRequest(sock, posi, ac); + if (result < 0) + { + // An error ocurred while sending. + // sendTERRRequest will print an error message, so just return. + return result; + } + + // Read Response + result = getTERRResponse(sock, values, ac); + if (result < 0) + { + // An error ocurred while reading the response. + // getTERRResponse will print an error message, so just return. + return result; + } + return 0; +} /*****************************************************************************/ /**** End TERR functions ****/ /*****************************************************************************/ From 26d85f755f65fdb9d6949c132fc62b2c43a7b06f Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sat, 2 May 2020 14:45:15 -0700 Subject: [PATCH 38/50] Added HandlePosT function that combines functions of HandlePosi with HandleGetT --- xpcPlugin/MessageHandlers.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xpcPlugin/MessageHandlers.cpp b/xpcPlugin/MessageHandlers.cpp index 0008f8f3..9e5c799c 100644 --- a/xpcPlugin/MessageHandlers.cpp +++ b/xpcPlugin/MessageHandlers.cpp @@ -63,6 +63,7 @@ namespace XPC handlers.insert(std::make_pair("DREF", MessageHandlers::HandleDref)); handlers.insert(std::make_pair("GETD", MessageHandlers::HandleGetD)); handlers.insert(std::make_pair("POSI", MessageHandlers::HandlePosi)); + handlers.insert(std::make_pair("POST", MessageHandlers::HandlePosT)); handlers.insert(std::make_pair("SIMU", MessageHandlers::HandleSimu)); handlers.insert(std::make_pair("TEXT", MessageHandlers::HandleText)); handlers.insert(std::make_pair("WYPT", MessageHandlers::HandleWypt)); @@ -70,7 +71,6 @@ namespace XPC handlers.insert(std::make_pair("GETC", MessageHandlers::HandleGetC)); handlers.insert(std::make_pair("GETP", MessageHandlers::HandleGetP)); handlers.insert(std::make_pair("GETT", MessageHandlers::HandleGetT)); - handlers.insert(std::make_pair("POST", MessageHandlers::HandlePosT)); // X-Plane data messages handlers.insert(std::make_pair("DSEL", MessageHandlers::HandleXPlaneData)); handlers.insert(std::make_pair("USEL", MessageHandlers::HandleXPlaneData)); From 6120869c2ce867e99321c2167dbd4324de150d27 Mon Sep 17 00:00:00 2001 From: Norman Princen <63923352+NPrincen@users.noreply.github.com> Date: Sat, 2 May 2020 14:46:46 -0700 Subject: [PATCH 39/50] Added HandlePosT function that combines functions of HandlePosi with HandleGetT --- xpcPlugin/MessageHandlers.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xpcPlugin/MessageHandlers.h b/xpcPlugin/MessageHandlers.h index d360286a..ee394922 100644 --- a/xpcPlugin/MessageHandlers.h +++ b/xpcPlugin/MessageHandlers.h @@ -70,13 +70,13 @@ namespace XPC static void HandleGetC(const Message& msg); static void HandleGetD(const Message& msg); static void HandleGetP(const Message& msg); + static void HandleGetT(const Message& msg); static void HandlePosi(const Message& msg); + static void HandlePosT(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 HandleGetT(const Message& msg); - static void HandlePosT(const Message& msg); static void HandleXPlaneData(const Message& msg); static void HandleUnknown(const Message& msg); From 581675818b32d660bed6933102632e9f63292fde Mon Sep 17 00:00:00 2001 From: Norman Princen Date: Tue, 12 May 2020 09:57:38 -0700 Subject: [PATCH 40/50] Minimize sendUDP and readUDP Socket Timeout Delays sendUDP and readUDP were using longer than necessary socket timeouts that may add to process time delay and stuttering. They were also using different values between Window and Linux/Mac. The timeouts are now standardized for all versions. --- C/src/xplaneConnect.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/C/src/xplaneConnect.c b/C/src/xplaneConnect.c index d48ac02e..11cc6a81 100755 --- a/C/src/xplaneConnect.c +++ b/C/src/xplaneConnect.c @@ -117,13 +117,16 @@ XPCSocket aopenUDP(const char *xpIP, unsigned short xpPort, unsigned short port) exit(EXIT_FAILURE); } - // Set timeout to 100ms + // Set socket timeout period for sendUDP to 1 millisecond + // Without this, playback may become choppy due to process blocking #ifdef _WIN32 - DWORD timeout = 100; + // Minimum socket timeout in Windows is 1 millisecond (0 makes it blocking) + DWORD timeout = 1; #else + // Set socket timeout to 1 millisecond = 1,000 microseconds to make it the same as Windows (0 makes it blocking) struct timeval timeout; timeout.tv_sec = 0; - timeout.tv_usec = 250000; + timeout.tv_usec = 1000; #endif if (setsockopt(sock.sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)) < 0) { @@ -188,13 +191,13 @@ int sendUDP(XPCSocket sock, char buffer[], int len) /// \returns If an error occurs, a negative number. Otherwise, the number of bytes read. int readUDP(XPCSocket sock, char buffer[], int len) { -#ifdef _WIN32 - // Windows readUDP needs the select command- minimum timeout is 1ms. - // Without this playback becomes choppy + // For readUDP, use the select command - minimum timeout of 0 makes it polling. + // Without this, playback may become choppy due to process blocking // Definitions FD_SET stReadFDS; FD_SET stExceptFDS; + struct timeval tv; // Setup for Select FD_ZERO(&stReadFDS); @@ -202,9 +205,10 @@ int readUDP(XPCSocket sock, char buffer[], int len) FD_ZERO(&stExceptFDS); FD_SET(sock.sock, &stExceptFDS); - struct timeval tv; + // Set timeout period for select to 0.05 sec = 50 milliseconds = 50,000 microseconds (0 makes it polling) + // TO DO - This could be set to 0 if a message handling system were implemented, like in the plugin. tv.tv_sec = 0; - tv.tv_usec = 100000; + tv.tv_usec = 50000; // Select Command int status = select(-1, &stReadFDS, (FD_SET*)0, &stExceptFDS, &tv); @@ -218,11 +222,9 @@ int readUDP(XPCSocket sock, char buffer[], int len) // No data return 0; } + + // If no error: Read Data status = recv(sock.sock, buffer, len, 0); -#else - // For apple or linux-just read - will timeout in 0.5 ms - int status = (int)recv(sock.sock, buffer, len, 0); -#endif if (status < 0) { printError("readUDP", "Error reading socket"); From d2486dd73b95f0130c095734794a1fa7ce707874 Mon Sep 17 00:00:00 2001 From: Norman Princen Date: Tue, 12 May 2020 10:25:01 -0700 Subject: [PATCH 41/50] Minimize SendTo and Read Socket Timeout Delays SendTo and Read were using longer than necessary socket timeouts that may add to process time delay and stuttering. They were also using different values between Window and Linux/Mac. The timeouts are now standardized for all versions and coded in the same manner as the xplaneConnect.c functions. --- xpcPlugin/UDPSocket.cpp | 54 ++++++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 20 deletions(-) diff --git a/xpcPlugin/UDPSocket.cpp b/xpcPlugin/UDPSocket.cpp index 6eaf3e11..440a6a6b 100644 --- a/xpcPlugin/UDPSocket.cpp +++ b/xpcPlugin/UDPSocket.cpp @@ -56,22 +56,25 @@ namespace XPC return; } - // Set Timout - int usTimeOut = 500; - + // Set timeout period for SendTo to 1 millisecond + // Without this, playback may become choppy due to process blocking #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) + // Minimum socket timeout in Windows is 1 millisecond (0 makes it blocking) + DWORD timeout = 1; +#else + struct timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = 1000; +#endif + if (setsockopt(this->sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)) < 0) { +#ifdef _WIN32 int err = WSAGetLastError(); Log::FormatLine(LOG_ERROR, tag, "ERROR: Failed to set timeout. (Error code %i)", err); - } #else - struct timeval tv; - tv.tv_sec = 0; - tv.tv_usec = usTimeOut; - setsockopt(this->sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval)); + Log::WriteLine(LOG_ERROR, tag, "ERROR: Failed to set timeout."); #endif + } } UDPSocket::~UDPSocket() @@ -87,11 +90,9 @@ namespace XPC int UDPSocket::Read(unsigned char* dst, int maxLen, sockaddr* recvAddr) const { socklen_t recvaddrlen = sizeof(*recvAddr); - int status = 0; -#ifdef _WIN32 - // Windows readUDP needs the select command- minimum timeout is 1ms. - // Without this playback becomes choppy + // For Read, use the select command - minimum timeout of 0 makes it polling. + // Without this, playback may become choppy due to process blocking // Definitions FD_SET stReadFDS; @@ -103,27 +104,40 @@ namespace XPC FD_SET(sock, &stReadFDS); FD_ZERO(&stExceptFDS); FD_SET(sock, &stExceptFDS); + + // Set timeout period for select to 0 to poll the socket tv.tv_sec = 0; - tv.tv_usec = 250; + tv.tv_usec = 0; // Select Command - int result = select(-1, &stReadFDS, (FD_SET *)0, &stExceptFDS, &tv); - if (result == SOCKET_ERROR) + int status = select(-1, &stReadFDS, (FD_SET *)0, &stExceptFDS, &tv); + if (status < 0) { +#ifdef _WIN32 int err = WSAGetLastError(); Log::FormatLine(LOG_ERROR, tag, "ERROR: Select failed. (Error code %i)", err); +#else + Log::WriteLine(LOG_ERROR, tag, "ERROR: Select failed."); +#endif + return -1; } - if (result <= 0) // No Data or error + if (result == 0) { + // No data return -1; } // If no error: Read Data status = recvfrom(sock, (char*)dst, maxLen, 0, recvAddr, &recvaddrlen); + if (status < 0) + { +#ifdef _WIN32 + int err = WSAGetLastError(); + Log::FormatLine(LOG_ERROR, tag, "ERROR: Receive failed. (Error code %i)", err); #else - // For apple or linux-just read - will timeout in 0.5 ms - status = (int)recvfrom(sock, dst, 5000, 0, recvAddr, &recvaddrlen); + Log::WriteLine(LOG_ERROR, tag, "ERROR: Receive failed."); #endif + } return status; } From 138c738ba07f89782971aa4f44713129305a6879 Mon Sep 17 00:00:00 2001 From: Norman Princen Date: Tue, 12 May 2020 12:23:07 -0700 Subject: [PATCH 42/50] Minimize SendTo and Read Socket Timeout Delays SendTo and Read were using longer than necessary socket timeouts that may add to process time delay and stuttering. They were also using different values between Window and Linux/Mac. The timeouts are now standardized for all versions and coded in the same manner as the xplaneConnect.c functions. --- xpcPlugin/UDPSocket.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xpcPlugin/UDPSocket.cpp b/xpcPlugin/UDPSocket.cpp index 440a6a6b..110bceaa 100644 --- a/xpcPlugin/UDPSocket.cpp +++ b/xpcPlugin/UDPSocket.cpp @@ -121,7 +121,7 @@ namespace XPC #endif return -1; } - if (result == 0) + if (status == 0) { // No data return -1; From 121b3c92f87dcfcd191cd7b6d41864b72a4baa32 Mon Sep 17 00:00:00 2001 From: Norman Princen Date: Tue, 12 May 2020 13:15:38 -0700 Subject: [PATCH 43/50] Include sys/select.h for Linux and Mac --- xpcPlugin/UDPSocket.h | 1 + 1 file changed, 1 insertion(+) diff --git a/xpcPlugin/UDPSocket.h b/xpcPlugin/UDPSocket.h index a1ee920a..398d8eab 100644 --- a/xpcPlugin/UDPSocket.h +++ b/xpcPlugin/UDPSocket.h @@ -14,6 +14,7 @@ #include #include #include +#include #endif From e2a6820d341b7e9e74bb8c1e4994716da5b435f6 Mon Sep 17 00:00:00 2001 From: Norman Princen Date: Tue, 12 May 2020 13:18:47 -0700 Subject: [PATCH 44/50] Minimize SendTo and Read Socket Timeout Delays SendTo and Read were using longer than necessary socket timeouts that may add to process time delay and stuttering. They were also using different values between Window and Linux/Mac. The timeouts are now standardized for all versions and coded in the same manner as the xplaneConnect.c functions. --- xpcPlugin/UDPSocket.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xpcPlugin/UDPSocket.cpp b/xpcPlugin/UDPSocket.cpp index 110bceaa..9defeb05 100644 --- a/xpcPlugin/UDPSocket.cpp +++ b/xpcPlugin/UDPSocket.cpp @@ -110,7 +110,7 @@ namespace XPC tv.tv_usec = 0; // Select Command - int status = select(-1, &stReadFDS, (FD_SET *)0, &stExceptFDS, &tv); + int status = select(-1, &stReadFDS, (FD_SET*)0, &stExceptFDS, &tv); if (status < 0) { #ifdef _WIN32 From bb16ab9d94d2afcc6dd6231482340ebea77ba8fe Mon Sep 17 00:00:00 2001 From: Norman Princen Date: Tue, 12 May 2020 13:25:10 -0700 Subject: [PATCH 45/50] Added includes for Linux and Mac socket select functions --- xpcPlugin/UDPSocket.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xpcPlugin/UDPSocket.h b/xpcPlugin/UDPSocket.h index 398d8eab..ea869307 100644 --- a/xpcPlugin/UDPSocket.h +++ b/xpcPlugin/UDPSocket.h @@ -13,8 +13,9 @@ #include #include #include +#include +#include #include -#include #endif From 4241599ad772268831ef652de753b2a5c2711207 Mon Sep 17 00:00:00 2001 From: Norman Princen Date: Tue, 12 May 2020 18:58:29 -0700 Subject: [PATCH 46/50] Minimize sendUDP and readUDP Socket Timeout Delays sendUDP and readUDP were using longer than necessary socket timeouts that may add to process time delay and stuttering. They were also using different values between Window and Linux/Mac. The timeouts are now standardized for all versions. --- C/src/xplaneConnect.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/C/src/xplaneConnect.c b/C/src/xplaneConnect.c index 11cc6a81..208ed7ff 100755 --- a/C/src/xplaneConnect.c +++ b/C/src/xplaneConnect.c @@ -195,9 +195,9 @@ int readUDP(XPCSocket sock, char buffer[], int len) // Without this, playback may become choppy due to process blocking // Definitions - FD_SET stReadFDS; - FD_SET stExceptFDS; - struct timeval tv; + fd_set stReadFDS; + fd_set stExceptFDS; + struct timeval timeout; // Setup for Select FD_ZERO(&stReadFDS); @@ -207,11 +207,11 @@ int readUDP(XPCSocket sock, char buffer[], int len) // Set timeout period for select to 0.05 sec = 50 milliseconds = 50,000 microseconds (0 makes it polling) // TO DO - This could be set to 0 if a message handling system were implemented, like in the plugin. - tv.tv_sec = 0; - tv.tv_usec = 50000; + timeout.tv_sec = 0; + timeout.tv_usec = 50000; // Select Command - int status = select(-1, &stReadFDS, (FD_SET*)0, &stExceptFDS, &tv); + int status = select(sock.sock+1, &stReadFDS, NULL, &stExceptFDS, &timeout); if (status < 0) { printError("readUDP", "Select command error"); From 1f78a23351faebc85fe7f82ddcd92a329852792a Mon Sep 17 00:00:00 2001 From: Norman Princen Date: Tue, 12 May 2020 19:06:28 -0700 Subject: [PATCH 47/50] Minimize SendTo and Read Socket Timeout Delays SendTo and Read were using longer than necessary socket timeouts that may add to process time delay and stuttering. They were also using different values between Window and Linux/Mac. The timeouts are now standardized for all versions and coded in the same manner as the xplaneConnect.c functions. --- xpcPlugin/UDPSocket.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/xpcPlugin/UDPSocket.cpp b/xpcPlugin/UDPSocket.cpp index 9defeb05..5925ebe3 100644 --- a/xpcPlugin/UDPSocket.cpp +++ b/xpcPlugin/UDPSocket.cpp @@ -95,9 +95,9 @@ namespace XPC // Without this, playback may become choppy due to process blocking // Definitions - FD_SET stReadFDS; - FD_SET stExceptFDS; - timeval tv; + fd_set stReadFDS; + fd_set stExceptFDS; + struct timeval timeout; // Setup for Select FD_ZERO(&stReadFDS); @@ -106,11 +106,11 @@ namespace XPC FD_SET(sock, &stExceptFDS); // Set timeout period for select to 0 to poll the socket - tv.tv_sec = 0; - tv.tv_usec = 0; + timeout.tv_sec = 0; + timeout.tv_usec = 0; // Select Command - int status = select(-1, &stReadFDS, (FD_SET*)0, &stExceptFDS, &tv); + int status = select(sock+1, &stReadFDS, NULL, &stExceptFDS, &timeout); if (status < 0) { #ifdef _WIN32 From 49dc454222a223c35091a90ac0b931c8e7ef30f4 Mon Sep 17 00:00:00 2001 From: harrisonhall Date: Thu, 28 May 2020 18:25:11 -0400 Subject: [PATCH 48/50] python3 integer division issue --- Python3/src/xpc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python3/src/xpc.py b/Python3/src/xpc.py index 9c85942e..c7f5ec97 100644 --- a/Python3/src/xpc.py +++ b/Python3/src/xpc.py @@ -120,7 +120,7 @@ def readDATA(self): buffer = self.readUDP() if len(buffer) < 6: return None - rows = (len(buffer) - 5) / 36 + rows = (len(buffer) - 5) // 36 data = [] for i in range(rows): data.append(struct.unpack_from(b"9f", buffer, 5 + 36*i)) From 388329b21804fabe12ea577ff1642583776eca59 Mon Sep 17 00:00:00 2001 From: Sander Datema Date: Sat, 27 Jun 2020 21:14:42 +0200 Subject: [PATCH 49/50] Add support for sendCOMM method Credits go to user @angelsware, I just did a copy/paste from #120 --- C/src/xplaneConnect.c | 37 +++++ C/src/xplaneConnect.h | 7 + Java/src/XPlaneConnect.java | 36 +++++ Python/src/xpc.py | 129 +++++++++++------- xpcPlugin/DataManager.cpp | 16 +++ xpcPlugin/DataManager.h | 5 + xpcPlugin/Message.cpp | 5 + xpcPlugin/MessageHandlers.cpp | 26 ++++ xpcPlugin/MessageHandlers.h | 1 + xpcPlugin/xpcPlugin.xcodeproj/project.pbxproj | 2 + 10 files changed, 211 insertions(+), 53 deletions(-) diff --git a/C/src/xplaneConnect.c b/C/src/xplaneConnect.c index 208ed7ff..f1da9673 100755 --- a/C/src/xplaneConnect.c +++ b/C/src/xplaneConnect.c @@ -973,3 +973,40 @@ int sendVIEW(XPCSocket sock, VIEW_TYPE view) /*****************************************************************************/ /**** End View functions ****/ /*****************************************************************************/ + +/*****************************************************************************/ +/**** Comm functions ****/ +/*****************************************************************************/ +int sendCOMM(XPCSocket sock, const char* comm) { + // Setup command + // Max size is technically unlimited. + unsigned char buffer[65536] = "COMM"; + int pos = 5; + + int commLen = strnlen(comm, 256); + if (pos + commLen + 2 > 65536) + { + printError("sendCOMM", "About to overrun the send buffer!"); + return -4; + } + if (commLen > 255) + { + printError("sendCOMM", "comm is too long. Must be less than 256 characters."); + return -1; + } + // Copy comm to buffer + buffer[pos++] = (unsigned char)commLen; + memcpy(buffer + pos, comm, commLen); + pos += commLen; + + // Send command + if (sendUDP(sock, buffer, pos) < 0) + { + printError("setDREF", "Failed to send command"); + return -3; + } + return 0; +} +/*****************************************************************************/ +/**** End Comm functions ****/ +/*****************************************************************************/ \ No newline at end of file diff --git a/C/src/xplaneConnect.h b/C/src/xplaneConnect.h index 842a2158..3dcf2363 100644 --- a/C/src/xplaneConnect.h +++ b/C/src/xplaneConnect.h @@ -303,6 +303,13 @@ int sendVIEW(XPCSocket sock, VIEW_TYPE view); /// \returns 0 if successful, otherwise a negative value. int sendWYPT(XPCSocket sock, WYPT_OP op, float points[], int count); +/// Sends commands. +/// +/// \param sock The socket to use to send the command. +/// \param comm The command string. +/// \returns 0 if successful, otherwise a negative value. +int sendCOMM(XPCSocket sock, const char* comm); + #ifdef __cplusplus } #endif diff --git a/Java/src/XPlaneConnect.java b/Java/src/XPlaneConnect.java index 675da9bf..df32cffb 100644 --- a/Java/src/XPlaneConnect.java +++ b/Java/src/XPlaneConnect.java @@ -889,6 +889,42 @@ public void sendWYPT(WaypointOp op, float[] points) throws IOException sendUDP(os.toByteArray()); } + /** + * Send a command to X-Plane. + * + * @param comm The name of the X-Plane command to send. + * @throws IOException If the command cannot be sent. + */ + public void sendCOMM(String comm) throws IOException + { + //Preconditions + if(comm == null || comm.length() == 0) + { + throw new IllegalArgumentException(("comm must be non-empty.")); + } + + ByteArrayOutputStream os = new ByteArrayOutputStream(); + os.write("COMM".getBytes(StandardCharsets.UTF_8)); + os.write(0xFF); //Placeholder for message length + + //Convert comm to bytes. + byte[] commBytes = comm.getBytes(StandardCharsets.UTF_8); + if (commBytes.length == 0) + { + throw new IllegalArgumentException("COMM is an empty string!"); + } + if (commBytes.length > 255) + { + throw new IllegalArgumentException("comm must be less than 255 bytes in UTF-8. Are you sure this is a valid comm?"); + } + + //Build and send message + os.write(commBytes.length); + os.write(commBytes); + sendUDP(os.toByteArray()); + } + + /** * Sets the port on which the client will receive data from X-Plane. * diff --git a/Python/src/xpc.py b/Python/src/xpc.py index 71b7eb2a..7a6f9260 100644 --- a/Python/src/xpc.py +++ b/Python/src/xpc.py @@ -1,20 +1,22 @@ import socket import struct + class XPlaneConnect(object): - '''XPlaneConnect (XPC) facilitates communication to and from the XPCPlugin.''' + """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. + 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 @@ -51,59 +53,59 @@ def __exit__(self, type, value, traceback): self.close() def close(self): - '''Closes the specified connection and releases resources associated with it.''' + """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.''' + """Sends a message over the underlying UDP socket.""" # Preconditions - if(len(buffer) == 0): + 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.''' + """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. + """Sets the port on which the client sends and receives data. Args: port: The new port to use. - ''' - #Validate parameters + """ + # Validate parameters if port < 0 or port > 65535: raise ValueError("The specified port is not a valid port number.") - #Send command + # Send command buffer = struct.pack("<4sxH", "CONN", port) self.sendUDP(buffer) - #Rebind socket + # Rebind socket clientAddr = ("0.0.0.0", port) - timeout = self.socket.gettimeout(); - self.socket.close(); + 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 + # Read response buffer = self.socket.recv(1024) def pauseSim(self, pause): - '''Pauses or un-pauses the physics simulation engine in X-Plane. + """Pauses or un-pauses the physics simulation engine in X-Plane. Args: pause: True to pause the simulation for all a/c; False to resume for all a/c. 2 to switch the status for all a/c. 100:119 to pause a/c 0:19. 200:219 to resume a/c 0:19 - ''' + """ pause = int(pause) - if pause < 0 or (pause > 2 and pause < 100) or (pause > 119 and pause < 200) or pause > 219 : + if pause < 0 or (pause > 2 and pause < 100) or (pause > 119 and pause < 200) or pause > 219: raise ValueError("Invalid argument for pause command.") buffer = struct.pack("<4sxB", "SIMU", pause) @@ -111,30 +113,30 @@ def pauseSim(self, pause): # X-Plane UDP Data def readDATA(self): - '''Reads X-Plane data. + """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(); + """ + 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)) + 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. + """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.") @@ -146,12 +148,12 @@ def sendDATA(self, data): self.sendUDP(buffer) # Position - def getPOSI(self, ac = 0): - '''Gets position information for the specified aircraft. + 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) @@ -168,8 +170,8 @@ def getPOSI(self, ac = 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. + 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 @@ -184,7 +186,7 @@ def sendPOSI(self, values, ac = 0): * 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.") @@ -204,12 +206,12 @@ def sendPOSI(self, values, ac = 0): self.sendUDP(buffer) # Controls - def getCTRL(self, ac = 0): - '''Gets the control surface information for the specified aircraft. + 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) @@ -224,11 +226,11 @@ def getCTRL(self, ac = 0): raise ValueError("Unexpected header: " + result[0]) # Drop the header from the return value - result =result[1:7] + result[8:] + result = result[1:7] + result[8:] return result - def sendCTRL(self, values, ac = 0): - '''Sets control surface information on the specified aircraft. + 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 @@ -243,7 +245,7 @@ def sendCTRL(self, values, ac = 0): * 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.") @@ -270,21 +272,21 @@ def sendCTRL(self, values, ac = 0): # DREF Manipulation def sendDREF(self, dref, values): - '''Sets the specified dataref to the specified value. + """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. + """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.") @@ -312,24 +314,24 @@ def sendDREFs(self, drefs, values): self.sendUDP(buffer) def getDREF(self, dref): - '''Gets the value of an X-Plane dataref. + """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. + """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: @@ -352,8 +354,8 @@ def getDREFs(self, drefs): return result # Drawing - def sendTEXT(self, msg, x = -1, y = -1): - '''Sets a message that X-Plane will display on the screen. + 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 @@ -363,7 +365,7 @@ def sendTEXT(self, msg, x = -1, y = -1): 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.") @@ -375,12 +377,12 @@ def sendTEXT(self, msg, x = -1, y = -1): self.sendUDP(buffer) def sendVIEW(self, view): - '''Sets the camera view in X-Plane + """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.") @@ -392,7 +394,7 @@ def sendVIEW(self, view): self.sendUDP(buffer) 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 point consists of a latitude and longitude expressed in fractional degrees and an altitude expressed as meters above sea level. @@ -402,7 +404,7 @@ def sendWYPT(self, op, points): `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: @@ -416,6 +418,27 @@ def sendWYPT(self, op, points): buffer = struct.pack("<4sxBB" + str(len(points)) + "f", "WYPT", op, len(points), *points) self.sendUDP(buffer) + def sendCOMM(self, comm): + '''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 comm == None: + raise ValueError("comm must be non-empty.") + + buffer = struct.pack("<4sx", "COMM") + if len(comm) == 0 or len(comm) > 255: + raise ValueError("comm must be a non-empty string less than 256 characters.") + + # Pack message + fmt = " #include @@ -791,6 +792,21 @@ namespace XPC Set(DREF_FlapActual, value); } + void DataManager::Execute(const std::string& comm) + { + Log::FormatLine(LOG_INFO, "DMAN", "Executing command (value:%s)", comm.c_str()); + + XPLMCommandRef xcref = XPLMFindCommand(comm.c_str()); + if (!xcref) + { + // COMM does not exist + Log::FormatLine(LOG_ERROR, "DMAN", "ERROR: invalid COMM %s", comm.c_str()); + return; + } + + XPLMCommandOnce(xcref); + } + float DataManager::GetDefaultValue() { return -998.0F; diff --git a/xpcPlugin/DataManager.h b/xpcPlugin/DataManager.h index 15f12182..27e3a40e 100644 --- a/xpcPlugin/DataManager.h +++ b/xpcPlugin/DataManager.h @@ -410,6 +410,11 @@ namespace XPC /// \param value The flaps settings. Should be between 0.0 (no flaps) and 1.0 (full flaps). static void SetFlaps(float value); + /// Executes a command + /// + /// \param comm The name of the command to execute. + static void Execute(const std::string& comm); + /// Gets a default value that indicates that a dataref should not be changed. static float GetDefaultValue(); diff --git a/xpcPlugin/Message.cpp b/xpcPlugin/Message.cpp index 3dcaf3bb..318cf5e2 100644 --- a/xpcPlugin/Message.cpp +++ b/xpcPlugin/Message.cpp @@ -176,6 +176,11 @@ namespace XPC ss << "Type:" << *((unsigned long*)(buffer + 5)); Log::WriteLine(LOG_DEBUG, "DBUG", ss.str()); } + else if (head == "COMM") + { + ss << "Type:" << *((unsigned long*)(buffer + 5)); + Log::WriteLine(LOG_DEBUG, "DBUG", ss.str()); + } else { ss << " UNKNOWN HEADER "; diff --git a/xpcPlugin/MessageHandlers.cpp b/xpcPlugin/MessageHandlers.cpp index 9e5c799c..5b1d79de 100644 --- a/xpcPlugin/MessageHandlers.cpp +++ b/xpcPlugin/MessageHandlers.cpp @@ -70,6 +70,7 @@ namespace XPC handlers.insert(std::make_pair("VIEW", MessageHandlers::HandleView)); handlers.insert(std::make_pair("GETC", MessageHandlers::HandleGetC)); handlers.insert(std::make_pair("GETP", MessageHandlers::HandleGetP)); + handlers.insert(std::make_pair("COMM", MessageHandlers::HandleComm)); handlers.insert(std::make_pair("GETT", MessageHandlers::HandleGetT)); // X-Plane data messages handlers.insert(std::make_pair("DSEL", MessageHandlers::HandleXPlaneData)); @@ -916,6 +917,31 @@ namespace XPC } } + void MessageHandlers::HandleComm(const Message& msg) + { + Log::FormatLine(LOG_TRACE, "COMM", "Request to execute COMM command received (Conn %i)", connection.id); + const unsigned char* buffer = msg.GetBuffer(); + 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 comm = std::string((char*)buffer + pos, len); + pos += len; + + DataManager::Execute(comm); + Log::FormatLine(LOG_DEBUG, "COMM", "Execute command %s", comm.c_str()); + } + if (pos != size) + { + Log::WriteLine(LOG_ERROR, "COMM", "ERROR: Command did not terminate at the expected position."); + } + } + void MessageHandlers::HandleWypt(const Message& msg) { // Update Log diff --git a/xpcPlugin/MessageHandlers.h b/xpcPlugin/MessageHandlers.h index ee394922..15379c43 100644 --- a/xpcPlugin/MessageHandlers.h +++ b/xpcPlugin/MessageHandlers.h @@ -77,6 +77,7 @@ namespace XPC static void HandleText(const Message& msg); static void HandleWypt(const Message& msg); static void HandleView(const Message& msg); + static void HandleComm(const Message& msg); static void HandleXPlaneData(const Message& msg); static void HandleUnknown(const Message& msg); diff --git a/xpcPlugin/xpcPlugin.xcodeproj/project.pbxproj b/xpcPlugin/xpcPlugin.xcodeproj/project.pbxproj index 9112e869..6af7a97b 100755 --- a/xpcPlugin/xpcPlugin.xcodeproj/project.pbxproj +++ b/xpcPlugin/xpcPlugin.xcodeproj/project.pbxproj @@ -221,6 +221,7 @@ "APL=1", "IBM=0", "LIN=0", + XPLM200, ); GCC_SYMBOLS_PRIVATE_EXTERN = YES; GCC_VERSION = ""; @@ -274,6 +275,7 @@ "APL=1", "IBM=0", "LIN=0", + XPLM200, ); GCC_SYMBOLS_PRIVATE_EXTERN = YES; GCC_VERSION = ""; From 1bc34ed0c5245afc517753d74e7747db5475b5c7 Mon Sep 17 00:00:00 2001 From: Sander Datema Date: Sat, 27 Jun 2020 21:29:19 +0200 Subject: [PATCH 50/50] Revert auto formatting --- Python/src/xpc.py | 110 +++++++++++++++++++++++----------------------- 1 file changed, 54 insertions(+), 56 deletions(-) diff --git a/Python/src/xpc.py b/Python/src/xpc.py index 7a6f9260..4bbf640d 100644 --- a/Python/src/xpc.py +++ b/Python/src/xpc.py @@ -1,22 +1,20 @@ import socket import struct - class XPlaneConnect(object): - """XPlaneConnect (XPC) facilitates communication to and from the XPCPlugin.""" - + '''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. + 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 @@ -53,59 +51,59 @@ def __exit__(self, type, value, traceback): self.close() def close(self): - """Closes the specified connection and releases resources associated with it.""" + '''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.""" + '''Sends a message over the underlying UDP socket.''' # Preconditions - if len(buffer) == 0: + 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.""" + '''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. + '''Sets the port on which the client sends and receives data. Args: port: The new port to use. - """ - # Validate parameters + ''' + #Validate parameters if port < 0 or port > 65535: raise ValueError("The specified port is not a valid port number.") - # Send command + #Send command buffer = struct.pack("<4sxH", "CONN", port) self.sendUDP(buffer) - # Rebind socket + #Rebind socket clientAddr = ("0.0.0.0", port) - timeout = self.socket.gettimeout() - self.socket.close() + 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 + #Read response buffer = self.socket.recv(1024) def pauseSim(self, pause): - """Pauses or un-pauses the physics simulation engine in X-Plane. + '''Pauses or un-pauses the physics simulation engine in X-Plane. Args: pause: True to pause the simulation for all a/c; False to resume for all a/c. 2 to switch the status for all a/c. 100:119 to pause a/c 0:19. 200:219 to resume a/c 0:19 - """ + ''' pause = int(pause) - if pause < 0 or (pause > 2 and pause < 100) or (pause > 119 and pause < 200) or pause > 219: + if pause < 0 or (pause > 2 and pause < 100) or (pause > 119 and pause < 200) or pause > 219 : raise ValueError("Invalid argument for pause command.") buffer = struct.pack("<4sxB", "SIMU", pause) @@ -113,30 +111,30 @@ def pauseSim(self, pause): # X-Plane UDP Data def readDATA(self): - """Reads X-Plane data. + '''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() + ''' + 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)) + 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. + '''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.") @@ -148,12 +146,12 @@ def sendDATA(self, data): self.sendUDP(buffer) # Position - def getPOSI(self, ac=0): - """Gets position information for the specified aircraft. + 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) @@ -170,8 +168,8 @@ def getPOSI(self, ac=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. + 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 @@ -186,7 +184,7 @@ def sendPOSI(self, values, ac=0): * 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.") @@ -206,12 +204,12 @@ def sendPOSI(self, values, ac=0): self.sendUDP(buffer) # Controls - def getCTRL(self, ac=0): - """Gets the control surface information for the specified aircraft. + 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) @@ -226,11 +224,11 @@ def getCTRL(self, ac=0): raise ValueError("Unexpected header: " + result[0]) # Drop the header from the return value - result = result[1:7] + result[8:] + result =result[1:7] + result[8:] return result - def sendCTRL(self, values, ac=0): - """Sets control surface information on the specified aircraft. + 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 @@ -245,7 +243,7 @@ def sendCTRL(self, values, ac=0): * 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.") @@ -272,21 +270,21 @@ def sendCTRL(self, values, ac=0): # DREF Manipulation def sendDREF(self, dref, values): - """Sets the specified dataref to the specified value. + '''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. + '''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.") @@ -314,24 +312,24 @@ def sendDREFs(self, drefs, values): self.sendUDP(buffer) def getDREF(self, dref): - """Gets the value of an X-Plane dataref. + '''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. + '''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: @@ -354,8 +352,8 @@ def getDREFs(self, drefs): return result # Drawing - def sendTEXT(self, msg, x=-1, y=-1): - """Sets a message that X-Plane will display on the screen. + 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 @@ -365,7 +363,7 @@ def sendTEXT(self, msg, x=-1, y=-1): 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.") @@ -377,12 +375,12 @@ def sendTEXT(self, msg, x=-1, y=-1): self.sendUDP(buffer) def sendVIEW(self, view): - """Sets the camera view in X-Plane + '''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.") @@ -394,7 +392,7 @@ def sendVIEW(self, view): self.sendUDP(buffer) 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 point consists of a latitude and longitude expressed in fractional degrees and an altitude expressed as meters above sea level. @@ -404,7 +402,7 @@ def sendWYPT(self, op, points): `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: @@ -438,7 +436,7 @@ def sendCOMM(self, comm): # Send self.sendUDP(buffer) - + class ViewType(object): Forwards = 73 Down = 74