Bardaan A
Published © GPL3+

003a - Raspberry Pi 3B with GPS Module and Azure IoT Hub

This is a supplementary tutorial to 003. In this tutorial we'll develop a program to collect and upload GPS data to the Azure IoT Hub.

AdvancedFull instructions provided12 hours2,449
003a - Raspberry Pi 3B with GPS Module and Azure IoT Hub

Things used in this project

Story

Read more

Schematics

Raspberry Pi 3B and u-Blox GPS module Schematics

This is the wiring diagram showing how the GPS module was connected to the Raspberry Pi 3B serial.

Code

MainPage.xaml.cs

C#
This is the main code behind for our application. This is where the main program's logic is implemented. We have also implemented timer in this program which runs our business logic every 30 seconds.
////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 System.Threading.Tasks;
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 RasPi3BApp
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    /// 

    // In this UWP Application we'll be collecting some GPS data from our GPS module every 30 seconds, convert that data into JSON
    // and upload it to Azure IoT Hub for further processing and Storage.
    public sealed partial class MainPage : Page
    {
        // This is the IoT Hub's Hostname can be retrieved from the Azure Portal
        private string iotHubHostname = "...";
        // This is the name of the device that we created, when we registered out device to the IoT Hub
        // Registry
        private string deviceName = "...";
        // This is the device Key that was generated when we registerd out device into the registry
        // This can also be retrieved from the Azure Portal
        private string deviceKey = "...";

        // Containment and Delegation once again
        // An IoTHub object
        private IoTHub iotHub;
        // SerialReceiver object declaration
        private SerialReceiver serialReceiver;
        // GPGGA object reference
        private GPGGA gpgga;
        // GPSData instance to be filled up with value later
        private GPSData gpsData;
        // Our Main timer, this timer is going to dictate the program flow and sends device data in 30 second intervals
        private DispatcherTimer mainTimer;

        public MainPage()
        {
            // This is where all the UWP elements are initialized... Kind of mandatory!
            this.InitializeComponent();

            // Setup all the necessary resources and initialize them
            SetupSerialReceiver();
            SetupGPGGA();
            SetupIoTHub();
            SetupTimer();
        }

        // This is where all the action is. This method is called every 30 seconds
        // by the DispatcherTimer
        private async void OnMainTimerTick(object sender, object e)
        {
            try
            {
                // This is where the string that was collected from the GPS module is being passed
                // into the Parser. That in turn fills the values into the GPSData
                gpsData = gpgga.TryParse(await serialReceiver.ReadAsync(1024));
                textBlockGPSStatusStatus.Text = gpsData.Status.ToString();
                textBoxGPSDataString.Text = gpsData.ToString();
                textBoxDataCollectionStatus.Text = "Data collected...";
                textBoxPayloadDeliveryStatus.Text = "...";
                if(iotHub.IsInitialized)  // It better be...
                {
                    textBlockIoTHubStatusStatus.Text = "Initialized!";
                    // Now this is very important point of this whole application. This is where
                    // our data, in this case it is GPSData is passed on to be packaged in to JSON payload and finally
                    // uploaded to the IoT Hub. In a way our data is being, "Spirited away!"
                    await iotHub.Upload(gpsData);
                    textBoxPayloadDeliveryStatus.Text = "Successfully uploaded!";
                    textBoxDataCollectionStatus.Text = "...";
                }
                else
                {
                    textBlockIoTHubStatusStatus.Text = "Not Initialized!";
                    textBoxPayloadDeliveryStatus.Text = "...";
                    textBoxDataCollectionStatus.Text = "...";
                }
            }
            catch(Exception ex)  // Please no!!!!
            {
                throw new GPSException(ex.Message);
            }
        }

        // This is where we setup our timer
        private void SetupTimer()
        {
            mainTimer = new DispatcherTimer();
            mainTimer.Interval = TimeSpan.FromMilliseconds(30000); // 30 second intervals
            mainTimer.Tick += OnMainTimerTick;
            Task.Delay(60000);  // Give some time for the GPS module to warm up
            mainTimer.Start();  // Ready set go...
        }

        // This is where the IoT Hub object is initialized. The security access strings are
        // passed in here
        private void SetupIoTHub()
        {
            iotHub = new IoTHub();
            iotHub.Initialize(iotHubHostname,deviceKey,deviceName);
        }

        // This is where Serial Port is initialized and data is collected from the GPS module
        private async void SetupSerialReceiver()
        {
            serialReceiver = new SerialReceiver();
            await serialReceiver.Initialize();
        }

        // This is where we setup out GPS GPGGA parser, i.e. Regular Expression "Pretty Cool"!
        private void SetupGPGGA()
        {
            gpsData = new GPSData();
            gpgga = new GPGGA();
        }

        // We just thought we should have some place to BruteForce stop the whole thing
        // if in case something goes wrong.
        // So this button stops all the operations and disposes off the resources
        private async void buttonCloseApplication_Click(object sender,RoutedEventArgs e)
        {
            mainTimer.Stop();
            await iotHub.Close();
            serialReceiver.Close();
        }
    }
}

GPGGA.cs

C#
This class contains methods that are used to parse the GPS data from the NEMA sentences collected from the GPS module via serial.
////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 RasPi3BApp
{
    class GPGGA
    {
        private GPSData gpsData;
        Match regexGPGGAMatch;
        // I've been using these StringBuilder object for a while, I kind of like their flexibility.
        StringBuilder outputString;
        string[] parseResult;

        Regex regexGPGGA;

        // I'm 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());
                    parseResult = Regex.Split(outputString.ToString(),@",");
                    int.TryParse(parseResult[6],out status);
                    if(status != 0)
                    {
                        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();
                    }
                    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 is our custom GPSData type. It makes it easier to package into a payload and transfer.
////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 RasPi3BApp
{
    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}, Number of Satellites: {NumberOfSatellites}";
        }
    }
}

GPSException.cs

C#
This exception type is used to report back to the caller that something wrong happened in our code.
////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 RasPi3BApp
{
    // Just following the exceptional convention ;)
    // "Relay the message, add some value to it if you feel like it!" Said by: Some king somewhere who lost the kingdom the following year! LOL...
    class GPSException : Exception
    {
        private string message;

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

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

IoTHub.cs

C#
This class contains methods that is used to convert the GPS data in to JSON and upload into IoT Hub.
////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 Microsoft.Azure.Devices;
using Microsoft.Azure.Devices.Client;
using Newtonsoft.Json;
//using System.Diagnostics;

namespace RasPi3BApp
{
    class IoTHub
    {
        // Standard IoT Hub device client and message
        private DeviceClient device;
        private Microsoft.Azure.Devices.Client.Message payload;
        string payloadIntoString;
        private bool initialized;
        public bool IsInitialized { get { return initialized; } }

        public void Initialize(string iotHubHostName,string deviceKey,string deviceId)
        {
            initialized = false;
            try
            {
                // Simply WOW! Good job microsoft Azure/IoT team... Thanks!
                device = DeviceClient.Create(iotHubHostName,new DeviceAuthenticationWithRegistrySymmetricKey(deviceId,deviceKey),Microsoft.Azure.Devices.Client.TransportType.Http1);
                if(device != null)
                {
                    initialized = true;
                }
            }
            catch(Exception ex)
            {
                //Debug.WriteLine("IoT Hub initialization failed!  " + ex.Message);
                throw new GPSException(ex.Message);
            }
        }

        // So this is where all the magic happens, the payload is "Spirited Away"!
        public async Task Upload(GPSData gpsData)
        {
            try
            {
                // JSON! JSON! JSON!
                payloadIntoString = JsonConvert.SerializeObject(gpsData);
                payload = new Microsoft.Azure.Devices.Client.Message(Encoding.UTF8.GetBytes(payloadIntoString));
                await device.SendEventAsync(payload);
            }
            catch(Exception ex)
            {
                //Debug.WriteLine("Upload failed!  " + ex.Message); // Seriously!
                throw new GPSException(ex.Message);
            }
        }

        public async Task Close()
        {
            await device.CloseAsync();
            device.Dispose();
        }
    }
}

MainPage.xaml

XML
This page contains information about the design interface of our application
<Page
    x:Class="RasPi3BApp.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:RasPi3BApp"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid Background="#FF81CCFF">
        <TextBlock x:Name="textBlockGPSStatus" HorizontalAlignment="Left" Margin="44,10,0,0" TextWrapping="Wrap" Text="GPS Status: " VerticalAlignment="Top" Height="50" Width="204" FontSize="36"/>
        <TextBlock x:Name="textBlockGPSStatusStatus" HorizontalAlignment="Left" Margin="268,10,0,0" TextWrapping="Wrap" Text="..." VerticalAlignment="Top" Height="50" Width="252" FontSize="36"/>
        <TextBox x:Name="textBoxGPSDataString" HorizontalAlignment="Left" Margin="28,65,0,0" TextWrapping="Wrap" Text="GPS Data String" VerticalAlignment="Top" Width="967" Height="104" FontSize="24"/>
        <TextBlock x:Name="textBlockIoTHubStatus" HorizontalAlignment="Left" Margin="40,188,0,0" TextWrapping="Wrap" Text="IoT Hub Status: " VerticalAlignment="Top" Height="50" Width="274" FontSize="36"/>
        <TextBlock x:Name="textBlockIoTHubStatusStatus" HorizontalAlignment="Left" Margin="342,188,0,0" TextWrapping="Wrap" Text="..." VerticalAlignment="Top" Height="50" Width="252" FontSize="36"/>
        <Button x:Name="buttonCloseApplication" Content="Close" HorizontalAlignment="Left" Margin="702,594,0,0" VerticalAlignment="Top" Width="285" Height="140" FontSize="72" Background="#FFA60000" Foreground="White" Click="buttonCloseApplication_Click"/>
        <TextBox x:Name="textBoxDataCollectionStatus" HorizontalAlignment="Left" Margin="28,258,0,0" TextWrapping="Wrap" Text="Data Collection Status" VerticalAlignment="Top" Width="959" Height="66" FontSize="36"/>
        <TextBox x:Name="textBoxPayloadDeliveryStatus" HorizontalAlignment="Left" Margin="28,358,0,0" TextWrapping="Wrap" Text="Payload Delivery Status" VerticalAlignment="Top" Width="959" Height="66" FontSize="36"/>

    </Grid>
</Page>

SerialReceiver.cs

C#
This class contains methods that is used to collect serial data from the hardware pheripheral connected to the RaspberryPi serial port.
////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 RasPi3BApp
{
    // Here I 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. I mean just standard procedure. Thank you Windows IOT team for making this so rediculously awesome. 
        private DeviceInformationCollection deviceInformationCollection;
        // IsInitialized flag, a check system, that I've been carrying since C/Linux System Programming days. I absolutely love this technique!!
        // To be honest I haven't done the CIL profiling to see the impact, but I've seen it work like a charm in UNIX based systems.
        // I might stop using it once I 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
            {
                // I did this to avoid my 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?? I 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 I 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;
            }
        }
    }
}

Credits

Bardaan A

Bardaan A

8 projects • 16 followers
Just another Software and Technology enthusiast.
Thanks to Microsoft.

Comments