Serial Class Per Universal Windows Platform - Part One

In this article, we will discuss the use of Serial Communication class, included in Windows.Devices namespace. At the hardware level, we will make use of Raspberry Pi2 board, Arduino Uno, etc.

Introduction

In this article, we will discuss everything related to the use of Serial Communication class, included in Windows.Devices namespace. We will see how it is possible with such a class to read and send data from the serial port. At the hardware level, we will make use of Raspberry Pi2 board, Arduino Uno, temperature sensor DHT11 and a simple diode Led both wired on the Arduino Uno pin. We will manage the temperature sensor for the display of data on Raspberry, while the LED will help us to demonstrate how we can send a command from the Arduino Raspberry by SerialComunication class. All of this is very simple, and the purpose of the article is to show how to exchange information between two devices connected with serial port.

Hardware required

After this brief introduction, let's move to the next step. For the realization of our circuit, we need the following hardware material,

  • Raspberry Pi2 with 10.0.10586.0 version installed on SD card, equipped with a power supply.
  • HDMI cable so as to connect the Raspberry Pi2 to a monitor.
  • Monitor with HDMI input.
  • ethernet cable.
  • Ethernet-USB 3.0 adapter
  • Breadboard, which is the necessary basis for mounting components and electrical wiring.
  • male-male and male-female jumper.
  • led diode
  • Arduino Uno
  • Power cable USB type B side Arduino Uno board and the USB type to connect the Raspberry.

Necessary software

A-level software you will need,

  • Windows 10 build 10.0.10586.0 installed on pc
  • Visual Studio 2015 Update 2
  • Windows SKD 10.0.10586.0 (and the latter still included with Visual Studio 2015 update 2)
  • Arduino IDE or Visual Micro for Arduino
  • Windows 10 IoT core 10.0.10586.0 installed on SD card

Windows 10

Before proceeding with the creation of the two projects, namely with Visual Studio 2015 for the UWP and the Arduino, you must install all the software mentioned above. So it will start with the installation of Windows 10 that you find in this link.

Visual Studio 2015 update 2

For installing the operating system and the time to install Visual Studio 2015 update2, find the download link here.

Arduino Ide

After installing Visual Studio 2015, it's time to devote our attention to the Arduino. As stated earlier, you can choose to avail yourself of the IDE Arduino found at this link.

Visual Micro for Arduino

Alternatively, you can download and install this Plug-in that will let you create Arduino projects directly from Visual Studio 2015. The pros are that you have available the intellisense for those who know that an automatic prompter will help -- and not a little -- when writing code. Cons are that unlike the IDE Arduino, not including debugging, if you intend to debug your application you will have to buy it separately.

Raspbrerry Pi2

Now that we have everything you need on your PC, it's time to think about the Raspberry Pi2 card. Go to this link and you can download Windows 10 IoT Core. We must, however, for the installation have a micro SD of at least 8GB, then install the operating system on it, at the end insert the SD card inside the dedicated port on Raspberry. To install Windows 10 IoT Core, refer to the following procedure, which explains in a simple and comprehensive way throughout the procedure. We have installed all the necessary software components, and we also have  all hardware components. Before turning to the creation of the projects, it is necessary to wire the electrical circuit. It is DHT11; connect the sensor and the LED diode to the Arduino board.

Electrical Circuit

Below is the final circuit of our project, we achieved it with Fritzing, an excellent software for the realization of electrical / electronic schemes.

the electrical circuit
                                                         Figure 1: the electrical circuit.

The connections are the following,

  • Anode of the LED diode on pin 13 of the Arduino board one
  • Katodo the LED diode on the Arduino board gnd pin one
  • pin "S" of DHT11 sensor (left pin) to pin 8 of the Arduino board one
  • the central pin of the sensor DHT11, + 5V pin on the Arduino board one
  • the right of DHT11 sensor pin, the pin of the Arduino board gnd one
  • Finally, we connect on the breadboard, two black and red cables to bring power to all of the above components
  • Lastly, connect the USB cable mentioned above, including a USB port of Raspberry Py 2 with the type usb output b of the Arduino board one.

These are all necessary connections, and nowit's time to devote ourselves to the creation of the test project.

Test project

We start Visual Studio 2015, on the File menu select New Project, select a universal project, and develop in C # as shown in the figure, and we call it Prova Comunicazione seriale.

test project
                                                          Figure 2: the test project.

We will be asked which version of the build we want our media project, the following dialog leaves everything unchanged, and confirm with ok button.

The minimum version and the target of the Windows build
            Figure 3: The minimum version and the target of the Windows build.

In this case, we left as a minimum version supported 10.0.10240, and target the 10.0.10586.

Confirm with the OK button, we will be led in the screen named App.xaml.cs. But before you write code to do the display and management of serial communication, we need to enable the capability required, this is to be able to make use of serial device class and DeviceInformation. Without setting capability, we will receive an exception at runtime, causing the application to crash. In other words, the capabilities are required to declare that in our application we make use of devices and / or system functionality. To enable them, usually just a double click with the mouse on the file in Package.appxmanifest on explorer solution is sufficient, but in this case it is a particular capability, and we must put everything in code. In explorer solutions, we select with a click of the mouse the files mentioned before, F7 key, and we will be led in the code as shown in the figure.

Applications and Capabilities section of Package.appxmanifest file
   Figure 4: Applications and Capabilities section of Package.appxmanifest file.

Then we're going to enable the use of serial device and DeviceInformation Classes. Insert the following code.

  1. <DeviceCapability Name="serialcommunication">   
  2.      <Device Id="any">   
  3.        < Function Type="name:serialPort" />   
  4.      </Device>   
  5.  </DeviceCapability>  
After the changes, the Capabilities section should take this aspect.

The Package.appxmanifest files after editing
         Figure 5: The Package.appxmanifest files after editing

After these changes, save and close the file Package.appxmanifest. Let's take care of the graphics now. In explorer solutions, double click with the mouse on MainPage.xaml file, we will go into the screen where we define our code using XAML GUI. To summarize briefly, the XAML language, also called declarative code, and used in different technologies, made its debut with Silverlight and WPF applications from version 3.0 of the DOTNET framework, and given the potential was developed and still used for Mobile applications, desktops and universal, is the same as that which we will develop in this article, therefore it's necessary to define all the interface objects of our application. And it's very similar for those who know the XML and HTML syntax, and then enclosed between tags, where further customization of each individual object by means of the properties that we will see shortly is possible. Below, I leave the linkto  the official Microsoft documentation for those who wish to learn every detail of the XAML language. Insert the following code inside the file MainPage.xaml.
  1. <Page   
  2.      x:Class="Prova_comunicazione_seriale.MainPage"   
  3.      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"   
  4.      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"   
  5.      xmlns:local="using:Prova_comunicazione_seriale"   
  6.      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"   
  7.      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"   
  8.      mc:Ignorable="d">  
  9.     <Grid Background="CornflowerBlue"   
  10.             
  11.            Margin="0,0,-104,0">   
  12.          <Grid.RowDefinitions>   
  13.              <RowDefinition Height="*"/>   
  14.              <RowDefinition Height="*"/>              
  15.              <RowDefinition Height="*"/>   
  16.              <RowDefinition Height="*"/>              
  17.          </Grid.RowDefinitions>  
  18.   
  19.          <Grid.ColumnDefinitions>   
  20.              <ColumnDefinition Width="Auto"/>   
  21.              <ColumnDefinition Width="Auto"/>   
  22.              <ColumnDefinition Width="Auto"/>   
  23.              <ColumnDefinition Width="Auto"/>   
  24.              <ColumnDefinition Width="Auto"/>   
  25.              <ColumnDefinition Width="Auto"/>   
  26.          </Grid.ColumnDefinitions>  
  27.           
  28.          <!--Riga 0-->   
  29.          <TextBlock x:Name="tbkAllarmi"   
  30.                     Grid.Row="0"   
  31.                     Grid.ColumnSpan="3"   
  32.                     Grid.Column="0"   
  33.                     HorizontalAlignment="Left"   
  34.                     VerticalAlignment="Center"   
  35.                     Text="Errori"/>  
  36.         <Button x:Name="btnSerialConnect"   
  37.                  Background="AliceBlue"   
  38.                  Grid.Row="0"   
  39.                  Grid.Column="4"   
  40.                  Content="Connect"   
  41.                  Click="ButtonClick"/>  
  42.         <Button x:Name="btnSerialDisconnect"   
  43.                  Background="AliceBlue"   
  44.                  Grid.Row="0"   
  45.                  Grid.Column="5"   
  46.                  Content="Disconnect"   
  47.                  Click="ButtonClick"/>  
  48.   
  49.          <!--Riga 1-->   
  50.          <TextBlock x:Name="tbkNomeComponente"   
  51.                     Grid.Row="1"   
  52.                     Grid.Column="0"                     
  53.                     HorizontalAlignment="Left"   
  54.                     VerticalAlignment="Center"   
  55.                     Text="Componete rilevato"/>  
  56.         <!--Riga 2-->   
  57.          <ListBox x:Name="lstSerialDevices"   
  58.                     Grid.Row="2"   
  59.                     Grid.ColumnSpan="6">   
  60.                
  61.              <ListBox.ItemTemplate>   
  62.                  <DataTemplate>   
  63.                      <TextBlock Text="{Binding Id}"/>   
  64.                  </DataTemplate>   
  65.              </ListBox.ItemTemplate>   
  66.          </ListBox>  
  67.   
  68.          <!--Riga 3-->   
  69.          <Button x:Name="btnAccendiled"   
  70.                  Background="AliceBlue"   
  71.                  Grid.Row="3"   
  72.                  Grid.Column="0"   
  73.                  Content="Accendi led"   
  74.                  Click="ButtonClick"/>  
  75.         <Button x:Name="btnSpegniled"   
  76.                  Background="AliceBlue"   
  77.                  Grid.Row="3"   
  78.                  Grid.Column="1"   
  79.                  Content="Spegni led"   
  80.                  Click="ButtonClick"/>  
  81.         <TextBlock x:Name="tbkStatusLed"   
  82.                     Grid.Row="3"   
  83.                     Grid.Column="2"   
  84.                     VerticalAlignment="Center"   
  85.                     HorizontalAlignment="Center"/>  
  86.         <Button x:Name="btnPulse1000ms"   
  87.                  Background="AliceBlue"   
  88.                  Grid.Row="3"   
  89.                  Grid.Column="4"   
  90.                  Content="Pulse 1000 ms"   
  91.                  Click="ButtonClick"/>  
  92.         <Button x:Name="btnPulse2000ms"   
  93.                  Background="AliceBlue"   
  94.                  Grid.Row="3"   
  95.                  Grid.Column="5"   
  96.                  Content="Pulse 2000 ms"   
  97.                  Click="ButtonClick"/>   
  98.      </Grid>   
  99. < /Page>   
If all is done correctly, this is the screen that will display.

screen MainPage.xaml file after writing the declarative code
Figure 6: the screen MainPage.xaml file after writing the declarative code.

This is truly something very simple at the interface, the purpose is to demonstrate how to send and receive data via the serial port. Let us now write managed code, in this example we will use C #. With the F7 key, we will be led in the code editor, paste the following C # code.
  1. using System;   
  2. using System.Collections.ObjectModel;   
  3. using System.Threading;   
  4. using System.Threading.Tasks;   
  5. using Windows.Devices.Enumeration;   
  6. using Windows.Devices.SerialCommunication;   
  7. using Windows.Storage.Streams;   
  8. using Windows.UI.Xaml;   
  9. using Windows.UI.Xaml.Controls;  
  10. // Il modello di elemento per la pagina vuota è documentato all'indirizzo http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x410  
  11. namespace Prova_comunicazione_seriale   
  12. {   
  13.      /// <summary>   
  14.      /// Pagina vuota che può essere usata autonomamente oppure per l'esplorazione all'interno di un frame.   
  15.      /// </summary>   
  16.      public sealed partial class MainPage : Page   
  17.      {   
  18.          /// <summary>   
  19.          /// Private variables   
  20.          /// </summary>   
  21.          private SerialDevice serialPort = null;  
  22.         DataWriter dataWriteObject = null;   
  23.          DataReader dataReaderObject = null;  
  24.         private ObservableCollection<DeviceInformation> listOfDevices;   
  25.          private CancellationTokenSource ReadCancellationTokenSource;  
  26.         public MainPage()   
  27.          {   
  28.              InitializeComponent();  
  29.             btnAccendiled.IsEnabled = false;   
  30.              btnSpegniled.IsEnabled = false;   
  31.              listOfDevices = new ObservableCollection<DeviceInformation>();   
  32.              ListAvailablePorts();   
  33.          }  
  34.   
  35.          private async void ListAvailablePorts()   
  36.          {   
  37.              try   
  38.              {   
  39.                  string aqs = SerialDevice.GetDeviceSelector();   
  40.                  var dis = await DeviceInformation.FindAllAsync(aqs);  
  41.                 for (int i = 0; i < dis.Count; i++)   
  42.                  {   
  43.                      listOfDevices.Add(dis[i]);   
  44.                  }  
  45.                 lstSerialDevices.ItemsSource = listOfDevices;   
  46.                  btnAccendiled.IsEnabled = true;   
  47.                  btnSpegniled.IsEnabled = true;   
  48.                  lstSerialDevices.SelectedIndex = -1;   
  49.              }   
  50.              catch (Exception ex)   
  51.              {   
  52.                  tbkAllarmi.Text = ex.Message;   
  53.              }   
  54.          }  
  55.   
  56.          private async void ButtonClick(object sender, RoutedEventArgs e)   
  57.          {   
  58.              var buttonClicked = sender as Button;  
  59.             switch(buttonClicked.Name)   
  60.              {   
  61.                  case "btnSerialConnect":   
  62.                      SerialPortConfiguration();   
  63.                      break;  
  64.                 case "btnSerialDisconnect":   
  65.                      SerialPortDisconnect();   
  66.                      break;  
  67.                 case "btnAccendiled":   
  68.                      if (serialPort != null)   
  69.                      {   
  70.                          dataWriteObject = new DataWriter(serialPort.OutputStream);   
  71.                          await ManageLed("2");   
  72.                      }  
  73.                     if (dataWriteObject != null)   
  74.                      {   
  75.                          dataWriteObject.DetachStream();   
  76.                          dataWriteObject = null;   
  77.                      }  
  78.                     break;  
  79.                 case "btnSpegniled":   
  80.                      if (serialPort != null)   
  81.                      {   
  82.                          dataWriteObject = new DataWriter(serialPort.OutputStream);   
  83.                          await ManageLed("1");   
  84.                      }  
  85.                     if (dataWriteObject != null)   
  86.                      {   
  87.                          dataWriteObject.DetachStream();   
  88.                          dataWriteObject = null;   
  89.                      }  
  90.                     break;  
  91.                 case "btnPulse1000ms":   
  92.                      if (serialPort != null)   
  93.                      {   
  94.                          dataWriteObject = new DataWriter(serialPort.OutputStream);   
  95.                          await ManageLed("3");   
  96.                      }  
  97.                     if (dataWriteObject != null)   
  98.                      {   
  99.                          dataWriteObject.DetachStream();   
  100.                          dataWriteObject = null;   
  101.                      }  
  102.                     break;  
  103.                 case "btnPulse2000ms":   
  104.                      if (serialPort != null)   
  105.                      {   
  106.                          dataWriteObject = new DataWriter(serialPort.OutputStream);   
  107.                          await ManageLed("4");   
  108.                      }  
  109.                     if (dataWriteObject != null)   
  110.                      {   
  111.                          dataWriteObject.DetachStream();   
  112.                          dataWriteObject = null;   
  113.                      }  
  114.                     break;   
  115.              }   
  116.          }  
  117.   
  118.          private  async void SerialPortConfiguration()   
  119.          {   
  120.              var selection = lstSerialDevices.SelectedItems;  
  121.             if (selection.Count <= 0)   
  122.              {   
  123.                  tbkAllarmi.Text = "Seleziona un oggetto per la connessione seriale!";   
  124.                  return;   
  125.              }  
  126.             DeviceInformation entry = (DeviceInformation)selection[0];  
  127.             try   
  128.              {   
  129.                  serialPort = await SerialDevice.FromIdAsync(entry.Id);   
  130.                  serialPort.WriteTimeout = TimeSpan.FromMilliseconds(1000);   
  131.                  serialPort.ReadTimeout = TimeSpan.FromMilliseconds(1000);   
  132.                  serialPort.BaudRate = 9600;   
  133.                  serialPort.Parity = SerialParity.None;   
  134.                  serialPort.StopBits = SerialStopBitCount.One;   
  135.                  serialPort.DataBits = 8;   
  136.                  serialPort.Handshake = SerialHandshake.None;   
  137.                  tbkAllarmi.Text = "Porta seriale correttamente configurata!";  
  138.                 ReadCancellationTokenSource = new CancellationTokenSource();  
  139.                 Listen();   
  140.              }  
  141.             catch (Exception ex)   
  142.              {   
  143.                  tbkAllarmi.Text = ex.Message;   
  144.                  btnAccendiled.IsEnabled = false;   
  145.                  btnSpegniled.IsEnabled = false;   
  146.              }   
  147.          }  
  148.   
  149.          private void SerialPortDisconnect()   
  150.          {   
  151.              try   
  152.              {   
  153.                  CancelReadTask();   
  154.                  CloseDevice();   
  155.                  ListAvailablePorts();   
  156.              }   
  157.              catch (Exception ex)   
  158.              {   
  159.                  tbkAllarmi.Text = ex.Message;   
  160.              }   
  161.          }  
  162.   
  163.          private async Task ManageLed(string value)   
  164.          {   
  165.              var accendiLed = value;  
  166.             Task<UInt32> storeAsyncTask;  
  167.             if (accendiLed.Length != 0)   
  168.              {   
  169.                  dataWriteObject.WriteString(accendiLed);                  
  170.                 storeAsyncTask = dataWriteObject.StoreAsync().AsTask();  
  171.                 UInt32 bytesWritten = await storeAsyncTask;   
  172.                  if (bytesWritten > 0)   
  173.                  {   
  174.                      tbkAllarmi.Text = "Valore inviato correttamente";   
  175.                  }   
  176.              }  
  177.             else   
  178.              {   
  179.                  tbkAllarmi.Text = "Nessun valore inviato";   
  180.              }   
  181.          }  
  182.   
  183.          private async void Listen()   
  184.          {   
  185.              try   
  186.              {   
  187.                  if (serialPort != null)   
  188.                  {   
  189.                      dataReaderObject = new DataReader(serialPort.InputStream);  
  190.                     while (true)   
  191.                      {   
  192.                          await ReadData(ReadCancellationTokenSource.Token);   
  193.                      }   
  194.                  }   
  195.              }  
  196.             catch (Exception ex)   
  197.              {   
  198.                  tbkAllarmi.Text = ex.Message;  
  199.                 if (ex.GetType().Name == "TaskCanceledException")   
  200.                  {   
  201.                      CloseDevice();   
  202.                  }  
  203.                 else   
  204.                  {   
  205.                      tbkAllarmi.Text = "Task annullato";   
  206.                  }   
  207.              }  
  208.             finally   
  209.              {   
  210.                  if (dataReaderObject != null)   
  211.                  {   
  212.                      dataReaderObject.DetachStream();   
  213.                      dataReaderObject = null;   
  214.                  }   
  215.              }   
  216.          }  
  217.   
  218.          private async Task ReadData(CancellationToken cancellationToken)   
  219.          {   
  220.              Task<UInt32> loadAsyncTask;  
  221.             uint ReadBufferLength = 1024;  
  222.             cancellationToken.ThrowIfCancellationRequested();  
  223.             dataReaderObject.InputStreamOptions = InputStreamOptions.Partial;  
  224.             loadAsyncTask = dataReaderObject.LoadAsync(ReadBufferLength).AsTask(cancellationToken);  
  225.             UInt32 bytesRead = await loadAsyncTask;   
  226.              if (bytesRead > 0)   
  227.              {   
  228.                  tbkStatusLed.Text = dataReaderObject.ReadString(bytesRead);                 
  229.              }   
  230.          }  
  231.   
  232.          private void CancelReadTask()   
  233.          {   
  234.              if (ReadCancellationTokenSource != null)   
  235.              {   
  236.                  if (!ReadCancellationTokenSource.IsCancellationRequested)   
  237.                  {   
  238.                      ReadCancellationTokenSource.Cancel();   
  239.                  }   
  240.              }   
  241.          }  
  242.   
  243.          private void CloseDevice()   
  244.          {   
  245.              if (serialPort != null)   
  246.              {   
  247.                  serialPort.Dispose();   
  248.              }   
  249.              serialPort = null;  
  250.             btnAccendiled.IsEnabled = false;   
  251.              btnSpegniled.IsEnabled = false;   
  252.              listOfDevices.Clear();   
  253.          }   
  254.      }   
  255. }   
Let's take a closer look at the above code when the application starts running the constructor of the MainPage class.

It is first of all a recalled method InitializeComponent (), which will handle the graphical interface for management. They disable the button to request power and led off. Later it recalle the ListAvailablePorts () method, which takes care of checking if in our case the Raspberry Pi2 are connected components. If so, we will have in listBox control, all of the components recognized Id. To click on the button btnSerialConnect, it is called the asynchronous method SerialPortConfiguration (), which deals with performing all the serial port configurations, and if all goes well, we will have a message that indicates that the configuration was successful. At this point we are ready to connect with one of the devices connected to Raspberry. It will also recall another method, Listen (), which will launch a Task called ReadData (). This task will listen so go read each incoming value on the serial port and display all onscreen. The Task ManageLed () is invoked to click on one of the button controls. As you can see, this task takes as input a parameter of type string, which will be used to perform a particular action on the Arduino Uno board, the Arduino board will send a confirmation of action taken, which will be intercepted by the Task ReadData (), so as to be displayed in our application. We now come to the last step, with the procedure for the execution of our example created with Visual Studio.

Compile and debug the test project

In exploring solutions, mouse click on the project name, right-click and select the "Properties" command. We will be led to another screen, where there will be a series of tabs. We order affecting the "Application" tab and "Debug" tab. On the first tab, leave everything as in the picture.

The Application tab
                                                Figure 7: The Application tab.

Now for the "Debug" tab, here perform some changes, namely, 
  • target device
  • ip address of the target device
  • Authentication Mode

On target device we set "Remote Computer"

For ip address, we need to enter the IP address provided by Raspberry board Py 2.
Last setting, the authentication mode, insert "Universal (non-encrypted protocol).

Below the Debug settings screen.

debug tab
                                               Figure 8: the debug tab.

We are now ready to debug our application on Raspberry Py 2.Hit F5, and if everything is done correctly, this and that will show onscreen.

project screen
               Figure 9: The test project screen.

Conclusions

In this first part, we did an overview of thenecessary hardware part, saw what software components are installed, and ended with the creation of the project and finally debuggedthe application with Visual Studio 2015 update 2. Obviously we are still missing the part relating to the Arduino one, the code sketches in order to exchange data between the two boards, which we will see in the second and final part.