Windows 10 IoT, UWP und der SerialPort (NullReferenceException)

ML89

Lt. Junior Grade
Registriert
Apr. 2014
Beiträge
440
Guten Morgen,

ich habe mal wieder ein Problemchen :freak: Ich habe das Beispiel von Microsoft für die Verwendung der UART-Schnittstelle des Raspberry Pi (3) unter Windows 10 IoT befolgt und das Problem, dass ich nur einmal mit einem SerialPort Verbinden kann:

Code:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading;
using System.Threading.Tasks;
using Windows.Devices.Enumeration;
using Windows.Devices.SerialCommunication;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.Storage.Streams;
using Windows.UI.Popups;
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;

namespace SerialMonitor_UWP__2
{
    /// <summary>
    /// Eine leere Seite, die eigenständig verwendet oder zu der innerhalb eines Rahmens navigiert werden kann.
    /// </summary>
    public sealed partial class MainPage : Page
    {
        private SerialDevice serialPort = null;
        DataWriter dataWriteObject = null;
        DataReader dataReaderObject = null;

        private ObservableCollection<DeviceInformation> listOfDevices;
        private CancellationTokenSource ReadCancellationTokenSource;

        public MainPage()
        {
            this.InitializeComponent();
            listOfDevices = new ObservableCollection<DeviceInformation>();
            ListAvailablePorts();
        }

        private async void ListAvailablePorts()
        {
            try
            {
                string aqs = SerialDevice.GetDeviceSelector();
                var dis = await DeviceInformation.FindAllAsync(aqs);
                
                for (int i = 0; i < dis.Count; i++)
                {
                    listOfDevices.Add(dis[i]);
                }

                DeviceListSource.Source = listOfDevices;
                listBox.SelectedIndex = -1;

            }
            catch (Exception ex)
            {
                textBox.Text = ex.Message;
                textBox.Text += "ListAvailablePorts()";
                listBox.SelectedIndex = -1;
            }

            serialPort = null;
        }

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            ListAvailablePorts();
        }

        private async void button2_Click(object sender, RoutedEventArgs e)
        {
            var selection = listBox.SelectedItems;

            if(selection.Count <= 0)
            {
                textBox.Text = "Wählen Sie einen COM-Port und verbinden Sie";
                return;
            }

            DeviceInformation entry = (DeviceInformation)selection[0];

            try
            {
                serialPort = await SerialDevice.FromIdAsync(entry.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.None;

                textBox.Text = "COM-Port erfolgreich eingerichtet: ";
                textBox.Text += serialPort.PortName + "-";
                textBox.Text += serialPort.BaudRate + "-";
                textBox.Text += serialPort.DataBits + "-";
                textBox.Text += serialPort.Parity.ToString() + "-";
                textBox.Text += serialPort.StopBits;

            }
            catch(Exception ex)
            {
                textBox.Text = ex.Message;
            }

        }
    }
}

letztendlich steigt er in Zeile 89 aus und schmeißt eine NullreferenceException (Object reference not set to an instance of an object). Meine Frage ist warum das ein erstes Mal geht und kein zweites Mal?
 
Hi,

debugge doch mal und schau nach, was die einzelnen Objekte und Properties im Erfolgs- und im Fehlerfall sind.

VG,
Mad
 
Madman1209 schrieb:
Hi,

debugge doch mal und schau nach, was die einzelnen Objekte und Properties im Erfolgs- und im Fehlerfall sind.

VG,
Mad

Öhm, wie geht das? ich Habe mir entry angeschaut und entry hat den selben Wert. Das heißt für mich, dass SerialDevice.FromIdAsync(entry.Id) warum auch immer im zweiten Durchgang ein leeres Objekt zurückgibt.
 
Hi,

naja, du setzt dir einen Breakpoint und schaust dir zu beiden Zeitpunkten (Erfolg, Fehler) alle relevanten Objekte, Properties und Werte an.

VG,
Mad
 
Ich würde mal grob sagen, dass du halt den SerialPort maximal einmal öffnen darfst (ist normalerweise immer so).
​Wenn du ihn wieder öffnen willst, musst du ihn vorher schließen (von Hand!), z.B. via Close() (https://docs.microsoft.com/en-us/uw...evices_SerialCommunication_SerialDevice_Close)

​EDIT:
Warum passiert das nicht automatisch? Weil C# eine Sprache mit GC (Garbage Collector) ist, und daher Ressourcen sehr spät (wenn überhaupt irgendwann mal) freigegeben werden können. Wenn du serialport=null schreibst, wird nur die Referenz zerstört, das Objekt lebt aber immer noch, daher muss man bei allen Ressourcen die Lebensdauer manuell verwalten (mit Close() z.B.).

​In C++ ist das nicht so, da RAII und damit ein definierter Zerstörzeitpunkt für das Objekt.
 
Zuletzt bearbeitet:
@Madman1209:

Ja, habe es gemacht, auch mit der System.Diagnostics.Debug. Tatsächlich ist es so, wie Hancock gesagt hat.
Warum das ganze? ich möchte mir die COM-Ports auflisten lassen und die "bekannten" Namen ala' COM1 werden erst mit öffnen des SerialDevice über die Eigenschaft PortName zugänglich.

@Hancok:

Ja, es "roch" schon danach. Aber danke dir :)
 
Zurück
Oben