Работа со сканерами#
Сканер передает считанное значение в систему, после чего прикладной обработчик определяет дальнейшее действие.
Для подключения используются два варианта:
HID — сканер работает в режиме клавиатурной эмуляции и передает последовательность нажатий;
COM-порт — данные принимаются через
Bts_ComPortLib.
В обоих случаях результатом приема является строковое значение, которое можно обработать как штрихкод, QR-код или другой формат данных. Если устройство уже настроено как клавиатурный сканер, используется HID. Для работы через последовательный порт используется COM-механизм.
Подробности формирования кодов приведены на страницах Штрихкоды и QR-коды.
Работа через HID#
Принцип работы#
При работе через HID сканер эмулирует ввод с клавиатуры. Для распознавания ввода сканера используются начальный шаблон, конечный шаблон и таймаут.
Система собирает распознанную последовательность в строку и передает ее прикладной операции. Обработчик получает:
input: String— считанное значение;isByTimeout: Boolean— признак завершения ввода по таймауту.
Если ввод завершен конечным шаблоном, isByTimeout = false. Если операция получила isByTimeout = true, ввод был завершен по таймауту, а не по заданному конечному шаблону.
Префикс и завершающий символ HID-ввода#
Для надежного определения ввода сканер должен передавать уникальный префикс и завершающий символ.
Префикс и завершающий символ задаются средствами самого сканера; способ их настройки зависит от модели устройства.
Например, если сканер передает:
префикс
SCAN:;считанное значение
4601234567890;клавишу Enter после считанного значения,
браузер получает последовательность:
SCAN:4601234567890\r
Если в качестве завершающего символа используется клавиша Enter, KeyDecoder формирует \r.
В прикладную операцию передается только считанное значение:
4601234567890
Начальный и конечный шаблоны в итоговое значение не включаются.
Ограничения HID#
Текущий KeyDecoder поддерживает латинские символы, цифры верхнего ряда клавиатуры, пробельные символы и часть ASCII-знаков. Кириллица, коды цифровой клавиатуры и произвольные Unicode-символы не декодируются.
Поэтому QR-коды с нестандартными символами или бинарным содержимым нельзя надежно передавать этим способом.
Работа через COM-порт#
Общая схема настройки#
Для настройки работы со сканером через COM-порт:
Включите параметр Доступно использование сканеров ШК.
Добавьте в выборку операцию
comPortListener.Создайте операцию обработки считанного значения.
Зарегистрируйте операцию обработки для всех доступных COM-портов или для выбранного порта.
При закрытии интерфейса отмените регистрацию обработчика или закройте выбранный порт.
Настройка работы с COM-портами#
Параметр Доступно использование сканеров ШК (bAllowUseBarCodeScanner) определяет доступность работы с COM-портами.
Путь: Настройка системы > Настройки и сервисы > Настройки модулей системы > Общие настройки модулей > bts.
Параметр действует для всей системы и по умолчанию выключен.
Если параметр выключен, методы открытия и закрытия портов, регистрации обработчиков и обработки поступающих данных завершаются без выполнения действий и вывода сообщений.
Зависимости#
Для работы библиотеки требуются:
сервер приложений версии 1.21.0 или выше;
Gl3BrowserPlugin версии 0.17.0 или выше;
Gl3BrowserExtension версии 0.17.0 или выше.
Проверка наличия и версий требуемых компонентов выполняется при вызове regComOper() и unRegComOper().
Методы openComPortByName() и closeComPortByName() такую проверку не выполняют.
Если при проверке версия сервера приложений, плагина или расширения не соответствует требованиям либо плагин или расширение отсутствует, информация записывается в журнал сервера приложений.
Примечание
Сообщение об ошибке не отображается пользователю в интерфейсе.
Настройка приема данных из COM-порта#
Для приема данных из COM-порта в выборке создайте скрытую операцию comPortListener, вызывающую одноименный метод библиотеки:
@Oper(
visible = false,
visibleOnToolbar = Visibilities.Invisible,
visibleOnMainMenu = Visibilities.Invisible,
visibleOnNavBar = Visibilities.Invisible
)
def comPortListener(): AnyRef =
Bts_ComPortLib().comPortListener()
Операция размещается в выборке, непосредственно работающей с COM-портами, или в одном из ее предков.
Примечание
Операция должна называться comPortListener.
Для одновременной работы с COM-портами из нескольких интерфейсов операцию comPortListener можно разместить в их общей родительской выборке, например в выборке приложения.
Обработка считанного значения#
Создайте операцию, которая принимает сформированное строковое значение и выполняет требуемое действие. Имя этой операции передается при регистрации обработчика COM-порта.
Если операция должна обрабатывать только один вид кода, можно сразу использовать соответствующий метод:
для штрихкода —
Bs_BarCodeLib().openCardByBarcode();для QR-кода —
Bs_QrCodeLib().processQrCode().
Если операция должна обрабатывать и штрихкоды, и QR-коды, используйте порядок, описанный в разделе Обработка штрихкодов и QR-кодов одной операцией.
Регистрация обработчиков COM-портов#
После создания операции обработки зарегистрируйте ее для всех доступных COM-портов или для выбранного порта.
Все доступные порты#
Метод regComOper() принимает имя операции контекстной обработки и регистрирует ее как обработчик для доступных COM-портов.
Вызов метода размещается в beforeOpen() выборки:
override def beforeOpen(): Unit = {
super.beforeOpen()
Bts_ComPortLib().regComOper("onComPortMess")
}
Для отмены регистрации используется unRegComOper():
override def beforeClose(): Unit = {
super.beforeClose()
Bts_ComPortLib().unRegComOper()
}
Метод unRegComOper() не имеет обязательных параметров. Необязательный параметр bpForce используется для принудительного закрытия портов и очистки сведений об их использовании.
Выбранный порт#
Метод openComPortByName() находит указанный COM-порт и регистрирует для него контекстный обработчик.
Параметры:
portName— имя порта, напримерCOM1илиCOM3; регистр символов не учитывается;operName— имя операции контекстной обработки.
Пример:
override def beforeOpen(): Unit = {
super.beforeOpen()
Bts_ComPortLib().openComPortByName("COM3", "onComPortMess")
}
Для закрытия выбранного порта используется closeComPortByName():
override def beforeClose(): Unit = {
super.beforeClose()
Bts_ComPortLib().closeComPortByName("COM3")
}
Сквозной пример для одного COM-порта#
Ниже показан минимальный сценарий для COM3: прием данных, обработка штрихкода и QR-кода и закрытие порта.
@Oper(
visible = false,
visibleOnToolbar = Visibilities.Invisible,
visibleOnMainMenu = Visibilities.Invisible,
visibleOnNavBar = Visibilities.Invisible
)
def comPortListener(): AnyRef =
Bts_ComPortLib().comPortListener()
@Oper(
visible = false,
visibleOnToolbar = Visibilities.Invisible,
visibleOnMainMenu = Visibilities.Invisible,
visibleOnNavBar = Visibilities.Invisible
)
def onComPortMess(spComPortData: String): Unit = {
Bs_BarCodeApi().findBarCode(spComPortData) match {
case Some(_) =>
Bs_BarCodeLib().openCardByBarcode(spComPortData)
case None =>
Bs_QrCodeLib().processQrCode(spComPortData)
}
}
override def beforeOpen(): Unit = {
super.beforeOpen()
Bts_ComPortLib().openComPortByName("COM3", "onComPortMess")
}
override def beforeClose(): Unit = {
super.beforeClose()
Bts_ComPortLib().closeComPortByName("COM3")
}
В этом варианте штрихкод имеет приоритет: если findBarCode() возвращает непустой результат, открывается связанный со штрихкодом объект. Если штрихкод не найден, исходное значение обрабатывается как QR-код.
Обработка и передача полученных данных#
Bts_ComPortLib накапливает данные, поступающие от COM-порта, до получения символа CR. Этот символ используется как признак окончания считанного значения.
Условно полученные данные можно представить так:
4601234567890<CR>
где <CR> обозначает управляющий символ CR. В зарегистрированную операцию будет передано только значение:
4601234567890
Сам символ CR в передаваемое значение не включается.
Если сканер передает последовательность CRLF, символ LF также удаляется и в прикладную операцию не передается.
Данные могут поступать частями. Если CR еще не получен, незавершенное значение сохраняется до поступления следующих данных. После получения CR сформированное значение передается в обработку.
Если в одном фрагменте поступило несколько значений, разделенных CR, каждое из них обрабатывается отдельно.
Передача незавершенного значения по тайм-ауту не предусмотрена.
После формирования завершенного значения библиотека перебирает выборки, зарегистрировавшие контекстные обработчики. Данные передаются обработчику активной выборки.
Обработка штрихкодов и QR-кодов одной операцией#
На этапе приема данных из COM-порта система получает считанное значение как строку и не определяет заранее, является оно штрихкодом или QR-кодом.
Для обработки считанного значения используется зарегистрированная для COM-порта операция-обработчик, например onComPortMess. Если эта операция должна поддерживать оба вида кодов, в ней сначала выполняется поиск зарегистрированного штрихкода.
Если штрихкод найден, открывается связанный с ним объект. Если штрихкод не найден, исходное считанное значение передается в обработку как QR-код.
Пример операции-обработчика:
def onComPortMess(spComPortData: String): Unit = {
Bs_BarCodeApi().findBarCode(spComPortData) match {
case Some(_) =>
Bs_BarCodeLib().openCardByBarcode(spComPortData)
case None =>
Bs_QrCodeLib().processQrCode(spComPortData)
}
}
Метод findBarCode() возвращает Option[NGid]:
Some(...)— штрихкод найден;None— штрихкод с таким значением не найден.
Таким образом, операция onComPortMess определяет дальнейший способ обработки считанной строки:
найденный штрихкод передается в
openCardByBarcode();если штрихкод не найден, исходная строка передается в
processQrCode()для обработки как QR-кода.
При таком порядке штрихкод имеет приоритет.