2011-08-28 14 views
8

kod:Dlaczego odmawia się dostępu do portu COM?

static void Main(string[] args) 
{ 
    Console.WriteLine("Memory mapped file reader started"); 

    using (var file = MemoryMappedFile.OpenExisting("AIDA64_SensorValues")) 
    { 
     using (var readerz = file.CreateViewAccessor(0, 0)) 
     { 
      var bytes = new byte[567]; 
      var encoding = Encoding.ASCII; 
      readerz.ReadArray<byte>(0, bytes, 0, bytes.Length); 

      File.WriteAllText("C:\\myFile.txt", encoding.GetString(bytes)); 

      var readerSettings = new XmlReaderSettings { ConformanceLevel = ConformanceLevel.Fragment }; 
      using (var reader = XmlReader.Create("C:\\myFile.txt", readerSettings)) 
      { 
       while (reader.Read()) 
       { 
        using (var fragmentReader = reader.ReadSubtree()) 
        { 
         if (fragmentReader.Read()) 
         { 

          reader.ReadToFollowing("value"); 
          SerialPort port = new SerialPort("COM2", 9600, Parity.None, 8, StopBits.One); 
          port.Open(); 
          port.Write(reader.ReadElementContentAsString() + ","); 
         } 
        } 
       } 
      }  
     } 
    } 

    Console.WriteLine("Press any key to exit ..."); 
    Console.ReadLine(); 
} 

odczytuje z pamięci współdzielonej, pisze, że wspólna pamięć do pliku, a następnie ten sam plik jest otwierany z czytnikiem XML i dzieli XML, ponieważ ma wiele korzeni, a następnie pobiera wartość węzła na każdy nowy podział xml i wysyła przez szeregowy. działa na pierwszym podzielonym pliku xml, a jego węzeł jest wysyłany przez port szeregowy, a następnie zatrzymuje się z dostępem odmawia się komunikatu portu przy próbie zapisania drugiego węzła do portu szeregowego.

Mam inną aplikację, którą zrobiłem z tego samego kodu seryjnego i działa dobrze (po prostu zmęczony to zamknęło go.) ... więc to dziwne.

+0

Może nie zamykasz niektórych referencji poprawnie, a otwarty akcesor oznacza odmowę większego dostępu z tej samej aplikacji/wątku? –

Odpowiedz

21

można otworzyć port szeregowy tylko raz. Ale twój kod ma wywołanie Open() wewnątrz pętli while. To zadziała tylko przy pierwszym przejściu przez pętlę, kaboom na drugim przejściu. Rozwiązanie cdhowie też nie działa, SerialPort ma dziwactwo (aka bug), o którym ostrzega dokumentacja. Potrzebne jest trochę czasu, aby wątek roboczy zakończył się po wywołaniu Dispose() lub Close(). Ilość czasu jest nieokreślona i nieprzewidywalna.

Prawdziwe rozwiązanie jest proste, wystarczy przenieść wywołanie Open() przed pętlą while.

+0

TAK !!! Dziękuję Ci! – Csharpz

0

Odpowiedź Hansa zastępuje ten; Zostawiam to tylko w kontekście i celach informacyjnych.


Musisz zamknąć port, gdy skończysz. Śmieciarz nie zbiera pierwszego obiektu SerialPort, zanim spróbujesz otworzyć inny uchwyt. Zmień ten kod:

SerialPort port = new SerialPort("COM2", 9600, Parity.None, 8, StopBits.One); 
port.Open(); 
port.Write(reader.ReadElementContentAsString() + ","); 

Do:

using (SerialPort port = new SerialPort("COM2", 9600, Parity.None, 8, StopBits.One))) 
{ 
    port.Open(); 
    port.Write(reader.ReadElementContentAsString() + ","); 
} 
+3

To też nie działa, SerirPort dziwactwo. –

+0

Hmm, to interesujące. Pozostawiam moją odpowiedź z powodów informacyjnych. – cdhowie

2

Poza odpowiedzią Hansa:

miałem ten sam problem i bawił się trochę z niektórymi czasów snu między otwarciem i zamknięciem portu szeregowego. W moim przypadku wystarczało 250 ms. Może to pomoże komuś tam.

EDIT:

I moje rozwiązanie zoptymalizowane i to, co wymyśliłem:

int maxRetries = 20; 
const int sleepTimeInMs = 50; 
string loggingMessage = string.Empty; 

while (maxRetries > 0) 
{ 
    try 
    { 
     loggingMessage = "Opening serial port '" + mSerialPort.PortName + "'..."; 
     mSerialPort.Open(); 
     loggingMessage += "Succeeded."; 
     IOLogger.LogInfo(loggingMessage); 
    } 
    catch (UnauthorizedAccessException unauthorizedAccessException) 
    { 
     maxRetries--; 
     loggingMessage += "Failed (UnauthorizedAccessException): "; 
     IOLogger.LogError(string.Format(loggingMessage + unauthorizedAccessException.Message + " -> Retrying in about {0} milliseconds...", sleepTimeInMs)); 
     Thread.Sleep(sleepTimeInMs); 
    } 
    catch (Exception exception) 
    { 
     loggingMessage += "Failed: "; 
     IOLogger.LogError(loggingMessage + exception.Message); 
    } 
} 

Możesz poeksperymentować z sleepTimeInMs i/lub maxRetries. Wybrałem te wartości, ponieważ wydawały się wystarczające w każdym przypadku użycia.

Powiązane problemy