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

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

  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), Bluetooth-принтер Zebra QL 220+ и портативное устройство Windows Mobile 6, если это имеет значение для решений.

Мы ценим любые предложения.

[ОБНОВИТЬ]

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

Джейсон, вы связались с Зеброй, и что они сказали? Мне интересно узнать, чем закончилась эта история ...

Adam Davis 22.12.2009 18:20

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

Jason Down 23.12.2009 01:36
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
11
2
11 258
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

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

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

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

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

Хороший ответ. Я бы записал его в разделе «Когда взлом - это не взлом».

endian 21.10.2008 20:28

Это могло бы объяснить, почему использование любой из опций «ясно для отправки» или «запрос на отправку», похоже, не имело никакого эффекта.

Jason Down 21.10.2008 20:30

Какое-то время займитесь мобильной разработкой, и вы, скорее всего, соберете несколько битов о том, «когда хакерство, а не хакерство». Фактически вы, вероятно, создадите небольшую их библиотеку. Это одна из тех вещей, которые заставляют считать, что разработка настольных компьютеров и разработка устройств - одно и то же, в значительной степени неверно.

ctacke 22.10.2008 01:28

ctacke - я заметил довольно много проблем, пытаясь перенести код из настольного приложения в мобильное приложение. Кажется, что в Compact Framework никогда не было того единственного метода или свойства, которое вам нужно для объекта, тогда как они доступны в обычной платформе .NET. Grrrr.

Jason Down 30.10.2008 05:52
Ответ принят как подходящий

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

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

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

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

-Адам

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

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

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

serialPort.Write(labelData);

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

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

Другие вопросы по теме