Come posso forzare un metodo di scrittura su porta seriale ad attendere che la riga venga cancellata prima di inviarne i dati?

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

Domanda

Ecco alcune informazioni su cosa sto cercando di fare:

  1. Apri una porta seriale da un dispositivo mobile a una stampante Bluetooth.
  2. Invia un modulo EPL / 2 alla stampante Bluetooth, in modo che capisca come trattare i dati che sta per ricevere.
  3. Una volta ricevuto il modulo, inviare alcuni dati alla stampante che verranno stampati su etichette.
  4. Ripetere il passaggio 3 tutte le volte necessarie per ciascuna etichetta da stampare.

Il passaggio 2 si verifica solo la prima volta, poiché il modulo non deve precedere ciascuna etichetta. Il mio problema è che quando invio il modulo, se invio i dati dell'etichetta troppo rapidamente, non verrà stampato. A volte ricevo " Errore Bluetooth: Radio non operativa " stampato sull'etichetta anziché sui dati che ho inviato.

Ho trovato un modo per aggirare il problema nel modo seguente:

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

Quindi, fondamentalmente, posso catturare TimeoutException e riprovare il metodo di scrittura dopo aver atteso un certo periodo di tempo (tre secondi sembrano funzionare tutto il tempo, ma niente di meno e sembra gettare l'eccezione ogni tentativo). Dopo tre tentativi presumo solo che la porta seriale abbia qualcosa di sbagliato e lo faccia sapere all'utente.

In questo modo sembra funzionare bene, ma sono sicuro che c'è un modo migliore per gestirlo. Ci sono alcune proprietà nella classe SerialPort che penso di dover usare, ma non riesco davvero a trovare alcuna buona documentazione o esempio su come usarle. Ho provato a giocare con alcune delle proprietà, ma nessuna di queste sembra fare ciò che sto cercando di ottenere.

Ecco un elenco delle proprietà con cui ho giocato:

  • CDHolding
  • CtsHolding
  • DsrHolding
  • DTREnable
  • Handshake
  • RTSEnable

Sono sicuro che una combinazione di questi gestirà ciò che sto cercando di fare con più grazia.

Sto usando C # (framework 2.0), una stampante Bluetooth Zebra QL 220+ e un dispositivo portatile Windows Mobile 6, se questo fa la differenza per le soluzioni.

Eventuali suggerimenti sarebbero apprezzati.

[UPDATE]

Vorrei anche notare che il dispositivo mobile utilizza Bluetooth 2.0, mentre la stampante è solo alla versione 1.1. Suppongo che la differenza di velocità sia ciò che sta causando un ritardo della stampante nella ricezione dei dati.

È stato utile?

Soluzione

Il controllo del flusso è la risposta corretta qui e potrebbe non essere presente / implementato / applicabile alla tua connessione bluetooth.

Controlla le specifiche Zebra e vedi se implementano, o se puoi accendere, il controllo del flusso del software (xon, xoff) che ti permetterà di vedere quando i vari buffer si riempiranno.

Inoltre, è improbabile che la radio bluetooth sia in grado di trasmettere al massimo più di 250k. Potresti considerare di limitarlo artificialmente a 9.600 bps - questo consentirà alla radio molto spazio di respirazione per ritrasmissioni, correzione di errori, rilevamento e il suo controllo del flusso.

Se tutto il resto fallisce, l'hack che stai usando in questo momento non è male, ma chiamerei il supporto tecnico Zebra e scoprirò cosa raccomandano prima di arrendersi.

-Adam

Altri suggerimenti

Bene, ho trovato un modo per farlo sulla base dei due suggerimenti già forniti. Devo impostare il mio oggetto porta seriale con il seguente:

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

Quindi devo solo fare la chiamata di scrittura:

serialPort.Write(labelData);

Poiché la stampante Zebra supporta il controllo del flusso del software, invierà un valore XOff al dispositivo mobile quando il buffer è quasi pieno. Questo fa sì che il dispositivo mobile attenda l'invio di un valore XOn dalla stampante, notificando efficacemente al dispositivo mobile che può continuare a trasmettere.

Impostando la proprietà di timeout di scrittura, sto concedendo un tempo totale concesso per la trasmissione prima che venga generata un'eccezione di timeout di scrittura. Vorresti comunque prendere il timeout di scrittura, come avevo fatto nel mio codice di esempio nella domanda. Tuttavia, non sarebbe necessario eseguire il ciclo 3 (o una quantità arbitraria di) volte, tentando di scrivere ogni volta, poiché il controllo del flusso del software si avviava e interrompeva la trasmissione in scrittura della porta seriale.

Probabilmente il problema non è con il codice della porta seriale, ma con lo stack bluetooth sottostante. La porta che stai usando è puramente virtuale, ed è improbabile che una qualsiasi delle operazioni di handshaking sia addirittura implementata (dato che sarebbe in gran parte insignificante). CTS / RTS DTR / DSR sono semplicemente non applicabili per ciò su cui stai lavorando.

Il problema di fondo è che quando si crea la porta virtuale, al di sotto di essa deve collegarsi allo stack bluetooth e connettersi al dispositivo seriale associato. La porta stessa non ha idea di quanto tempo potrebbe richiedere e probabilmente è impostata per farlo in modo asincrono (anche se sarebbe puramente compito dell'OEM del dispositivo come fatto) per impedire al chiamante di bloccarsi per un lungo periodo se non c'è il dispositivo associato o il dispositivo associato è fuori portata.

Anche se il tuo codice può sembrare un trucco, è probabilmente il modo migliore e più portatile per fare ciò che stai facendo.

Potresti utilizzare un'API di stack bluetooth per provare a vedere se il dispositivo è presente e attivo prima della connessione, ma non esiste una standardizzazione delle API di stack, quindi le API Widcom e Microsoft differiscono su come lo faresti e Widcom è proprietario e costoso. Quello che finiresti è un casino nel tentativo di scoprire il tipo di stack, caricando in modo dinamico una classe di verificatore appropriata, facendola chiamare lo stack e cercare il dispositivo. Alla luce di ciò, il tuo semplice sondaggio sembra molto più pulito e non devi sborsare qualche $ k per Widcom SDK.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top