Как заставить метод записи последовательного порта дождаться очистки линии перед отправкой данных? - PullRequest
11 голосов
/ 21 октября 2008

Вот некоторые сведения о том, что я пытаюсь сделать:

  1. Открытие последовательного порта с мобильного устройства на принтер Bluetooth.
  2. Отправьте форму EPL / 2 на принтер Bluetooth, чтобы он понимал, как обрабатывать данные, которые он собирается получить.
  3. Как только форма будет получена, отправьте на принтер некоторые данные, которые будут напечатаны на этикетке.
  4. Повторите шаг 3 столько раз, сколько необходимо для печати каждой этикетки.

Шаг 2 происходит только в первый раз, так как форма не должна предшествовать каждому ярлыку. Моя проблема в том, что при отправке формы, если я отправлю данные этикетки слишком быстро, она не будет напечатана. Иногда вместо данных, которые я отправляю, на этикетке печатается надпись «Отказ Bluetooth: радио не работает».

Я нашел способ обойти эту проблему, выполнив следующее:

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

Так что, в принципе, я могу поймать TimeoutException и повторить метод записи после ожидания определенного промежутка времени (три секунды, кажется, работают все время, но меньше, и, кажется, выдает исключение при каждой попытке). После трех попыток я просто предполагаю, что с последовательным портом что-то не так, и сообщаю пользователю.

Этот способ, кажется, работает нормально, но я уверен, что есть лучший способ справиться с этим. В классе SerialPort есть несколько свойств, которые, я думаю, мне нужно использовать, но я не могу найти хорошую документацию или примеры того, как их использовать. Я пытался поиграть с некоторыми из свойств, но ни один из них, кажется, не делает то, что я пытаюсь достичь.

Вот список свойств, с которыми я играл:

  • CDHolding
  • CtsHolding
  • DsrHolding
  • DtrEnable
  • Рукопожатие
  • RtsEnable

Я уверен, что некоторая их комбинация справится с тем, что я пытаюсь сделать более изящно.

Я использую C # (2.0 framework), принтер Zebra QL 220+ Bluetooth и портативное устройство Windows Mobile 6, если это имеет какое-то значение для решений.

Будем благодарны за любые предложения.

[UPDATE]

Следует также отметить, что мобильное устройство использует Bluetooth 2.0, тогда как принтер только в версии 1.1. Я предполагаю, что разница в скорости приводит к тому, что принтер отстает в получении данных.

Ответы [ 3 ]

7 голосов
/ 31 октября 2008

Ну, я нашел способ сделать это, основываясь на двух предложенных предложениях. Мне нужно настроить мой объект последовательного порта следующим образом:

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

Тогда мне просто нужно сделать запись вызова:

serialPort.Write(labelData);

Поскольку принтер Zebra поддерживает программное управление потоком, он отправит значение XOff на мобильное устройство, когда буфер почти заполнен. Это заставляет мобильное устройство ждать отправки значения XOn с принтера, эффективно уведомляя мобильное устройство о том, что оно может продолжить передачу.

Устанавливая свойство тайм-аута записи, я даю общее время, отведенное на передачу, до того, как будет сгенерировано исключение тайм-аута записи. Вы все еще хотите отловить таймаут записи, как я сделал в моем примере кода в вопросе. Тем не менее, нет необходимости повторять цикл 3 (или произвольное количество) раз, пытаясь записывать каждый раз, поскольку программное управление потоком запускает и останавливает передачу записи через последовательный порт.

5 голосов
/ 21 октября 2008

Управление потоком является правильным ответом здесь, и оно может отсутствовать / не реализовано / не применимо к вашему Bluetooth-соединению.

Ознакомьтесь со спецификацией Zebra и посмотрите, реализуют ли они или можно включить программное управление потоком данных (xon, xoff), которое позволит вам увидеть, когда различные буферы заполняются.

Кроме того, блютуз-радио вряд ли сможет передавать быстрее, чем 250k на максимуме. Вы можете искусственно ограничить его до 9600 бит / с - это даст радиоприемнику много места для ретрансляции, исправления ошибок, обнаружения и собственного управления потоком.

Если ничего не помогает, взлом, который вы сейчас используете, неплох, но я бы позвонил в техподдержку Zebra и выяснил, что они рекомендуют, прежде чем сдаться.

-Adam

2 голосов
/ 21 октября 2008

Проблема, скорее всего, не в коде последовательного порта, а в основном стеке Bluetooth. Используемый порт является чисто виртуальным, и маловероятно, что какое-либо подтверждение связи будет даже реализовано (поскольку это будет в значительной степени бессмысленно). CTS / RTS DTR / DSR просто не применимы для того, над чем вы работаете.

Основная проблема заключается в том, что при создании виртуального порта он должен привязываться к стеку Bluetooth и подключаться к сопряженному последовательному устройству. Сам порт понятия не имеет, сколько времени это может занять, и он, вероятно, настроен на асинхронное выполнение этого (хотя это будет зависеть от того, как это будет сделано изготовителем устройства), чтобы предотвратить блокировку вызывающего абонента на длительный период, если нет сопряженное устройство или сопряженное устройство вне диапазона.

Хотя ваш код может казаться взломанным, это, вероятно, лучший, самый переносимый способ сделать то, что вы делаете.

Вы можете использовать API стека bluetooth, чтобы попытаться увидеть, есть ли устройство там и живо перед подключением, но нет стандартизации стековых API, поэтому интерфейсы Widcom и Microsoft различаются по тому, как вы это делаете, и Widcom является частной и дорогой. В результате вы получите бесполезную попытку обнаружить тип стека, динамически загрузить соответствующий класс верификатора, заставить его вызывать стек и искать устройство. В свете этого ваш простой опрос кажется намного чище, и вам не нужно тратить несколько долларов на Widcom SDK.

...