2009-06-10 6 views
0

J'essaie d'écrire une petite application qui lit simplement les données d'un socket, extrait des informations (deux entiers) des données et envoie les informations extraites sur un port série.IOException de port série enfilé lors de l'écriture

L'idée est que cela devrait commencer et continuer tout simplement. Bref, ça marche, mais pas pour longtemps. Après une période régulièrement courte, je commence à recevoir des IOExceptions et le tampon de réception de socket est submergé.

L'infrastructure de thread a été extraite de l'exemple de port série MSDN. Le délai dans send(), readThread.Join(), est un effort pour retarder read() afin de permettre au traitement d'interruption de port série de se produire, mais je pense avoir mal interprété la fonction de jointure. J'ai soit besoin de synchroniser les processus plus efficacement ou de jeter des données à l'extérieur de la prise, ce qui serait bien. Les données entières contrôlent une unité de panoramique et je suis sûr que quatre fois par seconde seraient acceptables, mais je ne suis pas sûr de la meilleure façon d'y parvenir, toutes les idées seraient grandement appréciées, applaudissements.

using System; 
using System.Collections.Generic; 
using System.Text; 
using System.IO.Ports; 
using System.Threading; 
using System.Net; 
using System.Net.Sockets; 
using System.IO; 


namespace ConsoleApplication1 
{ 
    class Program 
    { 
     static bool _continue; 
     static SerialPort _serialPort; 
     static Thread readThread; 
     static Thread sendThread; 
     static String sendString; 
     static Socket s; 
     static int byteCount; 
     static Byte[] bytesReceived; 

     // synchronise send and receive threads 
     static bool dataReceived; 

     const int FIONREAD = 0x4004667F; 

     static void Main(string[] args) 
     { 
      dataReceived = false; 
      readThread = new Thread(Read); 
      sendThread = new Thread(Send); 

      bytesReceived = new Byte[16384]; 

      // Create a new SerialPort object with default settings. 
      _serialPort = new SerialPort("COM4", 38400, Parity.None, 8, StopBits.One); 

      // Set the read/write timeouts 
      _serialPort.WriteTimeout = 500; 

      _serialPort.Open(); 
      string moveMode = "CV "; 
      _serialPort.WriteLine(moveMode); 

      s = null; 
      IPHostEntry hostEntry = Dns.GetHostEntry("localhost"); 
      foreach (IPAddress address in hostEntry.AddressList) 
      { 
       IPEndPoint ipe = new IPEndPoint(address, 10001); 
       Socket tempSocket = 
        new Socket(ipe.AddressFamily, SocketType.Stream, ProtocolType.Tcp); 

       tempSocket.Connect(ipe); 

       if (tempSocket.Connected) 
       { 
        s = tempSocket; 
        s.ReceiveBufferSize = 16384; 
        break; 
       } 
       else 
       { 
        continue; 
       } 
      } 

      readThread.Start(); 
      sendThread.Start(); 

      while (_continue) 
      { 
       Thread.Sleep(10); 
       ;// Console.WriteLine("main..."); 
      } 

      readThread.Join(); 
      _serialPort.Close(); 
      s.Close(); 
     } 

     public static void Read() 
     { 
      while (_continue) 
      { 
       try 
       { 
        //Console.WriteLine("Read"); 
        if (!dataReceived) 
        { 
         byte[] outValue = BitConverter.GetBytes(0); 
         // Check how many bytes have been received. 
         s.IOControl(FIONREAD, null, outValue); 
         uint bytesAvailable = BitConverter.ToUInt32(outValue, 0); 

         if (bytesAvailable > 0) 
         { 
          Console.WriteLine("Read thread..." + bytesAvailable); 
          byteCount = s.Receive(bytesReceived); 
          string str = Encoding.ASCII.GetString(bytesReceived); 
          //str = Encoding::UTF8->GetString(bytesReceived); 
          string[] split = str.Split(new Char[] { '\t', '\r', '\n' }); 

          string filteredX = (split.GetValue(7)).ToString(); 
          string filteredY = (split.GetValue(8)).ToString(); 

          string[] AzSplit = filteredX.Split(new Char[] { '.' }); 
          filteredX = (AzSplit.GetValue(0)).ToString(); 
          string[] ElSplit = filteredY.Split(new Char[] { '.' }); 
          filteredY = (ElSplit.GetValue(0)).ToString(); 

          // scale values 
          int x = (int)(Convert.ToInt32(filteredX) * 1.9); 
          string scaledAz = x.ToString(); 
          int y = (int)(Convert.ToInt32(filteredY) * 1.9); 
          string scaledEl = y.ToString(); 

          String moveAz = "PS" + scaledAz + " "; 
          String moveEl = "TS" + scaledEl + " "; 

          sendString = moveAz + moveEl; 
          dataReceived = true; 
         } 
        } 
       } 
       catch (TimeoutException) {Console.WriteLine("timeout exception");} 
       catch (NullReferenceException) {Console.WriteLine("Read NULL reference exception");} 
      } 
     } 

     public static void Send() 
     { 
      while (_continue) 
      { 
       try 
       { 
        if (dataReceived) 
        { 
         // sleep Read() thread to allow serial port interrupt  processing 
         readThread.Join(100); 
         // send command to PTU 
      dataReceived = false; 
         Console.WriteLine(sendString); 
         _serialPort.WriteLine(sendString); 
        } 
       } 
       catch (TimeoutException) { Console.WriteLine("Timeout exception"); } 
       catch (IOException) { Console.WriteLine("IOException exception"); } 
       catch (NullReferenceException) { Console.WriteLine("Send NULL reference exception"); } 
      } 
     } 
    } 
} 

MISE À JOUR:

Merci pour la réponse Jon.

Ce que j'essaie de faire est un sondage socket pour les données, si son processus et y envoyer au port série, sinon gardez polling la prise , en répétant ce processus ad nauseam. Ma première tentative a utilisé un seul thread et je recevais le même problème, ce qui m'a amené à croire que je dois donner au port série plus de temps pour lui permettre d'envoyer les données avant de lui donner plus de données sur la prochaine boucle, car une fois que j'ai envoyé des données sur le port série, je suis de retour interroger le socket très dur. Après avoir dit que IOExceptions se produisent après environ 30 secondes de fonctionnement, peut-être avec ce que je dis est que je devrais voir IOExceptions immédiatement?

Mon interprétation de la fonction de jointure, je pense, est incorrecte, idéalement appel readThread.Join de send() permettrait à read() de dormir tout en pompant le port COM, mais où j'ai il semble mettre le send() pour dormir, ce que je suppose est la fonction d'appel? et ne produisant pas le résultat souhaité.

Toutes les suggestions seraient appréciées. À votre santé.

Répondre

1

Il semble que ce que vous essayez de faire est d'envoyer des données, puis attendez une réponse, puis répétez. Vous utilisez deux threads pour cela et essayez de les synchroniser. Je pense que vous avez seulement besoin d'un fil. Envoyez d'abord, puis attendez une réponse, puis répétez. Cela permettra d'éliminer vos problèmes de synchronisation de thread.

2

J'ai récemment rencontré ce problème (et beaucoup d'autres aussi) - et c'est fondamentalement un problème avec le code d'initialisation du port série de Microsoft. J'ai écrit un très detailed explanation here si vous souhaitez en savoir plus. J'ai également suggéré une solution de contournement. Heureusement, il y a assez de bruit autour de ce problème, de sorte que Microsoft le verrait et le corrigerait dès que possible - peut-être un correctif .NET 4.0. Ce problème a démarré assez longtemps .NET 2.0 (l'espace de noms System.IO.Ports a été introduit pour la première fois).

Questions connexes