c# - ¿Cómo obligo a un método de escritura de puerto serie a esperar a que la línea se borre antes de enviar sus datos?
windows-mobile bluetooth (3)
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 llenan los diversos almacenamientos intermedios.
Además, es poco probable que la radio bluetooth sea capaz de transmitir más rápido que 250k como máximo. Podría considerar limitarlo artificialmente a 9,600 bps, esto le permitirá a la radio mucho espacio para retransmitir, corregir errores, detectar y controlar su propio 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 qué recomiendan antes de darse por vencido.
-Adán
Aquí hay algunos antecedentes sobre lo que estoy tratando de hacer:
- Abra un puerto serie desde un dispositivo móvil a una impresora Bluetooth.
- Envíe un formulario EPL / 2 a la impresora Bluetooth, para que entienda cómo tratar los datos que está a punto de recibir.
- Una vez que se haya recibido el formulario, envíe algunos datos a la impresora que se imprimirán en el stock de etiquetas.
- Repita el paso 3 tantas veces como sea necesario para imprimir cada etiqueta.
El paso 2 solo ocurre la primera vez, ya que no es necesario que el formulario preceda 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 aparece impreso "Fallo de Bluetooth: Radio no operativa" en la etiqueta en lugar de los datos que envié.
He encontrado una forma de resolver el 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);
}
}
Básicamente, puedo atrapar una TimeoutException y reintentar el método de escritura después de esperar una cierta cantidad de tiempo (tres segundos parecen funcionar todo el tiempo, pero menos y parece arrojar la excepción en todos los intentos). Después de tres intentos, asumo que el puerto serie tiene algo mal y lo dejo saber al usuario.
De 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 parece hacer lo que intento lograr.
Aquí hay una lista de las propiedades con las que jugué:
- CDHolding
- CtsHolding
- DsrHolding
- DtrEnable
- Apretón de manos
- RtsEnable
Estoy seguro de que alguna combinación de estos se encargará de lo que estoy tratando de hacer con más gracia.
Estoy usando C # (2.0 framework), una impresora Zebra QL 220+ Bluetooth y un dispositivo de mano Windows Mobile 6, si eso hace la diferencia para las soluciones.
Cualquier sugerencia sera apreciada.
[ACTUALIZAR]
También debo tener en cuenta que el dispositivo móvil está utilizando Bluetooth 2.0, mientras que la impresora solo está en la versión 1.1. Supongo que la diferencia de velocidad es lo que está causando que la impresora se quede atrás al recibir los datos.
El problema probablemente no sea con el código del puerto serie, sino con la pila subyacente de bluetooth. El puerto que estás utilizando es puramente virtual, y es poco probable que se haya implementado siquiera el protocolo de enlace (ya que no tendría ningún sentido). CTS / RTS DTR / DSR simplemente no son aplicables para lo que está trabajando.
El problema subyacente es que cuando creas el puerto virtual, debajo tiene que vincularse a la pila bluetooth y conectarse al dispositivo serie emparejado. El puerto en sí no tiene idea de cuánto tiempo puede tardar y probablemente esté configurado para hacer esto de forma asíncrona (aunque sería responsabilidad exclusiva del OEM del dispositivo cómo hacerlo) para evitar que la persona que llama bloquee durante un período prolongado si no hay el dispositivo emparejado o el dispositivo emparejado está fuera de rango.
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.
Podría usar una API de pila bluetooth para tratar de ver si el dispositivo está allí y vivo antes de conectarse, pero no hay 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. Lo que terminaría es un desastre al tratar de descubrir el tipo de pila, cargando dinámicamente una clase de verificador adecuada, 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 unos $ k por el Widcom SDK.
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);
Como la impresora Zebra es compatible con el control de flujo de software, enviará un valor de XOff al dispositivo móvil cuando el buffer 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, concedo 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ía atrapar el tiempo de espera de escritura, como lo había hecho en mi código de muestra en la pregunta. Sin embargo, no sería necesario repetir 3 (o una cantidad arbitraria de) veces, intentando escribir cada vez, ya que el control de flujo del software se iniciaría y detendría la transmisión de escritura del puerto serie.