Как заставить метод записи последовательного порта ждать, пока строка не очистится, прежде чем отправлять свои данные?

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

  • Откройте последовательный порт с мобильного устройства на принтер Bluetooth.
  • Отправьте форму EPL/2 на принтер Bluetooth, чтобы он понимал, как обрабатывать данные, которые он собирается получать.
  • Как только форма получена, отправьте некоторые данные на принтер, которые будут напечатаны на этикетке.
  • Повторите шаг 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

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

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

Любые предложения будут оценены.

[ОБНОВЛЕНИЕ]

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

Ответ 1

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

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

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

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

-Adam

Ответ 2

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

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

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

serialPort.Write(labelData);

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

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

Ответ 3

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

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

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

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