Hackster is hosting Hackster Holidays, Finale: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Tuesday!Stream Hackster Holidays, Finale on Tuesday!
Bardaan A
Published © GPL3+

How to setup GPS module and collect GPS data in Windows IoT

How to use a built-in Serial Device in Windows IoT to collect GPS data from a GPS Module.

AdvancedFull instructions provided16 hours7,873
How to setup GPS module and collect GPS data in Windows IoT

Things used in this project

Story

Read more

Schematics

GPS Module connected via Serial

This schematic shows how the GPS module was connected to the Raspberry Pi 3B to collect GPS data for our application.

Code

MainPage.xaml.cs

C#
This is the code behind for the MainPage.xaml design file. The code in this file is used to control the behavior of the design elements and also control the overall control flow of the application.
////The MIT License(MIT)
////Copyright(c) 2016 BardaanA

////Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

////The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

////THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409

namespace GPSSerialGPGGA
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class MainPage : Page
    {
        // Here once again we make use of Containment/Delegation model
        // Encapsulation at its best.
        // This is our customized SerialReceiver class
        private SerialReceiver serialReceiver;
        // Main timer to initiate a onTick event.
        private DispatcherTimer mainTimer;
        private GPGGA gpgga;
        private GPSData gpsData;

        private string receivedMessage = "";

        public MainPage()
        {
            this.InitializeComponent();
            SetupGPGGA();
            SetupSerial();
            // Here we setup a timer to tick every 2 seconds. The GPS module we're using is programmed to
            // poll data every 1 second. So this two seconds might seem too slow at the beginning but over time
            // for GPS data we found it to be more than sufficient.
            SetupTimer(2000);
        }

        // This is where we define the main program logic, inside the onTick method for the main timer.
        // So the code inside this block will execute every timer tick. In this case every two seconds.
        private async void MainTimerOnTick(object sender, object e)
        {            
            if(serialReceiver.IsInitialized)  // Serial port initialized check.
            {
                receivedMessage = await serialReceiver.ReadAsync(1024);  // We're reading 1024 Bytes of data at one read
                textBoxNEMASentence.Text = receivedMessage;
                // This is where our custom defined Regular Expression class is made use of. The GPS data values are parsed using Regex and
                // packaged into our custom GPSData type for easier handling and transport.
                gpsData = gpgga.TryParse(receivedMessage);
                textBlockGPSFixStatusStatus.Text = gpsData.Status.ToString();
                if(gpsData.Status == GPSStatus.Active)  // GPS Fix data check
                {   
                    textBoxTime.Text = gpsData.Time;
                    textBoxLatitude.Text = gpsData.Latitude.ToString();
                    textBoxLongitude.Text = gpsData.Longitude.ToString();
                    textBoxNumberOfSatellites.Text = gpsData.NumberOfSatellites.ToString();
                    textBoxAltitude.Text = gpsData.Altitude.ToString();
                }
            }
            else
            {
                textBlockGPSFixStatusStatus.Text = "Inactive";
                textBlockSerialStatusStatus.Text = "Inactive";
            }
        }

        // Setting up our Regex and Match for faster execution when called
        private void SetupGPGGA()
        {
            gpsData = new GPSData();
            gpgga = new GPGGA();
        }

        // Setting up our SerialReceiver class
        private async void SetupSerial()
        {
            serialReceiver = new SerialReceiver();
            buttonSerialClose.IsEnabled = false;
        }

        // Setting up the main timer and assigning the event handler method to the Tick
        private void SetupTimer(int interval)
        {
            // We like using this particular timer class in our UWP applications
            // We have found it to be somewhat useful
            mainTimer = new DispatcherTimer();
            mainTimer.Interval = TimeSpan.FromMilliseconds(interval);
            mainTimer.Start();
            mainTimer.Tick += MainTimerOnTick;
        }
        // Initializing our already setup SerialReceiver class
        private async void buttonSerialOpen_Click(object sender,RoutedEventArgs e)
        {
            await serialReceiver.Initialize();
            if(serialReceiver.IsInitialized)
            {
                textBlockSerialStatusStatus.Text = "Active";
                buttonSerialClose.IsEnabled = true;
                buttonSerialOpen.IsEnabled = false;
            }
        }

        // Close the ZSerial Port and save the valuable resources if necessary.
        private void buttonSerialClose_Click(object sender,RoutedEventArgs e)
        {
            serialReceiver.Close();
            buttonSerialClose.IsEnabled = false;
            buttonSerialOpen.IsEnabled = true;
        }
    }
}

GPGGA.cs

C#
This file contains code that is used to parse the string input data and extract the GPS data from it. The regular expression used in this code file has been customized to parse a GPGGA NEMA sentence. It returns a GPSData format.
////The MIT License(MIT)
////Copyright(c) 2016 BardaanA

////Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

////The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

////THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.Text.RegularExpressions;

namespace GPSSerialGPGGA
{
    // This class contains methods used to parse the NEMA sentences and extract GPS data from it.
    class GPGGA
    {
        private GPSData gpsData;
        Match regexGPGGAMatch;
        // We've been using these StringBuilder object for a while, we kind of like their flexibility.
        StringBuilder outputString;
        string[] parseResult;

        Regex regexGPGGA;

        // We're certain there is a better way of dealing with these data types. Putting it on hold for now!
        int status;
        string time;
        double latitude;
        char polarity;
        double longitude;
        char alignment;
        int numberOfSatellites;
        double altitude;
        double geoid;

        public GPGGA()
        {
            gpsData = new GPSData();
            outputString = new StringBuilder();
            // Regular expression used to parse out the GPS data from a GPGGA sentence
            regexGPGGA = new Regex(@"\$GPGGA,-*\d*\.*\d*,-*\d*\.*\d*,[N]*,-*\d*\.*\d*,[W]*,-*\d*,-*\d*,-*\d*\.*\d*,-*\d*\.*\d*,[M]*,-*\d*\.*\d*,[M]*,",RegexOptions.Compiled);

            // Setting initial value to zero, so that when the GPS data is lost it will report zeros than NULL. Nasty NULL!! ;)
            status = 0;
            time = "";
            latitude = 0.0;
            polarity = ' ';
            longitude = 0.0;
            alignment = ' ';
            numberOfSatellites = 0;
            altitude = 0.0;
            geoid = 0.0;
        }

        public GPSData TryParse(string input)
        {
            if(input.Length != 0)
            {
                // GPS data parsing function
                regexGPGGAMatch = regexGPGGA.Match(input.ToString());
                if(regexGPGGAMatch.Success) // if Match found
                {
                    outputString = new StringBuilder(regexGPGGAMatch.Value.ToString());
                    // This is where the string is split into components seperated by commas
                    parseResult = Regex.Split(outputString.ToString(),@",");
                    int.TryParse(parseResult[6],out status);
                    if(status != 0)  // If the status is inactive then all the data is invalid
                    {
                        gpsData.Status = GPSStatus.Active;
                        time = parseResult[1];
                        double.TryParse(parseResult[2],out latitude);
                        char.TryParse(parseResult[3],out polarity);
                        double.TryParse(parseResult[4],out longitude);
                        char.TryParse(parseResult[5],out alignment);
                        int.TryParse(parseResult[7],out numberOfSatellites);
                        double.TryParse(parseResult[11],out geoid);
                        if(geoid != 0)  // If this Geoid value is not available then the Altitude value becomes invalid!
                        {
                            double.TryParse(parseResult[9],out altitude);
                        }

                        gpsData.Time = time;
                        gpsData.Latitude = TransformGPSValue(latitude,polarity);
                        gpsData.Longitude = TransformGPSValue(longitude,alignment);
                        gpsData.Altitude = altitude;
                        gpsData.NumberOfSatellites = numberOfSatellites;

                        outputString.Clear(); // Clear the StringBuilder object
                    }
                    else
                    {
                        gpsData.Status = GPSStatus.Inactive;
                    }
                }
            }
            return gpsData;
        }

        // Oh! Well! This part was tricky. Eventhough it looks like plain arithmetic. Oh, Boy!
        private double TransformGPSValue(double val,char direction)
        {
            double result = 0.0;
            double result_hundreth = 0.0;
            int result_integer = 0;
            double result_remainder = 0.0;
            if(val != 0)
            {
                result_hundreth = val / 100.0;
                result_integer = (int)result_hundreth;
                result_remainder = (result_hundreth - (double)result_integer) / 60.0;
                result = result_integer + result_remainder * 100;
            }
            if(direction == 'W')
            {
                return -result;
            }
            return result;
        }
    }
}

GPSData.cs

C#
This file provides type for our GPS data that was collected from our GPS module and was parsed off of NEMA sentence.
////The MIT License(MIT)
////Copyright(c) 2016 BardaanA

////Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

////The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

////THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GPSSerialGPGGA
{
    public enum GPSStatus : int { Inactive = 0, Active = 1 };

    // Custom GPS Datatype desined for easy transport. We hope you like it! ():)
    class GPSData
    {
        public GPSStatus Status { get; set; }
        public string Time { get; set; }
        public int NumberOfSatellites { get; set; }
        public double Latitude { get; set; }
        public double Longitude { get; set; }
        public double Altitude { get; set; }

        public GPSData()
        {
            Status = GPSStatus.Inactive;
            Time = "";
            NumberOfSatellites = 0;
            Latitude = 0.0;
            Longitude = 0.0;
            Altitude = 0.0;
        }

        // These ToString() methods comes in handy while debugging. You gotta love em.
        public override string ToString()
        {
            return $"GPS :: Status: {Status.ToString()}, Time: {Time}, Latitude: {Latitude}, Longitude: {Longitude}, Altitude: {Altitude}";
        }
    }
}

GPSException.cs

C#
This Exception type is just used to tell the debugger that something went wrong with our GPS class. This comes in handy when many types are in action and when you have difficulty categorizing exceptions.
////The MIT License(MIT)
////Copyright(c) 2016 BardaanA

////Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

////The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

////THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GPSSerialGPGGA
{
    // Just following the exceptional convention ;)
    class GPSException : Exception
    {
        private string message;

        public GPSException(string msg)
        {
            message = msg;
        }

        public override string Message
        {
            get
            {
                return $"GPS fail!  " + message + " " + base.Message;
            }
        }
    }
}

SerialReceiver.cs

C#
This code file is used to initialize a Raspberry Pi's serial port and collect GPS data from the GPS module. It then returns a string that if then fed to the GPS parser.
////The MIT License(MIT)
////Copyright(c) 2016 BardaanA

////Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

////The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

////THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
//using System.Diagnostics;

using Windows.Devices.Enumeration;
using Windows.Devices.SerialCommunication;
using Windows.Foundation;
using Windows.Storage.Streams;

namespace GPSSerialGPGGA
{
    // Here we use the containment/delegation model.
    // Encapsulation at its best.
    class SerialReceiver
    {
        // Raspberry pi's builtin serial device, where the GPS module is hooked up.
        private SerialDevice serialPort;
        // DataReader for reading serial port stream
        private DataReader dataReader;
        // Yada, yada, yada. We mean just standard procedure. Thank you Windows IOT team for making this so rediculously awesome. 
        private DeviceInformationCollection deviceInformationCollection;
        // IsInitialized flag, a check system, that we've been carrying since C/Linux System Programming days. We absolutely love this technique!!
        // To be honest we haven't done the CIL profiling to see the impact, but we've seen it work like a charm in UNIX based systems.
        // We might stop using it once we find out... ??
        private bool initialized;
        public bool IsInitialized
        {
            get
            {
                return initialized;
            }
        }

        public async Task Initialize()
        {
            initialized = false;
            try
            {
                // Standard procedure to enable serial
                string aqs = SerialDevice.GetDeviceSelector();
                deviceInformationCollection = await DeviceInformation.FindAllAsync(aqs);
                // Here you might encounter a problem with the setting if you have more than one serial device
                // connected to your board. Just read the error message and change the index value
                // for the serial device if necessary.
                DeviceInformation selectedDevice = deviceInformationCollection[0];
                serialPort = await SerialDevice.FromIdAsync(selectedDevice.Id);
                serialPort.WriteTimeout = TimeSpan.FromMilliseconds(1000);
                serialPort.ReadTimeout = TimeSpan.FromMilliseconds(1000);
                serialPort.BaudRate = 9600;
                serialPort.Parity = SerialParity.None;
                serialPort.StopBits = SerialStopBitCount.One;
                serialPort.DataBits = 8;
                serialPort.Handshake = SerialHandshake.XOnXOff;

                if(serialPort != null)
                {
                    dataReader = new DataReader(serialPort.InputStream);
                    initialized = true;
                    //Debug.WriteLine("SerialPort successfully initialized!");
                }
            }
            catch(Exception ex)
            {
                //Debug.WriteLine("SerialReceiver failed to initialize!" + ex.Message);
                throw new GPSException(ex.Message);
            }
        }

        // This function returns a string which will then be passed on to the parser to extract GPS data!
        public async Task<string> ReadAsync(uint bufferLength)
        {
            try
            {
                // We did this to avoid our program from crashing with some horrible errors?? Any suggestions will be highly appreciated! Thanks in advance :)
                // My best guess is that the unfinished thread was competing with its shadow?? We might end up writing a book about "Shadow of a Thread". LOL
                //var bytesRead = await this.dataReader.LoadAsync(bufferLength);
                IAsyncOperation<uint> newTaskLoad = dataReader.LoadAsync(bufferLength);
                newTaskLoad.AsTask().Wait();
                var bytesRead = newTaskLoad.GetResults();
                if(bytesRead > 0)
                {
                    return dataReader.ReadString(bytesRead);
                }
            }
            catch(Exception ex)
            {
                //Debug.WriteLine("Reading serial data failed!" + ex.Message);
                throw new GPSException(ex.Message);
            }
            // Once again horrible production code we know, but hey it helps avoid so many problems while testing.
            // Don't worry it will be taken care of when the system is production ready...?
            return $"";
        }

        public void Close()
        {
            if(serialPort != null)
            {
                serialPort.Dispose();
                initialized = false;
                serialPort = null;
            }
        }
    }
}

MainPage.xaml

XML
This is the XAML code file used to design the interface for our program.
<Page
    x:Class="GPSSerialGPGGA.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:GPSSerialGPGGA"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid Background="#FFD2E6FF" BorderBrush="#FFF7C0C0">
        <Button x:Name="buttonSerialOpen" Content="Open Serial" HorizontalAlignment="Left" Margin="730,14,0,0" VerticalAlignment="Top" Height="32" Width="127" Click="buttonSerialOpen_Click"/>
        <Button x:Name="buttonSerialClose" Content="Close Serial" HorizontalAlignment="Left" Margin="880,14,0,0" VerticalAlignment="Top" Click="buttonSerialClose_Click"/>
        <TextBlock x:Name="textBlockSerialStatus" HorizontalAlignment="Left" Margin="42,14,0,0" TextWrapping="Wrap" Text="Serial Port Status: " VerticalAlignment="Top" Height="32" Width="186" FontSize="22"/>
        <TextBox x:Name="textBoxNEMASentence" HorizontalAlignment="Left" Margin="42,51,0,0" TextWrapping="Wrap" Text="..." VerticalAlignment="Top" Height="320" Width="934" FontSize="12"/>
        <TextBlock x:Name="textBlockGPSFixStatus" HorizontalAlignment="Left" Margin="42,376,0,0" TextWrapping="Wrap" Text="GPS GPGGA Fix Status: " VerticalAlignment="Top" Height="34" Width="252" FontSize="24"/>
        <TextBox x:Name="textBoxTime" HorizontalAlignment="Left" Margin="184,432,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="342" FontSize="24"/>
        <TextBlock x:Name="textBlockTime" HorizontalAlignment="Left" Margin="60,432,0,0" TextWrapping="Wrap" Text="Time: " VerticalAlignment="Top" Height="44" Width="119" FontSize="24"/>
        <TextBox x:Name="textBoxLatitude" HorizontalAlignment="Left" Margin="184,498,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="342" FontSize="24"/>
        <TextBlock x:Name="textBlockLatitude" HorizontalAlignment="Left" Margin="60,498,0,0" TextWrapping="Wrap" Text="Latitude: " VerticalAlignment="Top" Height="44" Width="119" FontSize="24"/>
        <TextBox x:Name="textBoxLongitude" HorizontalAlignment="Left" Margin="184,568,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="342" FontSize="24"/>
        <TextBlock x:Name="textBlockLongitude" HorizontalAlignment="Left" Margin="60,568,0,0" TextWrapping="Wrap" Text="Longitude: " VerticalAlignment="Top" Height="44" Width="119" FontSize="24"/>
        <TextBox x:Name="textBoxNumberOfSatellites" HorizontalAlignment="Left" Margin="318,636,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="208" FontSize="24"/>
        <TextBlock x:Name="textBlockNumberOfSatellites" HorizontalAlignment="Left" Margin="60,636,0,0" TextWrapping="Wrap" Text="Number of Satellites: " VerticalAlignment="Top" Height="44" Width="253" FontSize="24"/>
        <TextBox x:Name="textBoxAltitude" HorizontalAlignment="Left" Margin="184,704,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="342" FontSize="24"/>
        <TextBlock x:Name="textBlockAltitude" HorizontalAlignment="Left" Margin="60,704,0,0" TextWrapping="Wrap" Text="Altitude: " VerticalAlignment="Top" Height="44" Width="119" FontSize="24"/>
        <Image x:Name="image" HorizontalAlignment="Left" Height="316" Margin="605,432,0,0" VerticalAlignment="Top" Width="371" Source="Assets/GPSConstellation.jpg"/>
        <TextBlock x:Name="textBlockGPSFixStatusStatus" HorizontalAlignment="Left" Margin="306,376,0,0" TextWrapping="Wrap" Text="..." VerticalAlignment="Top" Height="34" Width="670" FontSize="24"/>
        <TextBlock x:Name="textBlockSerialStatusStatus" HorizontalAlignment="Left" Margin="226,14,0,0" TextWrapping="Wrap" Text="..." VerticalAlignment="Top" Height="32" Width="468" FontSize="22"/>

    </Grid>
</Page>

Credits

Bardaan A
8 projects • 16 followers
Just another Software and Technology enthusiast.

Comments