2017-01-15 2 views
1

J'essaie de créer une classe qui initialise une connexion série entre une framboise et un arduino. La classe doit également être capable de lire et d'écrire sur la connexion série établie. Le code que j'ai utilisé est le microsoft developers website.Pourquoi ma méthode async n'attend pas "serialPort = await SerialDevice.FromIdAsync()"?

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

public async void Serial() 
{ 
    /* Find the selector string for the serial device */ 
    string aqs = SerialDevice.GetDeviceSelector("UART0"); 
    /* Find the serial device with our selector string */ 
    var dis = await DeviceInformation.FindAllAsync(aqs); 
    /* Create an serial device with our selected device */ 
    SerialDevice SerialPort = await SerialDevice.FromIdAsync(dis[0].Id); 
    /* Configure serial settings */ 
    SerialPort.WriteTimeout = TimeSpan.FromMilliseconds(1000); 
    SerialPort.ReadTimeout = TimeSpan.FromMilliseconds(1000); 
    SerialPort.BaudRate = 9600; 
    SerialPort.Parity = SerialParity.None; 
    SerialPort.StopBits = SerialStopBitCount.One; 
    SerialPort.DataBits = 8; 

    /* Write a string out over serial */ 
    string txBuffer = "Hello Serial"; 
    DataWriter dataWriter = new DataWriter(); 
    dataWriter.WriteString(txBuffer); 
    uint bytesWritten = await SerialPort.OutputStream.WriteAsync(dataWriter.DetachBuffer()); 

    /* Read data in from the serial port */ 
    const uint maxReadLength = 1024; 
    DataReader dataReader = new DataReader(SerialPort.InputStream); 
    uint bytesToRead = await dataReader.LoadAsync(maxReadLength); 
    string rxBuffer = dataReader.ReadString(bytesToRead); 
} 

J'ai ajouté la capacité de communication série au package.appxmanifest.

<Capabilities> 
    <DeviceCapability Name="serialcommunication"> 
    <Device Id="any"> 
     <Function Type="name:serialPort" /> 
    </Device> 
    </DeviceCapability> 
</Capabilities> 

Jusqu'à présent, tout fonctionne très bien. Le Raspberry envoie et reçoit avec succès un message de l'Arduino à l'autre bout. Maintenant, j'essaie de faire ces étapes séparément. Initialisez d'abord la connexion série, de sorte que les fonctions de lecture et d'écriture peuvent être utilisées dès qu'elles sont nécessaires dans l'application.

MainPage

namespace SerialUART 
{ 
    public sealed partial class MainPage : Page 
    { 
     private SerialController serial = new SerialController(); 

     public MainPage() 
     { 
      this.InitializeComponent(); 
      serial.Write(); 
      serial.Read(); 
     } 
    } 
} 

SerialController

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

namespace SerialUART 
{ 
    class SerialController 
    { 
     private SerialDevice SerialPort; 
     private DataWriter dataWriter; 
     private DataReader dataReader; 

     public SerialController() 
     { 
      InitSerial(); 
     } 

     private async void InitSerial() 
     { 
      string aqs = SerialDevice.GetDeviceSelector("UART0"); 
      var dis = await DeviceInformation.FindAllAsync(aqs); 
      SerialPort = await SerialDevice.FromIdAsync(dis[0].Id);  
      // The program does not wait here and executes Write() 
      // after Write() the following code will be executed 
      SerialPort.WriteTimeout = TimeSpan.FromMilliseconds(1000); 
      SerialPort.ReadTimeout = TimeSpan.FromMilliseconds(1000); 
      SerialPort.BaudRate = 9600; 
      SerialPort.Parity = SerialParity.None; 
      SerialPort.StopBits = SerialStopBitCount.One; 
      SerialPort.DataBits = 8; 
      dataWriter = new DataWriter(); 
      dataReader = new DataReader(SerialPort.InputStream); 
     } 

     public async void Read() 
     { 
      /* Read data in from the serial port */ 
      const uint maxReadLength = 1024; 
      uint bytesToRead = await dataReader.LoadAsync(maxReadLength); 
      string rxBuffer = dataReader.ReadString(bytesToRead); 
      Debug.WriteLine(rxBuffer); 
     } 

     public async void Write() 
     { 
      /* Write a string out over serial */ 
      string txBuffer = "Hello Serial"; 
      dataWriter.WriteString(txBuffer); 
      uint bytesWritten = await SerialPort.OutputStream.WriteAsync(dataWriter.DetachBuffer()); 
     } 
    } 
} 

Ce code n'attend pas pour le SERIALPORT, dataWriter et datareader à initialisent. Donc, ils ne sont jamais assignés.

Quelqu'un peut-il m'expliquer pourquoi il n'attend pas la connexion série? Et comment est-ce censé être fait?

Toute aide est appréciée. Merci d'avance!

Répondre

10

Toutes vos méthodes async retour void - cela signifie qu'ils commencent à exécuter, et le code d'appel a aucun moyen facile d'attendre jusqu'à ce qu'il soit réellement terminé avant de continuer. Dès que vous utilisez une expression await sur quelque chose qui n'est pas terminée, la méthode async retournera à l'appelant, ayant prévu une continuation qui s'exécutera lorsque l'attente sera terminée. Dans votre cas, vous continuez simplement à la déclaration suivante. Au lieu de cela, vous devez faire en sorte que vos méthodes asynchrones renvoient Task et modifiez votre méthode d'appel pour attendre la fin de la méthode asynchrone avant de continuer. C'est difficile à faire avec élégance parce que dans chaque cas vous appelez les méthodes asynchrones à partir de constructeurs, qui ne peuvent pas être eux-mêmes asynchrones. Vous pouvez envisager d'utiliser des méthodes statiques asynchrones au lieu de faire le travail dans les constructeurs, qui peuvent appeler les méthodes asynchrones, les attendre, puis appeler un constructeur réel qui ne fait aucun travail réel. Avant d'entrer dans l'un des changements détaillés, vous devriez vraiment en savoir plus sur ce que font async et await - essayer de les utiliser sans les comprendre est une recette pour d'autres problèmes.

+0

Merci pour la réponse. C'était la première fois que je devais faire face à l'async et je m'attendais à un comportement totalement différent. J'ai corrigé le problème en faisant une tâche InitSerial() et attendez la fin de la tâche. – MKFreebird

1

Ceci est votre constructeur:

public SerialController() 
{ 
    InitSerial(); 
} 

Il appelle la méthode InitSerial() qui a possède plusieurs attendre (s) en eux. Le constructeur revient tout de suite, sans faire tout ce qui est nécessaire.Ensuite, vous appelez ces méthodes:

serial.Write(); 
serial.Read(); 

Mais ces méthodes dépendent de chaque ligne de code ont été exécutées dans la méthode InitSerial, mais il est évident qu'ils ont pas.

Une façon de le résoudre serait de rendre InitSerial non privé (interne ou public) et de le renvoyer Task. Lorsque vous l'appelez, vous devez l'attendre pour qu'il ait été exécuté jusqu'à la fin. Ensuite, vous pouvez appeler serial.Write() et Serial.Read(). Vous devez éviter async void. Ils ne doivent être utilisés que pour la gestion des événements. Pour les autres méthodes, renvoyez Task ou Task<T>.