Вот некоторая предыстория того, что я пытаюсь сделать:
Шаг 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 есть несколько свойств, которые, как мне кажется, мне нужно использовать, но я не могу найти никакой хорошей документации или примеров того, как их использовать. Я пробовал поиграть с некоторыми свойствами, но, похоже, ни одно из них не делает то, что я пытаюсь достичь.
Вот список свойств, с которыми я играл:
Я уверен, что какая-то комбинация из них более изящно справится с тем, что я пытаюсь сделать.
Я использую C# (2.0 framework), Bluetooth-принтер Zebra QL 220+ и портативное устройство Windows Mobile 6, если это имеет значение для решений.
Мы ценим любые предложения.
[ОБНОВИТЬ]
Следует также отметить, что мобильное устройство использует Bluetooth 2.0, тогда как принтер только версии 1.1. Я предполагаю, что разница в скорости является причиной того, что принтер отстает в получении данных.
Это было некоторое время назад ... Я просто помню, что они рекомендовали программное управление потоком, которое мы уже определили как лучший подход. Я не помню, чтобы они упоминали об ограничении скорости передачи или что-то в этом роде.





Проблема, скорее всего, не в коде последовательного порта, а в базовом стеке Bluetooth. Порт, который вы используете, является чисто виртуальным, и маловероятно, что какое-либо квитирование вообще будет реализовано (поскольку это было бы в значительной степени бессмысленным). CTS / RTS DTR / DSR просто неприменимы для того, над чем вы работаете.
Основная проблема заключается в том, что при создании виртуального порта он должен быть привязан к стеку Bluetooth и подключаться к парному последовательному устройству. Сам порт не знает, сколько времени это может занять, и он, вероятно, настроен на то, чтобы делать это асинхронно (хотя это будет исключительно на усмотрение OEM-производителя устройства), чтобы предотвратить блокировку вызывающего абонента на длительный период, если нет сопряженное устройство или сопряженное устройство вне зоны действия.
Хотя ваш код может показаться взломанным, это, вероятно, лучший и наиболее переносимый способ делать то, что вы делаете.
Вы можете использовать API стека bluetooth, чтобы попытаться проверить, есть ли устройство и живо ли перед подключением, но нет стандартизации API стека, поэтому API Widcom и Microsoft различаются по тому, как вы это делаете, а Widcom является проприетарным и запатентованным. дорогие. В итоге вы получите беспорядок, пытаясь определить тип стека, динамически загружая соответствующий класс верификатора, заставляя его вызывать стек и искать устройство. В свете этого ваш простой опрос кажется намного чище, и вам не нужно выкладывать несколько тысяч долларов на Widcom SDK.
Хороший ответ. Я бы записал его в разделе «Когда взлом - это не взлом».
Это могло бы объяснить, почему использование любой из опций «ясно для отправки» или «запрос на отправку», похоже, не имело никакого эффекта.
Какое-то время займитесь мобильной разработкой, и вы, скорее всего, соберете несколько битов о том, «когда хакерство, а не хакерство». Фактически вы, вероятно, создадите небольшую их библиотеку. Это одна из тех вещей, которые заставляют считать, что разработка настольных компьютеров и разработка устройств - одно и то же, в значительной степени неверно.
ctacke - я заметил довольно много проблем, пытаясь перенести код из настольного приложения в мобильное приложение. Кажется, что в Compact Framework никогда не было того единственного метода или свойства, которое вам нужно для объекта, тогда как они доступны в обычной платформе .NET. Grrrr.
Здесь правильный ответ - управление потоком, и он может не присутствовать / реализовываться / применяться к вашему соединению 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 (или произвольное количество) раз, пытаясь каждый раз писать, поскольку программное управление потоком запускает и останавливает передачу записи через последовательный порт.
Джейсон, вы связались с Зеброй, и что они сказали? Мне интересно узнать, чем закончилась эта история ...