Hardware components | ||||||
| × | 1 | ||||
| × | 1 | ||||
Software apps and online services | ||||||
| ||||||
|
This tutorial is a supplementary tutorial to 003 - How to Stream Device Data to Azure IoT Hub. If you've been following along then you know that we have been setting up two devices at the same time. Both of these devices have their own set of sensors and their own code base. This tutorial will explain the code base used by the Raspberry Pi 3B with the GPS module attached to it. We started off as one tutorial because it concerns one IoT Hub which we'll be streaming our data into from both of our devices.
Getting startedBy this point our blank UWP application that we have been enabling with numerous exciting features is almost ready to employ some programming logic. There is this thing in UWP called Capabilities. This feature is pretty awesome but very easily overlooked. Let's provide our UWP application some Serial Communication Capability. Right click your Package.appmanifest file from the solution explorer and select 'View Code'. At the end of the file, within the Package tag, add this code snippet:
Now our UWP application is ready to roll.
In the code section of this tutorial we've attached code for a working example application. The code is very well commented and we hope it will be easy for you to embed it into your own application. We also recommend that you check out our other tutorial on How to setup GPS module and collect GPS data in Windows IoT.
If you looked into that tutorial you should now have a good grasp of how the data was collected from the GPS module using a serial port. So in this tutorial all we have to do is somehow package the GPSData into JSON and stream it to Azure IoT Hub via HTTP1.
Our ApplicationPlease note that we have employed a DispatcherTimer
into our application because we wanted to limit our IoT Hub bandwidth. As you might have seen in the code, our timer ticks every 30 seconds. This way we send 2880 messages from one device in 24 hours. In total, we send about 5760 messages to our IoT Hub. As you know, with our developer benefits we are allowed to send only 8000 messages per day. This is the reason that even this 30 second beat feels pretty fast when the whole system is operational.
The finished application has a visual interface like this:
Now, before you start streaming data into the IoT Hub there is one more thing that you need to change in your code: the access parameters to the IoT Hub. This is something like the connection string, but in this case we've used IoT Hub's HostName
, Device Name, and Device Key. We generated this key when we registered our devices into our Azure device registry, remember? Don't worry if you haven't saved those keys, you can always retrieve them from your Azure IoT Hub page like so:
This is what your Visual Studio Solution Explorer should look like now:
At this point, we recommend you run your program and see how the numbers in you Azure Portal dashboard start to change. You can also monitor your messages with the help of the console application that we built at the end of tutorial 003. We hope you didn't have any difficulty in this sub-section of our tutorial!
See you back on track in tutorial 003!
MainPage.xaml.cs
C#////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#////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#////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#////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#////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();
}
}
}
<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#////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;
}
}
}
}
Comments