rheitzman Posted February 19, 2014 Report Posted February 19, 2014 Great tool! My BeattlesBlog connection stopped working after I installed P3D and I started looking around for solutions - this one is great! I think I did look at it ages ago via the old FSUIPC VB.Net demo but I think it required treading which is a huge pain. This tool (is there a short name?) seems to do the trick w/o any serious hoop jumping. In the VB.Net code below (VS2013 Express, .Net 4.0, FSX) is a minimal proof of concept of opening a connection on demand and getting the curretn lat/long and closing the connection - seems to work OK. How about garbage collection? This code would run in a "moving map" type tool that would stay open. The app has a button to "Center on the a/c" that gets clicked every once in awhile - it does not try to track the a/c. Can I call GetLatLongString() using the garabge collection code shown - or is it overkill, or? Also - for the latlong class - how to I get a decimal string instead of DDHHMMSS? Thanks! Option Explicit OnImports FSUIPCPublic Class frmACLocation Dim ofsLatitude As Offset(Of Long) = New Offset(Of Long)(&H560) Dim ofsLongitude As Offset(Of Long) = New Offset(Of Long)(&H568) Dim mlat As FsLatitude Dim mlon As FsLongitude Dim mlatlon As New FsLatLonPoint Private Sub btnGetLatLong_Click(sender As Object, e As EventArgs) Handles btnGetLatLong.Click Try MsgBox(GetLatLongString) Catch ex As Exception MsgBox(ex.Message, , "btnGetLatLong_Click") End Try End Sub Function GetLatLongString() As String Try FSUIPCConnection.Open() FSUIPCConnection.Process() mlat = New FsLatitude(ofsLatitude.Value) mlon = New FsLongitude(ofsLongitude.Value) mlatlon = New FsLatLonPoint(mlat, mlon) Return mlatlon.ToString ' how to get decimal lat/lon? FSUIPCConnection.Close() Catch ex As Exception ' Badness occurred - show the error message MsgBox(ex.Message, , "OpenFSUIPC") Return "error" Finally ' cleanup required? ' ofsLatitude = Nothing ' ofsLongitude = Nothing mlat = Nothing mlon = Nothing mlatlon = Nothing End Try End FunctionEnd Class
Paul Henty Posted February 19, 2014 Report Posted February 19, 2014 Hi, You don't need to worry about garbage collection, the .NET framework will take care of everything for you. Your current 'finally' block is overkill and not required. You could improve things a little by declaring mlat, mlon and mlatlon in the method rather than at the class level as they only seem to be used in that method. They only take a up a few bytes however which is insignificant on modern PCs with gigabytes of memory. The only improvement I would advise is to call FSUIPCConnection.Close() at the end of your Catch block. If you don't do this then you might find you'll never be able to open a connection again if you ever get an exception (e.g. if FSX is not running at the time). To show the lat/lon in decimal format, use the ToString() overload that takes the formatting parameters. See the intellisense for details. (If you're not getting the intellisense make sure you have the FSUIPCClient.xml file in the same folder as your FSUIPCClient.dll.) I suggest the following would be what you want but it's quite flexible so you can tweak it to your exact requirements. mlatlon.ToString(False, "d", 6) Here's your code with the suggested changes: Option Explicit On Imports FSUIPC Public Class frmACLocation Dim ofsLatitude As Offset(Of Long) = New Offset(Of Long)(&H560) Dim ofsLongitude As Offset(Of Long) = New Offset(Of Long)(&H568) Private Sub btnGetLatLong_Click(sender As Object, e As EventArgs) Handles btnGetLatLong.Click Try MsgBox(GetLatLongString) Catch ex As Exception MsgBox(ex.Message, , "btnGetLatLong_Click") End Try End Sub Function GetLatLongString() As String Try FSUIPCConnection.Open() FSUIPCConnection.Process() Dim mlat As FsLatitude = New FsLatitude(ofsLatitude.Value) Dim mlon As FsLongitude = New FsLongitude(ofsLongitude.Value) Dim mlatlon As New FsLatLonPoint = New FsLatLonPoint(mlat, mlon) Return mlatlon.ToString(False, "d", 6) FSUIPCConnection.Close() Catch ex As Exception ' Badness occurred - show the error message MsgBox(ex.Message, , "OpenFSUIPC") FSUIPCConnection.Close() Return "error" End Try End Function End Class Paul
rheitzman Posted February 20, 2014 Author Report Posted February 20, 2014 Thanks - here is my modified code. This is a simple one button form that gets the lat/lon from the a/c and offers to open a chart web site. I used your format string but it had some non-numeric'ness to the returned string. I resorted to the deprciated, but handy, Val() to clean it up. The code is verbose, I didn't want to string a bunch of operations together for the post. Is there an elegant way to check to see if Open() was called and we're still connected? What's the check that the a/c is "ready?" (loaded by FSX/P3D and ready to respond) In the code sample I Open() once then error out on other calls. I close the conenction when the form closes. Bad technique? If the form made other calls to other offsets would things get balled up? GetLatLongString() below should probably have some busy logic to avoid a second call from wherever. I couldn't find a good list of offsets - is FSUIPC4 Offsets Status.pdf the best available? Option Explicit On Imports FSUIPC ' Project Reference to FSUIPCClient.dll Public Class frmACLocation Private Sub btnGetLatLong_Click(sender As Object, e As EventArgs) Handles btnGetLatLong.Click Try Dim sLatLon As String = GetLatLongString() If sLatLon <> "error" Then If MsgBox("a/c Lat/Lon: " & sLatLon & vbCrLf & "Open Chart?", MsgBoxStyle.YesNo) = MsgBoxResult.Yes Then Process.Start("http:\\skyvector.com/?ll=" & sLatLon & "&zoom=3") End If End If Catch ex As Exception MsgBox(ex.Message, , "btnGetLatLong_Click") End Try End Sub Function GetLatLongString() As String Dim ofsLatitude As Offset(Of Long) = New Offset(Of Long)(&H560) Dim ofsLongitude As Offset(Of Long) = New Offset(Of Long)(&H568) Dim mlat As FsLatitude Dim mlon As FsLongitude Dim sLat As String = "" Dim sLon As String = "" Try Try ' is there a better test to see if Open() has happened and we're connected FSUIPCConnection.Open() Catch ex As Exception ' assume already Open ' next call with throw an error if that was not the case End Try FSUIPCConnection.Process() mlat = New FsLatitude(ofsLatitude.Value) mlon = New FsLongitude(ofsLongitude.Value) sLat = mlat.ToString(False, "d", 6) sLon = mlon.ToString(False, "d", 6) sLat = Val(sLat) ' strip off leading zeros and * symbol sLon = Val(sLon) Return sLat & "," & sLon Catch ex As Exception ' Badness occurred - show the error message MsgBox(ex.Message, , "GetLatLongString") Return "error" End Try End Function Private Sub frmACLocation_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing Try FSUIPCConnection.Close() Catch ex As Exception End Try End Sub End Class
Paul Henty Posted February 20, 2014 Report Posted February 20, 2014 I used your format string but it had some non-numeric'ness to the returned string. I resorted to the deprciated, but handy, Val() to clean it up. The code is verbose, I didn't want to string a bunch of operations together for the post. You can use the DecimalDegrees property then (as this is a pure number (double)) and use ToString("F6") to turn it into a string with 6 decimal places. In the code sample I Open() once then error out on other calls. I close the conenction when the form closes. Bad technique? Yes, bad technique, If you want to maintain the connection for the lifetime of the application then you should just open it once when the application starts. Usually you would do this on a timer until the open is successful. If the connection ever drops then you restart the timer to attempt reconnection. Is there an elegant way to check to see if Open() was called and we're still connected? You have to maintain a connected flag yourself and track the Open() and subsequent Process() failures. Although FSUIPC uses the language of 'connections' being 'open' and 'closed' in reality there is nothing like a connection behind the scenes. The only way you know if the Flight Sim has been unloaded is when a Process() or Open() fails. You need to track those exceptions and maintain your own 'connected' flag. All of this is shown in the sample application that I provide with the DLL. If the form made other calls to other offsets would things get balled up? GetLatLongString() below should probably have some busy logic to avoid a second call from wherever. No you don't need any such checks and there is no way anything gets 'balled up'. The only concern would be if you had multiple threads calling GetLatLonString() but there's no way that would happen on such a simple form as you have. Even then, the DLL is thread safe and would just deal with one thread at a time, blocking the others. What's the check that the a/c is "ready?" (loaded by FSX/P3D and ready to respond) You can check offset 0x3364. When it's 0 the sim is 'ready to fly'. I couldn't find a good list of offsets - is FSUIPC4 Offsets Status.pdf the best available? It's the best available because it's the only official and complete list. It's the only source of information about offsets you should use. You have made a mistake in your new code: Dim ofsLatitude As Offset(Of Long) = New Offset(Of Long)(&H560) Dim ofsLongitude As Offset(Of Long) = New Offset(Of Long)(&H568) These offsets are now declared in your GetLatLongString method. I did not advise this. Offsets should only be declared once in the lifetime of your application.The easiest way to make sure this is the case is to declare them in at the form (or class) level, like you had them before. I've amended your code with the suggestions above. I've also added an example timer mechanism, 'open' connection tracking and the use of the ready to fly offset. You'll need to add a timer to your form called 'tmrConnection' and a label 'lblConnection' to show the status of the connection. Option Explicit On Imports FSUIPC Public Class frmACLocation Dim ofsLatitude As Offset(Of Long) = New Offset(Of Long)(&H560) Dim ofsLongitude As Offset(Of Long) = New Offset(Of Long)(&H568) Dim ofsReadyToFly As Offset(Of Byte) = New Offset(Of Byte)(&H3364) Dim bolConnected As Boolean = False Private Sub btnGetLatLong_Click(sender As Object, e As EventArgs) Handles btnGetLatLong.Click Try Dim sLatLon As String = GetLatLongString() If sLatLon <> "error" Then If MsgBox("a/c Lat/Lon: " & sLatLon & vbCrLf & "Open Chart?", MsgBoxStyle.YesNo) = MsgBoxResult.Yes Then Process.Start("http:\\skyvector.com/?ll=" & sLatLon & "&zoom=3") End If End If Catch ex As Exception MsgBox(ex.Message, , "btnGetLatLong_Click") End Try End Sub Function GetLatLongString() As String Dim mlat As FsLatitude Dim mlon As FsLongitude Dim sLat As String = "" Dim sLon As String = "" Try FSUIPCConnection.Process() If (ofsReadyToFly.Value = 0) Then mlat = New FsLatitude(ofsLatitude.Value) mlon = New FsLongitude(ofsLongitude.Value) sLat = mlat.DecimalDegrees.ToString("F6") sLon = mlon.DecimalDegrees.ToString("F6") Return sLat & "," & sLon Else MsgBox("Flight Sim is not ready to fly", , "GetLatLongString") Return "error" End If Catch ex As Exception 'Badness occurred - show the error message MsgBox(ex.Message, , "GetLatLongString") Me.tmrConnection.Start() 'start the timer again to reconnect Return "error" End Try End Function Private Sub frmACLocation_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing Try FSUIPCConnection.Close() Catch ex As Exception End Try End Sub Private Sub frmACLocation_Load(sender As Object, e As EventArgs) Handles MyBase.Load configureScreen() Me.tmrConnection.Interval = 1000 ' try connection every second Me.tmrConnection.Start() ' Start looking for flight sim End Sub Private Sub tmrConnection_Tick(sender As Object, e As EventArgs) Handles tmrConnection.Tick Me.bolConnected = False Try FSUIPCConnection.Open() ' Open sucessful Me.bolConnected = True Me.tmrConnection.Stop() ' Stop looking for a connection Catch ex As Exception ' Connection failed FSUIPCConnection.Close() ' Close ready for next retry Finally configureScreen() End Try End Sub Private Sub configureScreen() If Me.bolConnected Then Me.lblConnection.Text = "Connected to " & FSUIPCConnection.FlightSimVersionConnected.ToString() Me.lblConnection.ForeColor = Color.Green Me.btnGetLatLong.Enabled = True Else Me.lblConnection.Text = "Connecting to Flight Sim..." Me.lblConnection.ForeColor = Color.Red Me.btnGetLatLong.Enabled = False End If End Sub End Class Paul
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now