2010-03-22 15 views
5

Ho due dispositivi che vorrei collegare tramite un'interfaccia seriale, ma hanno connessioni incompatibili. Per ovviare a questo problema, li ho collegati entrambi al mio PC e sto lavorando a un programma C# che indirizzerà il traffico sulla porta COM X alla porta COM Y e viceversa.C# SerialPort - Problemi di missaggio delle porte con velocità di trasmissione diverse

Il programma si collega a due porte COM. Nel gestore di eventi di dati ricevuti, ho letto i dati in arrivo e li ho scritti sull'altra porta COM. Per fare questo, ho il seguente codice:

private void HandleDataReceived(SerialPort inPort, SerialPort outPort) 
    { 
     byte[] data = new byte[1]; 

     while (inPort.BytesToRead > 0) 
     { 
      // Read the data 
      data[0] = (byte)inPort.ReadByte(); 

      // Write the data 
      if (outPort.IsOpen) 
      { 
       outPort.Write(data, 0, 1); 
      } 
     } 
    } 

Questo codice ha funzionato bene fino a quando la porta COM in uscita funzionare ad una velocità di trasmissione superiore alla porta COM in ingresso. Se la porta COM in entrata era più veloce della porta COM in uscita, ho iniziato a perdere i dati. Ho dovuto correggere il codice in questo modo:

private void HandleDataReceived(SerialPort inPort, SerialPort outPort) 
    { 
     byte[] data = new byte[1]; 

     while (inPort.BytesToRead > 0) 
     { 
      // Read the data 
      data[0] = (byte)inPort.ReadByte(); 

      // Write the data 
      if (outPort.IsOpen) 
      { 
       outPort.Write(data, 0, 1); 
       while (outPort.BytesToWrite > 0); //<-- Change to fix problem 
      } 
     } 
    } 

Non capisco perché ho bisogno di quella correzione. Sono nuovo di C# (questo è il mio primo programma), quindi mi chiedo se c'è qualcosa che mi manca. Il SerialPort ha come valore predefinito un buffer di scrittura di 2048 byte e i miei comandi sono meno di dieci byte. Il buffer di scrittura dovrebbe avere la capacità di bufferizzare i dati fino a quando non può essere scritto su una porta COM più lenta.

In sintesi, sto ricevendo dati su COM X e scrivendo i dati su COM Y. COM X è connesso a una velocità di trasmissione più veloce di COM Y. Perché il buffering nel buffer di scrittura non gestisce questa differenza? Perché sembra che devo aspettare che il buffer di scrittura si svuoti per evitare di perdere dati?

Grazie!

* Aggiornamento *

Come notato, questo codice può facilmente incorrere in una condizione di overflow con grandi e/o veloci trasferimenti di dati in entrata. Avrei dovuto scrivere di più sul mio flusso di dati. Mi aspetto < comandi da 10 byte (con < risposte a 10 byte) a 10 Hz. Inoltre, sto vedendo errori nel primo comando.

Così mentre so che questo codice non è scalabile e non è ottimale, mi chiedo perché i buffer di lettura/scrittura 2-4K non siano nemmeno in grado di gestire il primo comando. Mi chiedo se c'è un bug nella scrittura di un singolo byte di dati o qualcosa con il gestore di eventi che non capisco. Grazie.

* Aggiornamento *

Ecco un esempio del fallimento:

Diciamo che il mio comando è di quattro byte: 0x01 0x02 0x3 0x4. Il dispositivo su COM X invia il comando. Riesco a vedere il programma C# che riceve quattro byte e li invia al dispositivo su COM Y. Il dispositivo su COM Y riceve due byte: 0x01 0x03. So che il dispositivo su COM Y è affidabile, quindi mi chiedo come sono stati eliminati i due byte.

A proposito, qualcuno può farmi sapere se è meglio rispondere solo a risposte con commenti o se dovrei continuare a modificare la domanda originale? Quale è più utile?

risposta

0

È necessario assicurarsi che outPort.WriteBufferSize sia più grande del buffer più grande che si prevede di inviare. Inoltre, chiamare ReadByte e WriteByte in un ciclo è in genere lento.Se modificate il gestore su qualcosa come:

int NumBytes = 20; //or whatever makes sense 
byte[] data = new byte[NumBytes]; 

while (inPort.BytesToRead > 0) 
{ 
    // Read as much data as possible at once 
    count = inPort.Read(data, 0, min(NumBytes, inPort.BytesToRead)); 

    // Write the data 
    if (outPort.IsOpen) 
    { 
     outPort.Write(data, 0, count); 
    } 
} 

questo ridurrà il sovraccarico, che dovrebbe aiutare. Il buffer di scrittura quindi (si spera) gestirà i tempi come previsto.

2

Quello che stai cercando di fare equivale a bere da una manichetta antincendio. Stai facendo affidamento sul buffer di ricezione per immagazzinare l'acqua, non durerà a lungo quando qualcuno non spegne il rubinetto. Con la tua soluzione alternativa, stai facendo in modo che il buffer di ricezione si riempia in modo silenzioso, probabilmente non hai implementato l'evento ErrorReceived.

Per fare in modo che funzioni, è necessario dire al dispositivo di input di interrompere l'invio quando il buffer è pieno. Fallo impostando la proprietà Handshake. Impostalo prima su Handshake.RequestToSend. Usa XOnXOff dopo. Dipende dal dispositivo se utilizzerà correttamente i segnali di handshake.

Utilizzare il metodo Read() per rendere questo un po 'più efficiente.


Ok, non la manichetta antincendio. Posso pensare solo a un'altra possibilità. Un problema comune con i primi progetti di chip UART, avevano un buffer di ricezione su chip che poteva memorizzare solo un byte. Il che ha richiesto alla routine di servizio di interrupt di leggere quel byte prima che arrivasse il successivo. Se l'ISR non è abbastanza veloce, il chip attiva lo stato SerialError.Overrun e il byte viene irrimediabilmente perso.

Una soluzione per questo problema era di mettere artificialmente un ritardo tra ogni byte trasmesso, dando all'ISR nel dispositivo più tempo per leggere il byte. Qual è il tuo codice risolvibile, come effetto collaterale.

Non è una buona spiegazione, i moderni progetti di chip hanno un buffer FIFO con una profondità di almeno 8 byte. Se c'è del vero in tutto questo, dovresti vedere il problema scomparire quando abbasserai il baud rate. Inoltre, l'uso di Read() anziché di ReadByte() dovrebbe peggiorare il problema poiché la chiamata a Write() può ora trasmettere più di un byte alla volta, eliminando il ritardo tra caratteri. Per essere chiari, sto parlando del dispositivo di output.

+0

Sì, hai ragione che questo codice è come bere da una manichetta antincendio. Purtroppo avrei dovuto scrivere di più sul tubo collegato a questo codice. Invio comandi <10 byte (con risposte <10 byte) a 10 Hz. Mi aspetterei buffer di lettura/scrittura 2-4K per me più che sufficienti. Inoltre, sto vedendo errori nel primo comando. Quindi, mentre so che questo codice non si adatta a trasferimenti di dati più grandi/più veloci, sono curioso di sapere perché non ha funzionato con trasferimenti piccoli/lenti. Scusa per non essere più chiaro. – GrandAdmiral

+0

Ok, dovrebbe funzionare. Si prega di essere espliciti su "I'm seeing failures". –

+0

Sicuro. Diciamo che il mio comando è di quattro byte: 0x01 0x02 0x3 0x4. Il dispositivo su COM X invia il comando. Riesco a vedere il programma C# che riceve quattro byte e li invia al dispositivo su COM Y. Il dispositivo su COM Y riceve due byte: 0x01 0x03. So che il dispositivo su COM Y è affidabile, quindi mi chiedo come sono stati eliminati i due byte. – GrandAdmiral