¿Cómo fuerzo un método de escritura de puerto serie para esperar a que la línea se borre antes de enviar sus datos?

StackOverflow https://stackoverflow.com/questions/222455

Pregunta

Aquí hay algunos antecedentes sobre lo que estoy tratando de hacer:

  1. Abra un puerto serie desde un dispositivo móvil a una impresora Bluetooth.
  2. Envíe un formulario EPL / 2 a la impresora Bluetooth, para que comprenda cómo tratar los datos que está a punto de recibir.
  3. Una vez recibido el formulario, envíe algunos datos a la impresora que se imprimirán en el stock de etiquetas.
  4. Repita el paso 3 tantas veces como sea necesario para cada etiqueta que se va a imprimir.

El paso 2 solo ocurre la primera vez, ya que el formulario no necesita preceder a cada etiqueta. Mi problema es que cuando envío el formulario, si envío los datos de la etiqueta demasiado rápido, no se imprimirá. A veces recibo "Falla de Bluetooth: Radio no operativa" impreso en la etiqueta en lugar de los datos que envié.

He encontrado una solución al problema haciendo lo siguiente:

for (int attempt = 0; attempt < 3; attempt++)
{
    try
    {
        serialPort.Write(labelData);
        break;
    }
    catch (TimeoutException ex)
    {
        // Log info or display info based on ex.Message
        Thread.Sleep(3000);
    }
}

Entonces, básicamente, puedo detectar una TimeoutException y volver a intentar el método de escritura después de esperar una cierta cantidad de tiempo (tres segundos parecen funcionar todo el tiempo, pero nada menos y parece arrojar la excepción en cada intento). Después de tres intentos, simplemente asumo que el puerto serie tiene algo mal y le informo al usuario.

Esta manera parece funcionar bien, pero estoy seguro de que hay una mejor manera de manejar esto. Hay algunas propiedades en la clase SerialPort que creo que necesito usar, pero realmente no puedo encontrar ninguna buena documentación o ejemplos de cómo usarlas. He intentado jugar con algunas de las propiedades, pero ninguna de ellas parece hacer lo que intento lograr.

Aquí hay una lista de las propiedades con las que he jugado:

  • CDHolding
  • CtsHolding
  • DsrHolding
  • DtrEnable
  • Apretón de manos
  • RtsEnable

Estoy seguro de que alguna combinación de estos manejará lo que estoy tratando de hacer con más gracia.

Estoy usando C # (marco 2.0), una impresora Bluetooth Zebra QL 220+ y un dispositivo portátil Windows Mobile 6, si eso hace alguna diferencia para las soluciones.

Cualquier sugerencia sería apreciada.

[ACTUALIZACIÓN]

También debo tener en cuenta que el dispositivo móvil está utilizando Bluetooth 2.0, mientras que la impresora solo tiene la versión 1.1. Supongo que la diferencia de velocidad es lo que hace que la impresora se retrase en la recepción de los datos.

¿Fue útil?

Solución

El control de flujo es la respuesta correcta aquí, y puede no estar presente / implementado / aplicable a su conexión bluetooth.

Consulte la especificación de Zebra y vea si implementan, o si puede activar, el control de flujo de software (xon, xoff) que le permitirá ver cuándo se están llenando los diversos buffers.

Además, es poco probable que la radio bluetooth sea capaz de transmitir más rápido que 250k como máximo. Puede considerar limitarlo artificialmente a 9.600 bps; esto le dará a la radio mucho espacio para respirar para retransmisiones, corrección de errores, detección y su propio control de flujo.

Si todo lo demás falla, el truco que está utilizando en este momento no es malo, pero llamaría al soporte técnico de Zebra y averiguaría lo que recomiendan antes de darse por vencido.

-Adam

Otros consejos

Bueno, he encontrado una manera de hacer esto en base a las dos sugerencias ya dadas. Necesito configurar mi objeto de puerto serie con lo siguiente:

serialPort.Handshake = Handshake.RequestToSendXOnXOff;
serialPort.WriteTimeout = 10000; // Could use a lower value here.

Entonces solo necesito hacer la llamada de escritura:

serialPort.Write(labelData);

Dado que la impresora Zebra admite el control de flujo de software, enviará un valor XOff al dispositivo móvil cuando el búfer esté casi lleno. Esto hace que el dispositivo móvil espere a que se envíe un valor XOn desde la impresora, notificando efectivamente al dispositivo móvil que puede continuar transmitiendo.

Al establecer la propiedad de tiempo de espera de escritura, estoy dando un tiempo total permitido para la transmisión antes de que se produzca una excepción de tiempo de espera de escritura. Todavía querrás ver el tiempo de espera de escritura, como lo hice en mi código de muestra en la pregunta. Sin embargo, no sería necesario realizar un bucle 3 (o una cantidad arbitraria de) veces, intentando escribir cada vez, ya que el control de flujo del software iniciaría y detendría la transmisión de escritura del puerto serie.

Es probable que el problema no esté en el código del puerto serie, sino en la pila de bluetooth subyacente. El puerto que está utilizando es puramente virtual, y es poco probable que se implemente el protocolo de enlace (ya que en gran medida no tendría sentido). CTS / RTS DTR / DSR simplemente no son aplicables para lo que está trabajando.

El problema subyacente es que cuando crea el puerto virtual, debajo tiene que unirse a la pila de bluetooth y conectarse al dispositivo serial emparejado. El puerto en sí no tiene idea de cuánto tiempo puede tomar y probablemente esté configurado para hacerlo de forma asíncrona (aunque dependería exclusivamente del OEM del dispositivo cómo hacerlo) para evitar que la persona que llama se bloquee durante un largo período si no hay dispositivo emparejado o el dispositivo emparejado está fuera de alcance.

Si bien su código puede parecer un hack, es probablemente la mejor y más portátil forma de hacer lo que está haciendo.

Puede usar una API de pila de bluetooth para intentar ver si el dispositivo está vivo antes de conectarse, pero no hay una estandarización de las API de pila, por lo que las API de Widcom y Microsoft difieren en cómo lo haría, y Widcom Es propietario y costoso. Con lo que terminaría es con un lío al tratar de descubrir el tipo de pila, cargando dinámicamente una clase de verificador apropiada, haciendo que llame a la pila y busque el dispositivo. A la luz de eso, su encuesta simple parece mucho más limpia, y no tiene que pagar algunos $ k para el SDK de Widcom.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top