Работа со сканерами#

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

Для подключения используются два варианта:

  • 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-порт:

  1. Включите параметр Доступно использование сканеров ШК.

  2. Добавьте в выборку операцию comPortListener.

  3. Создайте операцию обработки считанного значения.

  4. Зарегистрируйте операцию обработки для всех доступных COM-портов или для выбранного порта.

  5. При закрытии интерфейса отмените регистрацию обработчика или закройте выбранный порт.

Настройка работы с 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-кода.

При таком порядке штрихкод имеет приоритет.