Paul Henty

FSUIPC Client DLL for .NET - Version 2.0

429 posts in this topic

Version 2.0 is now out of date. 

 

Please get the latest version that is pinned at the top of this subforum.

 

Thanks.

Paul

0

Share this post


Link to post
Share on other sites

I have to say a purpose built module for .Net like this has been long overdue. Its great to see that someone who really knowns their stuff has put together a great module for the community. Its going to make coding for FSUIPC much more efficient. As developer of a few small addon's I'm happy to say I can discard the old methods and will be using this module from now on.

So thanks, and keep up the good work!

:D :D :D

0

Share this post


Link to post
Share on other sites

Hi,

I can not read aircraft position using this DLL. Could anyone be so kind to post the code to get the latitude (or longitude) of the aircraft?

Luis

0

Share this post


Link to post
Share on other sites

Hi Luis,

The Lon and Lat offsets are 64 bit Integers which are called Long in C# and VB. (The underlying class is System.Int64 if you are using a different language).

So the declaration of the offsets would be:

C#

private Offset<long> latFS = new Offset<long>(0x0560);
private Offset<long> lonFS = new Offset<long>(0x0568);

VB.NET

Private latFS As Offset(Of Long) = New FSUIPC.Offset(Of Long)(&H560)
Private lonFS As Offset(Of Long) = New FSUIPC.Offset(Of Long)(&H568)

I've called them LonFS and LatFS because they return Lon and Lat in FS internal units.

After calling Process() you can transform the FS Units into degrees with the following lines (as described in the FSUIPC Documentation) and you end up with a Double floating point type that holds the Lon/Lat as degress.

C#

// Convert Lat and Lon from FS Units into degrees (as a double),
double lat = (double)latFS.Value * 90d / (10001750d * 65536d * 65536d);
double lon = (double)lonFS.Value * 360d / (65536d * 65536d * 65536d * 65536d);

.

VB.NET

' Convert Lat and Lon from FS Units into degrees (as a double).
Dim lat As Double = latFS.Value * 90D / (10001750D * 65536D * 65536D)
Dim lon As Double = lonFS.Value * 360D / (65536D * 65536D * 65536D * 65536D)

Paul

0

Share this post


Link to post
Share on other sites

Hi Paul,

Thank you very much for the explanation. I am using the DLL in SBuilder (scenery creation programme) and I get an error in the situation that I will try to explain:

My programme has an option to show the FS aircraft on the Sbuilder display. When the user sets this option and until he disconnects the option, the programme displays the aircraft position at regular intervals (set by a timer). This is the code for the timer event:

Try

FSUIPCConnection.Process()

AircraftLatitude = CDbl(LatAircraft.Value)

AircraftLatitude = AircraftLatitude * 90.0 / (10001750.0 * 65536.0 * 65536.0)

AircraftLongitude = CDbl(LonAircraft.Value)

AircraftLongitude = AircraftLongitude * 360.0 / (65536.0 * 65536.0 * 65536.0 * 65536.0)

Catch ex As Exception

MsgBox("Error communicating with FSUIPC!", MsgBoxResult.Ok)

AircraftVIEW = False

ShowAircraftMenuItem.Checked = False

Me.Timer2.Enabled = False

Exit Sub

End Try

UpdateDisplay()

This runs fine except if the user closes FS. Then SBuilder (in debug mode) reports an error in the DLL or it crashes in normal operation. I could start the shown routine with:

Try

FSUIPCConnection.Close()

FSUIPCConnection.Open()

FSUIPCConnection.Process()

...

but this does not look good as the timer interval can be very short (100ms or so depending on the settings of the user of my programme).

Many thanks for any tip,

Regards,

Luis

0

Share this post


Link to post
Share on other sites

Hi Luis,

The code you have posted looks OK to me. You've setup a Try/Catch block, so when the Process() executes and FS isn't arouond anymore the DLL should throw an error. You're catching this so there shouldn't be an unhandled exeption thrown to the debugger.

You're right about the Close(), Open() at the start of your timer loop - you don't want to do that. It shouldn't be necassary.

I can't really tell from your post what's going on - could you let me know:

1. Which line(s) the exception is being thrown on

2. The exact message and type of the exception(s)

3. Do you have any other methods in your application that also call Process()?

Regards,

Paul

0

Share this post


Link to post
Share on other sites

I'm writing a program using the .net package you provided to extract the com2 active frequency. I am somewhat of a programming amateur, so please forgive me...

From what i've read, the frequency drops the leading '1' and stores only the xx.xx portion in Binary Coded Decimal format - ok, I've read up on that and understand how it works, but how the heck do i

a) pull it from fsuipc (type integer?)

b) convert it to xx.xx format for display in a text field?

any help you can spare would be great - i realise that this is probably a really stupid question.

cheers,

Devon.

0

Share this post


Link to post
Share on other sites

Hi Devon,

Not a stupid question - it's simple when you know how, but if you don't know then it's not so easy!

The offset for COM2 is specified as 2 bytes in the programmer’s documentation so we declare it as a 16 bit integer (ie, System.Int16, or Short in VB, or short in C#):

VB:

Dim com2bcd As Offset(Of Short) = New FSUIPC.Offset(Of Short)(&H3118)

C#:

Offset<short> com2bcd = new Offset<short>(0x3118);

After processing, the value of this offset will be a number with the frequency encoded in BCD format. Each group of 4 bits out of the 16 specifies a digit in the frequency. To get this into a string representing the frequency we need to convert each group of 4 bits into a digit representing the value stored in those 4 bits.

This is the same as converting a binary number into Hexadecimal format. Fortunately the .NET framework can do this for us. We use one of the overloads of the ToString method. We pass in "X" to request the number to be formatted in Hex:

VB:

Dim com2String As String = com2bcd.Value.ToString("X")

C#:

string com2String = com2bcd.Value.ToString("X");

What we now have is a four digit string where the first two are before the decimal point and the last two are after.

For example if the frequency is 119.45 what we will have now is "1945".

All we need to do now is put the missing 1 on the front and insert the decimal point thus:

VB:

com2String = "1" & com2String.Substring(0, 2) & "." & com2String.Substring(2, 2)

c#:

com2String = "1" + com2String.Substring(0, 2) + "." + com2String.Substring(2, 2);

If you want to set a com frequency you'll need to reverse the process. The following shows using the static Parse method on the System.Int16 class to set the value of the com2bcd offset we declared. Note that you need to parse the 'interesting' four digits so you'll need to get the new frequency into that format first.

VB:

Dim newCom2Frequency As String = "1945" ' Set to 119.45
com2bcd.Value = Short.Parse(newCom2Frequency, Globalization.NumberStyles.AllowHexSpecifier)

C#:

string newCom2Frequency = "1945"; // Set to 119.45
com2bcd.Value = short.Parse(newCom2Frequency, System.Globalization.NumberStyles.AllowHexSpecifier);

Hope this helps. If you need any more info just ask...

Paul

0

Share this post


Link to post
Share on other sites

Paul - Thanks so much. I haven't gotten back to the PC, but everything you've written seems so logical.

As I'm new to .net, I was unaware of that function shortcut, so you've probably saved me tons of agony there - Thanks again.

If it makes you proud of me - I did eventually figure out how to retrieve the value with a short (i realized this as I was grabbing the value for Com1 as well and it occurred that I was 'running too far' from the offset) - but the next step would have had me befuddled for ages.

...and the concat line at the end is very helpful.

What a great New Years Day present - Cheers!!!!

Best regards,

Devon.

0

Share this post


Link to post
Share on other sites

Hi Paul,

Just a follow-up.

Not only did your code help - it unlocked the floodgates. I have completed my app as a tray application and it's running marvelously.

On that note - I am also experiencing the same problem if FS is closed when the app is running (in debug mode) - could it be a 'throw' exception is needed?

I've set my app up with the idea of being loaded before FS - in this manner, it polls for FSUIPC every five seconds with the .open method until FS is detected and once it is, it begins polling offsets with the .process method every 1/2 second. If the connection drops, I've written it to halt using the .process and resume 5-second monitoring with .open ...

Sounds great -but what actually happens is that I must run the app while FS is open or it doesn't detect - also, if I close FS while the app is open, i also get an exception error...I shall try and post the trouble spot later today if needed. Based on what I've read above and experienced myself - I believe the issue resides in the exception handling for the .process method as it is the first to get hit by a dropped connection and because my program does not report an error if fs is not loaded when it boots - only when FS closes which means that the .process method is catching (or throwing rather) the exception as the .open is not being used at that stage. Any thoughts?

Your experience and assistance is greatly appreciated.

Regards,

Devon.

0

Share this post


Link to post
Share on other sites

Hi Devon,

I'm assuming that your app executes the Process() in a try, catch block. If FS is closed the Process() method should throw an FSUIPCException which you have to catch and then do whatever you need to. If you are doing this (as Luis above seems to be) but there's still an unhandled exception appearing from somewhere then there seems to be a problem.

Can you let me know the exact exception wording (message) and its classtype.

Can you also do me a quick favour? If you use C# or VB.NET can you load up one of my sample programs and see what happens when you unload FS while it's are running?

It should handle it gracefully - ie, there should be a message box telling you the connection has been lost and the [connect] button should light.

If you can give my any code snippits that would help too. My email address is in the documentation if you'd prefer email.

Paul

0

Share this post


Link to post
Share on other sites

Good ideas, Paul - I'll take a look at that tonight. (I'm on Edinburgh time GMT+0)

Quick answer is yes - I'm definitely using a try/catch block. (with a throw i think)

I wouldn't have modified it from your original too much - although the app looks a lot different because my app doesn't have a form per se - just a tray icon with a righty-popup.

Let me get back to you...

Devon.

0

Share this post


Link to post
Share on other sites

Hi Paul - haven't forgotten about you, just been busy last couple days...hoping to look into this tomorrow...

Question: if the fsuipc.close() is not in a try/catch block, could this cause issues?

0

Share this post


Link to post
Share on other sites

Paul,

If you get a chance - could you send me your email address to devon.leslie@gmail.com

The code is working in debug state - but in publish state the program jams occasionally and the audio doesn't work at all.

I'm prepared to send you the entire project if you could look through it.

Let me know,

Devon.

0

Share this post


Link to post
Share on other sites

Hi

I can read the lat and longitude as for example 47.xxxxxx and -122.xxxxxx degrees.

Showing the co-ordinates in FS displays N47*26.75 W122*18.26.

Does anyone know the code for converting the decimal degrees into degrees, minutes and seconds in VB.net?

I am trying to code an app to 'read' where the plane is ie on a taxiway, parking or runway

many thanks

Graham

0

Share this post


Link to post
Share on other sites

Hi Graham,

1. Take off the degrees part so you're left with only the value after the point

2. Multiply the result by 60 to convert to minutes.

In .NET you can use the Math.Truncate method to get the integer portion and then subtract it leaving only the bit after the point.

Here's how the whole thing looks: (This assumes a double called Lon has already been created and is holding the location in decimal degrees. What you end up with is another double which holds the number of Minutes represented by the deciimal portion of Lon).

C#

double lonMinutes = Math.Abs(lon - Math.Truncate(lon)) * 60d;

VB.NET

Dim lonMinutes As Double = Math.Abs(lon - Math.Truncate(lon)) * 60D

BTW the 'Abs' method makes sure the answer is +tve. Otherwise for -tve degrees you'll end up with a -tve seconds value which probably isn't what you want. If you do, just delete "Math.Abs" - Leave the brackets in though!

The same thing will work for Lat.

LonMinutes now holds the number of minutes before the decimal point with the seconds represented as the part after the decimal point.

That's as far as the FS display goes. You can however do the same operation on lonMinutes to get the number of seconds if you need to.

I assume you need to do this for display purposes. If you are just trying to test the position of the aircraft in code I think it would be much easier just to use the raw decimal degrees that you get from FSUIPC. That way you only have to test one number and don't have to go through the conversion.

If you need any more info let me know.

Paul

0

Share this post


Link to post
Share on other sites

I appreciate your detailed reply Paul. Thankyou

I am coding a flight monitor to check I am flying the aircraft using correct procedures at each stage of flight.

What I am trying to achieve is to detect whether the aircraft is on the runway, taxiway etc and then checking the appropriate lights, flaps etc are on/set.

You make a good point of not converting the lat/long and I think that I will follow that. I am going to get the lat/long values from the airport charts and make a table so I can check the aircraft pos against it and know where I am.

The charts are in dec,min,sec format so is there a quick fire way of converting this back into decimal format as read via your offsets?

thanks again for your support

Graham

0

Share this post


Link to post
Share on other sites
The charts are in dec,min,sec format so is there a quick fire way of converting this back into decimal format as read via your offsets?

Say you have:

40* 24' 36.1"

1. take the minutes and divide by 60 to convert to degrees: 24/60 = 0.4

2. take the seconds and divide by 3600 to convert to degrees: 36.1/3600 = 0.0100278

3. Add them both to the number of degrees:

40 + 0.4 + 0.0100278 = 40.4100278

so in short it's:

Degrees + (Minutes / 60) + (Seconds / 3600)

If the lon or lat degrees are -tve (e.g. -40* 24' 36.1")

Then it's:

Degrees - (Minutes / 60) - (Seconds / 3600)

-40 - 0.4 - 0.0100278 = -40.4100278

I'm going to look at adding a Lon/Lat class or type into the DLL. It'll let you convert between the FS Integer format, the degrees decimal format, the degrees,minutes,seconds format and let you extract the degrees or minutes or seconds portion of the value.

I'll try and get it done over Easter but I can't promise.

Paul

0

Share this post


Link to post
Share on other sites

My program can now check if a plane is on/off a runway

KSEA works perfect as the runway is more or less straight up

However, when trying to add KBFI I discovered a fatal flaw in my coding. I never thought that not all runways are that straightforward eg KBFI runway runs at 310degrees, which is -50degrees offset from north.

Basically in my code I get the lat/long of my plane and check it against the 'box' of the runway. KSEA is fine as it is more or less a perfect rectangle at true north.

Here is my code for checking I am on runway.

(bl is bottom left, tr is top right etc)

'are we on ground and within the left side limits of the runway, left and right

If onground = 1 And latitude > departurerunwaybllat And longitude > departurerunwaybllong And latitude < departurerunwaytllat And longitude > departurerunwaytllong Then

'are we within the right limits of the runway, left and right

If latitude < departurerunwaytrlat And longitude < departurerunwaytrlong And latitude > departurerunwaybrlat And longitude < departurerunwaybrlong Then

'plane is on runway

etc

This works perfect for a 'straight-upwards box'.

How can I rotate this 'box' 50 degrees to the left so I can check the lat/long of KBFI?

Many thanks

Graham

0

Share this post


Link to post
Share on other sites

Hi Graham,

You need to be checking each boundry of the runway as opposed to just checking if it's in the four corners like you're doing at the moment.

The main thing you need to find out is the latitudes of the edges of the runway at the plane's current longitude and vice verse.

I've attached a graphic to show the maths for one boundry (NW/SW).

(the lon/lat units have been simplified to make things clearer)

We know the plane is at Lon 23.5E. But at what longitude is the edge of the runway at the current aircraft Latitude (24N)?

To find out we use some basic trigonometry with right angled triangles...

1. We know the positions of the NW corner and SW corner. From this we can get the lengths of two sides of the triangle. (Blue numbers)

2. The ratio between these side is 10:5 = 2:1.

3. What we want to know is: How far across is the edge of the runway at 24N. ('X' on the diagram). 24N is only 6 south of from the NW latitude . This forms a smaller triangle inside the larger one. (In red)

4. The ratio of the sides of this smaller triangle will be the same at the larger one (2:1).

5. To if the long edge is 6 the short one will be 6/2 which is 3.

6. Add that distance to the NW longitude (20E) and you get the absolute longitude of where the runway starts. In this case 23E.

7. Since the aircraft is at 23.5E it's east of the west boundry and so we could be on the runway.

You just do similar calculations for the other 4 boundries.

If they all pass, you're on the runway.

So here's a routine that will check if a point is within a quadrangle. This even works if the sides arn't parralel.

It's important that you enter the corordinates of the four corners correctly or it won't work. They are labeled NW, NE, SW and SE. Just make sure your map is pointing north and it should be fairly easy to work out which is which.

C#

 private bool AreaContainsPoint(double AreaNELat, double AreaNELon, double AreaSELat, double AreaSELon, double AreaSWLat, double AreaSWLon, double AreaNWLat, double AreaNWLon, double PointLat, double PointLon)
        {
            bool InArea = false;
            // Check if point is EAST of the NW/SW boundry
            if (PointLon &gt; AreaNWLon + ((AreaSWLon - AreaNWLon) / (AreaNWLat - AreaSWLat) * (AreaNWLat - PointLat )))
            {
                // Check if point is WEST of the NE/SE boundry
                if (PointLon &lt; AreaNELon + ((AreaSELon - AreaNELon) / (AreaNELat - AreaSELat) * (AreaNELat- PointLat)))
                {
                    // Check if point is NORTH of the SW/SE boundry
                    if (PointLat &gt; AreaSWLat + ((AreaSELat - AreaSWLat) / (AreaSELon - AreaSWLon) * (PointLon - AreaSWLon)))
                    {
                        // Check if point is South of the NW/NE boundry
                        InArea = (PointLat &lt; AreaNWLat + ((AreaNELat - AreaNWLat) / (AreaNELon - AreaNWLon) * (PointLon - AreaNWLon)));
                    }
                }
            }
            return InArea;
        }

VB.NET

    Private Function AreaContainsPoint(ByVal AreaNELat As Double, ByVal AreaNELon As Double, ByVal AreaSELat As Double, ByVal AreaSELon As Double, ByVal AreaSWLat As Double, ByVal AreaSWLon As Double, ByVal AreaNWLat As Double, ByVal AreaNWLon As Double, ByVal PointLat As Double, ByVal PointLon As Double) As Boolean
        Dim InArea As Boolean = False
        ' Check if point is EAST of the NW/SW boundry
        If (PointLon &gt; AreaNWLon + ((AreaSWLon - AreaNWLon) / (AreaNWLat - AreaSWLat) * (AreaNWLat - PointLat))) Then
            ' Check if point is WEST of the NE/SE boundry
            If (PointLon &lt; AreaNELon + ((AreaSELon - AreaNELon) / (AreaNELat - AreaSELat) * (AreaNELat - PointLat))) Then
                ' Check if point is NORTH of the SW/SE boundry
                If (PointLat &gt; AreaSWLat + ((AreaSELat - AreaSWLat) / (AreaSELon - AreaSWLon) * (PointLon - AreaSWLon))) Then
                    ' Check if point is South of the NW/NE boundry
                    InArea = (PointLat &lt; AreaNWLat + ((AreaNELat - AreaNWLat) / (AreaNELon - AreaNWLon) * (PointLon - AreaNWLon)))
                End If
            End If
        End If
        AreaContainsPoint = InArea
    End Function

It's also worth noting that this assumes the earth is flat. That's probably not a problem with checking a small area like a runway. The larger the area you check, the more inaccurate it becomes because of the roundness of the earth. The maths to do it property taking into account the round earth is fairly complicated.

Hope this works.

I've started to put Lon/Lat support in the .NET client DLL. I'll put this in there as well. Can't say when I'll get time to finish it off though.

Let me know how it goes...

Paul

post-6881-128689518863_thumb.jpg

0

Share this post


Link to post
Share on other sites

I was using AFCAD to manually get the 4 corners of the runway and entering this info into an 'airport.dat' file. My app was working fine although I only had 6 airports in the list so far. Upon discovering MakeRwys.exe I thought it would be able to read all the info that I needed but it seems to lack on some points(unless I am not using it correctly!)

Is there any way to read the width of a runway from any of the scenery bgl files?

Using MakeRwys.exe I can obtain the centreline lat/long and the length of the runway. What I cant appear to do is to expand the centreline x degrees to the left and right to form a rectangle over the runway as I dont know the width.

0

Share this post


Link to post
Share on other sites

I don't know anything about BGL files sorry.

MakeRunways seems to include runway widths. This is from the readme...

R4.csv

This is the same as the previous CSV file, but additionally includes

runways widths as the last value in each CSV line. This is used

in Radar Contact (before RC4.3) for more precise ATC operations.

Let me know if you need help modifying the routine I gave you to work with the new data (e.g. centreline + width, rather than four corners.)

Paul

0

Share this post


Link to post
Share on other sites

Right I've found the width!

I was looking at the very end of the line at stated in the readme, which in most cases is 0. It is sandwiched in the middle of the line.

KSEA,0341,47.437584,-122.311058,429,340.300,9550,111.70,150,19.700,47.450684,-122.311058,0

Regarding the updated code I will try it myself over the next few hours and if I get stuck I will be sure to let you know Paul :D

Best regards and thanks

Graham

0

Share this post


Link to post
Share on other sites
Guest
This topic is now closed to further replies.