Работа с драйвером ФР "Штрих-М" на уровне протокола

Для работы со своими фискальными регистраторами компания «Штрих-М» написала свой драйвер «Штрих-М: Драйвер ФР».
А для интеграции с программами семейства 1С компании «Штрих-М» пришлось подготовить дополнительный драйвер, который довольно сложно называется: «ПО «ШТРИХ-М: Драйвер ФР» в соответствии с «требованиями к разработке драйверов для фискальных регистраторов» компании 1С».
Это предыстория. А история в том, что, используя драйвер 1С, невозможно выполнить некоторые команды, которые имеет стандартный драйвер «Штрих-М». Например, вывести штрих код.

 Для решения таких ситуаций, когда возможностей драйвера 1С не хватает, есть несколько решений:

  1. Отказаться от драйвера 1С и полностью перейти на драйвер «Штрих-М»
  2. В нужные моменты отключать драйвер 1С, подключать драйвер «Штрих-М», выполнять нужные команды, отключать драйвер «Штрих-М», подключать драйвер 1С.
  3. Использовать низкоуровневые команды с помощью метода DeviceControlHEX.

Пункты 1 и  2 мне показались достаточно неудобными, поэтому переходим к пункту 3.

Сначала описание метода, которое дает 1С:

DeviceControlHEX (DeviceID, TxData, RxData): WordBool УправлениеУстройствомХекс (ИДУстройства, ВхДанные, ВыхДанные)

Команда аналогична команде DeviceControl. Передает низкоуровневую команду устройству. Отличие заключается в том, что входные и выходные данные передаются в виде HEX-строки.

Параметры:

DeviceID: WideString [IN]

 ИДУстройства [ВХ]

Идентификатор устройства

TxData:

WideString [IN]

ВхДанные [ВХ]

Последовательность байт команды, передаваемой в ФР. (см. описание протокола). Например, для команды «гудок» последовательность будет такая (в шестнадцатеричном виде): «13 1E 00 00 00». То есть, последовательность начинается с кода команды (в данном случае «13»), за ним следуют параметры команды (в данном случае – пароль оператора: «1E 00 00 00»). Последовательность задается в виде строки в HEX-формате (разделенные пробелами двузначные шестнадцатеричные числа). RxData: Integer [OUT] ВыхДанные [ВЫХ] Строка с последовательностью байт ответа ФР. Также возвращается в HEX-формате. Возвращаемое значение: Метод возвращает True в случае успешного выполнения операции, в случае ошибки – False

Теперь можно потренироваться в употреблении этого метода.

Приведу пример печати штрих-кода EAN13 с помощью данного метода.

Для этого заглянем в мануал под названием «Протокол работы ФР». Там написано:

Печать штрих-кода

Команда: C2H. Длина сообщения: 10 байт.

Пароль оператора (4 байта)

Штрих-код (5 байт) 000000000000…999999999999

Ответ: С2H. Длина сообщения: 3 байта.

Код ошибки (1 байт)

Порядковый номер оператора (1 байт) 1…30

Получаем такую функцию, для печать штрих-кода:

Функция DeviceControlHEX_ПечатьШтрихкода(Объект, РезультатКоманды, Штрихкод)Экспорт
//Исходный штрих-код:
//2000988614846
//Отсекаем контрольный символ:
//200098861484
//Переводим в шестнадцатеричное
//2E96D251AC
//Меняем порядок:
//AC 51 D2 96 2E

ШтрихкодФР = Лев(Штрихкод, СтрДлина(Штрихкод) - 1);
ШтрихкодФР = ЧислоВФорматеФР(ШтрихкодФР);


КомандаКВыполнению =  "C2" +
" 1E 00 00 00" +
ШтрихкодФР;

КомандаВыполнена = Объект.Драйвер.DeviceControlHEX(Объект.ИДУстройства, КомандаКВыполнению, РезультатКоманды);

КонецФункции
Вспомогательные функции:   
Функция ЧислоВФорматеФР(_Число)

Если _Число = 0 Тогда
Возврат " 00";
КонецЕсли;

// десятичное число в шестнадцатеричное
Шестнадцатеричное = Строка(DecToHex(_Число));

// Если один символ, добавим 0
Если СтрДлина(Шестнадцатеричное) = 1 Тогда
Шестнадцатеричное = "0" + Шестнадцатеричное;
КонецЕсли;

// Если длина не четная добавить ноль
Если СтрДлина(Шестнадцатеричное) % 2 <> 0 Тогда
Шестнадцатеричное = Шестнадцатеричное + "0";
КонецЕсли;

ЧислоФР = "";
Пока СтрДлина(Шестнадцатеричное) > 0 Цикл

ЧислоФР = ЧислоФР + " " + Прав(Шестнадцатеричное, 2);
Шестнадцатеричное = Лев(Шестнадцатеричное, СтрДлина(Шестнадцатеричное) - 2);

КонецЦикла;

Возврат ЧислоФР;

КонецФункции
Функция DecToHex(Знач _Число)

База = 16;
Результат = "";
Пока _Число <> 0 Цикл
Поз =_Число % База;
Результат = Сред("0123456789ABCDEF", Поз + 1, 1) + Результат;
_Число = Цел(_Число / База);
КонецЦикла;

Возврат Результат;

КонецФункции // DecToHex()
 
 
Пример еще одной функции, печатающей произвольный текст нужным шрифтом:
Функция DeviceControlHEX_СтрокиДаннымШрифтом(Объект, РезультатКоманды, Стр, НомерШрифта)Экспорт
// Номер штрифта от 1 до 7

//Печать строки данным шрифтом
//Команда: 2FH. Длина сообщения: 47 байт.
//Пароль оператора(4 байта)
//Флаги(1 байт) Бит0 – контрольная лента, Бит1
//Номер шрифта(1 байт) 0…255
//Печатаемые символы(40 байт)
//Ответ: 2FH. Длина сообщения: 3 байта.
//Код ошибки(1 байт)
//Порядковый номер оператора(1 байт) 1…30

СтрФР = СтрокаВФорматеФР(Стр);

КомандаКВыполнению =  "2F" +
" 1E 00 00 00" +
" 01" +
" 0" + НомерШрифта +
СтрФР;
КомандаВыполнена = Объект.Драйвер.DeviceControlHEX(Объект.ИДУстройства, КомандаКВыполнению, РезультатКоманды);

Возврат КомандаВыполнена;

КонецФункции
 
 
Получается, что если немного напрячься, можно выполнить любою команду, заложенную в "Протоколе работы ФР".
Замечание: насколько я знаю, метод появился с версии драйвера 4.10
Изменения: Добавлена обработка с реальными примерами работы с методом DeviceControlHEX.
Обновление 23.05.2024 
Добавлен пример проверки наличности в кассе перед записью чека возврата.
Т.к. время от времени бывали ситуации когда документ "ЧекККМ в информационной базе провелся, а чек на ФР не пробился.

19 Comments

  1. bigmal

    Мсье знает толк в извращениях! (с) ))

    Переход на работу по упомянутому выше пункту №1, на порядок проще, быстрее и правильнее, чем извращаться с HEX-ами. Ну, разве что для овладения использования данного метода от 1С, но не более того 🙂

    Reply
  2. JohnyDeath

    (1) bigmal, конечно проще, но с оговоркой, что нужные методы есть в родном драйвере.

    Я также использовал и п.2 и п.3 при разработке печати на подкладных документах.

    Подробностей уже и не вспомню, но точно также приходилось играть с HEX-ами. Ес-но, предварительно общался со службой поддержки Штрих-М. Именно они мне сказали, что HEX в некоторых случаях — единственный вариант.

    Reply
  3. dmt

    (1) bigmal, возможно и так :-), но я могу привести свои аргументы.

    1. Используя решение из пункта 3. можно решить все необходимые вопросы с минимальными изменениями типового кода.

    Для меня это было принципиально важно.

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

    Надо и писать нормально 🙂 и тестировать.

    3. Ну и как уже упомянул комрад JohnyDeath, работа напрямую с протоколом позволяет все что описано в протоколе.

    Reply
  4. dmt

    Добавил примеры. В том числе как в человекочитабельном виде получать строковые данные от ФР.

    Reply
  5. kostik_love

    А почему бы не связаться с ребятами из «Штрих-М» и подать заявку на доработку драйвера «ПО «ШТРИХ-М: Драйвер ФР» в соответствии с «требованиями к разработке драйверов для фискальных регистраторов» компании 1С»- что бы в следующей версии все нужные вам функции были.

    а пункты 1, 2, 3 — получается временное решение.

    Reply
  6. dmt

    (5) kostik_love, потому что именно на форуме Штриха от сотрудников Штриха я и получил ответ использовать DeviceControlHEX.

    Reply
  7. webester

    (1)Дописать одну функцию или переписать весь функционал работы с ФР? Хм какой сложный выбор…

    Reply
  8. al2ko

    Бодрого времени суток. Пробовал данный метод на версии драйвера 4.13 и получил сообщение:

    {ВнешняяОбработка.ШтрихМФискальныеРегистраторы.МодульОбъекта(921)}: Метод объекта не обнаружен (DeviceControlHEX)

    КомандаВыполнена = Объект.Драйвер.DeviceControlHEX(Объект.ИДУстройства, КомандаКВыполнению, РезультатКоманды);

    У вас на какой версии работает?

    Reply
  9. dmt

    Привет!

    На кассах стоит 4.10.

    Но, насколько я помню работала и на 4.12.

    А что за конфигурация? Название обработки намекает, что это УТ 11 или Розница 2.

    Насколько я понимаю в этих конфигурациях логика работы торгового оборудования немного изменена.

    Отсюда пара вопросов:

    1. Объект это действительно объект? 🙂

    2. Драйвер действительно драйвер Штриха (DrvFR), а не DrvFR1C?

    Reply
  10. al2ko

    Бодрого времени суток.

    Конфигурация УТ 10.3. Для проверки засунул код в стандартную обработку фискального регистратора ShtrihMFiscalPrinters_v2.

    Драйвер наверно используется DrvFR1C из стандартной обработки.

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

    Мне показалось что представленный тобой способ подойдет.

    Reply
  11. dmt

    (10) Привет!

    Затестил 4.13. У меня тоже не взлетело.

    Ошибок не выдает. И даже частично печатает. Но частично.

    Reply
  12. pomestnik

    А у меня другая печаль).Медленная печать с rdp. Весь штриховский форум кишит сообщениями что надо добавить

    BeginDocument и EndDocument для буферизации.

    Но в DrvFR1C их нету.. .

    И костыль описанный тобой тут не всунуть ибо мне воздействовать на сам драйвер надо… Я правильно понимаю ?

    p.s. интересно можно ли декомпильнуть и пересобрать дллку эту =\r

    Reply
  13. dmt

    (12) По идее, костыль может все что может протокол «Протокол работы ФР».

    Описание протокола можно посмотреть тут:

    ftp://ftp.shtrih-m.ru/download/FR/Doc/ProtocolFR_1_12.pdf

    Reply
  14. anrahell

    // Функция переводит обычную cтроку в шестнадцатеричное представление

    // Параметры:

    // ТекстСообщения — Строка — Текст сообщения

    // ТипКодировки — Число — Тип кодировки (1 — каждый символ представляется 2 байтами, 0 — 1 байтом)

    // Возвращаемое значение: Строка — Строка после перекодировки

    //

    Функция Str2Hex(ТекстСообщения, ТипКодировки)

    СтрокаЗнаков = «»;

    Если ТипКодировки = 1 Тогда

    ДлинаКодаСимвола = 4;

    Иначе

    ДлинаКодаСимвола = 2;

    КонецЕсли;

    Для К = 1 По СтрДлина(ТекстСообщения) Цикл

    СтрокаЗнаков = СтрокаЗнаков + Padl(DecToHex(КодСимвола(Сред(ТекстСообщения, К, 1))), ДлинаКодаСимвола, «0»);

    КонецЦикла;

    Возврат СтрокаЗнаков;

    КонецФункции // Str2Hex()

    // Функция переводит cтроку из шестнадцатеричного представления в обычную строку

    // Параметры:

    // СтрокаСимволов — Строка — Текст в шестнадцатеричном виде

    // ПризнакКода — Строка — Тип кодировки («0» — каждый символ представляется 1 байтами, «1» — 2 байтами)

    // Возвращаемое значение: Строка — Строка после перекодировки

    //

    Функция StrHexToStr(СтрокаСимволов, ПризнакКода) Экспорт

    Если Число(ПризнакКода) = 0 Тогда

    КоличествоСимволов = 2;

    Иначе

    КоличествоСимволов = 4;

    КонецЕсли;

    к = 1;

    Результат = «»;

    Пока к < СтрДлина(СтрокаСимволов) Цикл

    Строка = Сред(СтрокаСимволов, к, КоличествоСимволов);

    Результат = Результат + Символ(HexToDec(Строка));

    к = к + КоличествоСимволов;

    КонецЦикла;

    Возврат Результат;

    КонецФункции // StrHexToStr()

    Reply
  15. ardn

    Подскажите, можно ли воспользоваться данным методом в текущих конфигурациях, где общение программы с устройством идет через компоненту 1С? Не вижу там команды DeviceControlHEX…

    Reply
  16. bigmal

    (15) Юрий, в компоненте а-ля 1С нет практически ничего. Это заусенец на верхушке айсберга в сравнении с возможностями нормального драйвера ))

    Reply
  17. dmt

    (15) В компоненте DrvFR1C такой метод есть, в SMDrvFR1C20 для ККТ такого метода нет.

    Reply
  18. Strange Device

    А с Атоллами ничего подобного не проделывали? Столкнулся с бедой, что при переходе с 8-ых драйверов Атолла на 9-е перестал работать код печати ШК, который раньше работал, вот ищу пути решения проблемы…

    Reply
  19. man-1982

    Подскажите, а как отлаживать такие обработки для фискальников и для ККМ? На примере ут 10.3

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

    Может есть какой то метод, чтобы в 10.3 не выгружать и загружать обработки каждый раз, может они могут подхватываться прямо из кода? Из встроенных обработок конфигуратора?

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *