2010-03-22 14 views
5

Tengo dos dispositivos que me gustaría conectar a través de una interfaz en serie, pero tienen conexiones incompatibles. Para evitar este problema, los conecté a mi PC y estoy trabajando en un programa C# que enrutará el tráfico en el puerto COM X al puerto COM Y y viceversa.C# SerialPort: problemas para mezclar puertos con diferentes velocidades de baudios

El programa se conecta a dos puertos COM. En el manejador de eventos de datos recibidos, leo los datos entrantes y los escribo en el otro puerto COM. Para ello, tengo el siguiente código:

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); 
      } 
     } 
    } 

Ese código funcionaba bien, siempre y cuando el puerto COM de salida funcionar a una velocidad de transmisión más alta que el puerto COM de entrada. Si el puerto COM entrante era más rápido que el puerto COM saliente, comencé a perder datos. Tuve que corregir el código como este:

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 
      } 
     } 
    } 

No entiendo por qué necesito esa solución. Soy nuevo en C# (este es mi primer programa), así que me pregunto si hay algo que me falta. El SerialPort tiene como valor predeterminado un búfer de escritura de 2048 bytes y mis comandos son de menos de diez bytes. El buffer de escritura debe tener la capacidad de almacenar los datos hasta que se puedan escribir en un puerto COM más lento.

En resumen, estoy recibiendo datos en COM X y escribiendo los datos en COM Y. COM X está conectado a una velocidad en baudios más rápida que COM Y. ¿Por qué el búfer en el búfer de escritura no maneja esta diferencia? ¿Por qué parece que tengo que esperar a que drene el búfer de escritura para evitar perder datos?

Gracias!

* Actualización *

Como se ha señalado, este código puede correr muy fácilmente en una condición de desbordamiento con grandes transferencias y/o rápidas de datos entrantes. Debería haber escrito más sobre mi flujo de datos. Estoy esperando < comandos de 10 bytes (con < respuestas de 10 bytes) a 10 Hz. Además, estoy viendo fallas en el primer comando.

Así que, aunque sé que este código no se escala y es menos que óptimo, me pregunto por qué los búferes de lectura/escritura de 2-4K ni siquiera podían manejar el primer comando. Me pregunto si hay un error al escribir un solo byte de datos o algo con el controlador de eventos que no entiendo. Gracias.

* Actualización *

He aquí un ejemplo del fracaso:

Digamos que mi mando es de cuatro bytes: 0x01 0x02 0x3 0x4. El dispositivo en COM X envía el comando. Puedo ver que el programa C# recibe cuatro bytes y los envía al dispositivo en COM Y. El dispositivo en COM Y recibe dos bytes: 0x01 0x03. Sé que el dispositivo en COM Y es confiable, así que me pregunto cómo se eliminaron los dos bytes.

Por cierto, ¿alguien me puede decir si es mejor responder a las preguntas con comentarios o si debería seguir editando la pregunta original? ¿Cuál es más útil?

Respuesta

0

Debe asegurarse de que outPort.WriteBufferSize sea más grande que el búfer más grande que espera enviar. Además, llamar a ReadByte y WriteByte en un bucle generalmente va a ser lento.Si cambia su manejador a algo como:

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); 
    } 
} 

esto reducirá los gastos generales, lo que debería ayudar. El búfer de escritura luego (con suerte) manejará el tiempo como esperabas.

2

Lo que estás tratando de hacer es equivalente a beber de una manguera contra incendios. Confía en el buffer de recepción para almacenar el agua, no va a durar mucho cuando alguien no cierra el grifo. Con su solución, se asegura de que el búfer de recepción se desborde en forma silenciosa, probablemente no implementó el evento ErrorReceived.

Para que esto funcione, tendrá que decirle al dispositivo de entrada que deje de enviar cuando el búfer esté lleno. Haga eso estableciendo la propiedad Handshake. Configúrelo en Handshake.RequestToSend primero. Use XOnXOff a continuación. Depende del dispositivo si usará las señales de saludo correctamente.

Utilice el método Read() para hacer esto un poco más eficiente.


Bien, no manguera de incendios. Solo puedo pensar en otra posibilidad más. Un problema común con los primeros diseños de chips UART, tenían un buffer de recepción en el chip que podía almacenar solo un byte. Lo que requería la rutina de servicio de interrupción para leer ese byte antes de que llegara el siguiente. Si el ISR no es lo suficientemente rápido, el chip activa el estado SerialError.Overrun y el byte se pierde irremediablemente.

Una solución temporal para este problema fue poner artificialmente un retraso entre cada byte transmitido, dando al ISR en el dispositivo más tiempo para leer el byte. Que es lo que hace su código de solución, como un efecto secundario.

No es una gran explicación, los diseños de chips modernos tienen un búfer FIFO que tiene al menos 8 bytes de profundidad. Si hay algo de cierto en esto, debería ver el problema desaparecer cuando baje la velocidad de baudios. Además, el uso de Read() en lugar de ReadByte() debería empeorar el problema ya que su llamada de Write() ahora puede transmitir más de un byte a la vez, eliminando el retraso entre caracteres. Para ser claro, estoy hablando del dispositivo de salida.

+0

Sí, tiene razón en que este código es como beber de una manguera contra incendios. Desafortunadamente, debería haber escrito más sobre la manguera conectada a este código. Estoy enviando comandos de <10 bytes (con <10 respuestas de bytes) a 10 Hz. Esperaría más de suficiente buffer de lectura/escritura de 2-4K. Además, estoy viendo fallas en el primer comando. Así que, aunque sé que este código no se adapta a transferencias de datos más grandes/más rápidas, tengo curiosidad de por qué no funcionó con transferencias pequeñas/lentas. Perdón por no ser más claro. – GrandAdmiral

+0

De acuerdo, debería funcionar. Por favor sea explícito sobre "Estoy viendo fallas". –

+0

Claro. Digamos que mi comando es de cuatro bytes: 0x01 0x02 0x3 0x4. El dispositivo en COM X envía el comando. Puedo ver que el programa C# recibe cuatro bytes y los envía al dispositivo en COM Y. El dispositivo en COM Y recibe dos bytes: 0x01 0x03. Sé que el dispositivo en COM Y es confiable, así que me pregunto cómo se eliminaron los dos bytes. – GrandAdmiral

Cuestiones relacionadas