Некоторое время назад я увлекался тем, то писал самодельные прошивки для различных готовых устройств. Так, например, сделал пульт для управления солярием из пульта от охранной сигнализации. А что, смотрите сами: корпус есть отличный; уже встроена клавиатура и не просто, а более-менее надежная; есть светодиодные индикаторы и динамик (пищалка); корпус штатно крепится к стене; все собрано красиво и на вид надежно. Внутри есть платка с AVR микроконтроллером, разъемом внутрисхемного программирования. Что осталось: вывести наружу com порт для подключения к серверу; приделать реле для включения пускателя солярия; подключить блок питания; и главное – написать саму прошивку. С этой задачей я справился, потом было еще некоторое количество похожих переделок, я переделывал снятые с учета кассовые аппараты, переделывал вызывную панель от домофона, какие-то блоки сопряжения или внешней памяти от кассовой техники. Общими чертами было то, что уже я имел готовый корпус, схему питания, запуска микроконтроллера, и красивый законченный внешний вид.  После переделок касс, я начал работу по написанию утилиты для красивой печати. Дело в том, что я также разработчик на 1с, с++ и мне приходилось что-то печатать из кучи разных программ на кучу разных устройств. Поэтому я решил сделать суперуниверсальную программу, которая бы могла все: печатать на разные устройства; работать с 1 и 2 мерными штрих кодами; уметь печатать кучей различных шрифтов; иметь возможности по редактированию отдельных символов и создания целиком новых шрифтов; должна быть возможность работы в режиме командной строки (т.е. программа на 1с готовит заранее текстовый файл, потом дает команду на печать); показывать на экране как будет выглядеть документ после печати; уметь работать со шрифтами двойной ширины/высоты, жирными, подчеркнутыми и т.п.; двигать бумагу вперед и назад на любые требуемые интервалы; и еще все что потребуется. Постепенно я создал эту программу, и она уже умеет очень много всего, но вот я подхожу к основной теме статьи. Дело в том, что мне попадались на работе, у заказчиков аппараты АТОЛ. Обычно они назывались Fprint-22, Fprint-55 и еще куча вариантов. Это были совершенно разные ккм и общая черта была только та, что все они работали через драйвера Атол. В аппаратах были разные микроконтроллеры, разные термоголовки, и ширина бумаги была от 45 до 80 мм. Но все они работали через атоловские драйвера.  И часто заказчики хотели помимо основных функций (печать чеков) сэкономить на покупке термопринтера и использовать уже имеющуюся кассу для печати различных не фискальных документов. Это могли быть счета в барах, временные пароли для Wi‑Fi, талоны для въезда на территорию, те же коды для включения солярия на 5 или 10 мин. И я понял, что пришла пора для еще одной модернизации программы. Естественно, так просто на кассе не попечатаешь — это же не принтер. Для начала я выделил три основных ветки драйверов. Это была 6…8 версии, 9 ая версия и 10 ая. Все они имели свои особенности. Чем старше был аппарат, тем больше вероятность, что на самой новой 10-й версии он не заработает. Поскольку я пишу на с++, то взаимодействовать с атоловским драйвером пришлось из с++. Сразу скажу, это был еще тот квест. Тут как раз оказалось все просто. Сначала объявляем переменную  Потом создаем объект: Дальше включаем устройство: И готово, можно делать с кассой все что хочешь. Например, Это полная отрезка ленты. В конце вызываем  И все делов. т. е. ничего сложного. Конечно, перед этим надо было установить сами драйвера и зарегистрировать нужные библиотеки. Потом к проекту на с++ я добавлял файл с заголовками функций fprnm1c.h. Для нее я уже не смог повторить тот фокус что для 6ой. Файл с заголовками я нашел, а дальше был затык. Может быть конечно я что‑то не допер, но создать объект fptr10 у меня не получилось. Пришлось подключать на лету dll от 10ой версии fptr10.dll и извлекать из нее функции. Делал я это так: Вот так удалось подружиться с 10ой версией драйвера. Это была для меня самая нужная версия. Дело в том, что разработчики драйверов применяли несколько видов протокола обмена с кассами. Я знал про 2 и 3 версии. 6ая версия драйверов работала, как я понял со 2ым протоколом, 10ые драйвера с 3им протоколом. А 9ые драйвера были переходными! И в них была возможность выбора 2 или 3 версии протокола! Это было круто, т.к. позволяло работать и со старыми кассами и с новыми. Вот тут я и получил большую часть проблем. Но в итоге все заработало. Делал так: Тут меня ждала еще одна засада. При вызове CreateFptrInterface надо было передавать переменную int. Типа версию драйверов. Я передавал: 9, 0, 1, 6, 8, 10 и вообще хрен знает что, но вызов не срабатывал:‑( В итоге я решил сделать так. Создал цикл от 0 до 10 000 и вызывал эту заразу в цикле со всеми аргументами подряд, пока не вернет нормальное значение. И она вернула! В общем, удалось подобрать число. Если хотите, попробуйте сами подобрать, пишите в коменты что получится. После этой инициализации можно уже было вызывать разные методы. Но тут встал главный вопрос: К драйверу‑то я подключился. Методы вызывались, а дальше?! Как вывести на кассу что‑то нужное, и при этом ее не убить? Для решения этого вопроса, я очень внимательно прочитал руководство программиста по драйверу атол и понял, что единственный шанс — это печатать документ как картинку. Моя программа как раз умела сохранять результат работы в формате BMP, и полдела уже было сделано. Далее я добавил команду для печати уже через драйвер атол и при нажатии соответствующей кнопки сначала формировал BMP файл (конечно же монохром 1 бит на пиксель) и потом уже начинал манипуляции с драйвером. Выглядели они примерно так: Конечно, тут тоже было много подводных камней. Для начала, сам временный файл. Если на windows 7 я отлично его записывал в корень диска С, то на windows 10 этот номер не прокатывал. Даже запуская программу под администратором, первый раз новый файл было не создать. Если только я сам его туда копировал и давал на него полные права, то перезаписывался файл нормально. Потом пришлось перенести сохранение файла в другую папку. Также были сложности с шириной и высотой картинки. Разные аппараты имели разные размеры печатной области. Приходилось подстраиваться.  Еще одна проблема была с невозможностью обратной прокрутки бумаги. Это было нужно для отреза сразу после области печати и для начала печати без полей. Если в аппаратах с моей собственной прошивкой я мог крутить шаговик, как говорится «налево, направо и в другие стороны», то тут вниз бумагу было не протянуть. Может есть тут гуру по атолу, посоветуете в коментах как это можно сделать. Но судя по тому, что даже настоящие чеки касса печатает «особым способом», т. е. без обратной прокрутки, этого не сделать. «Особый способ» — это когда печатается чек и сразу шапка следующего чека, а потом происходит отрез. Отрезается текущий документ, а первые несколько строк следующего при этом уже напечатаны и скрыты под крышкой аппарата. Следующий документ печатается уже не с начала а, например, с 5ой строки. И тоже после его печати печатаются первые 5 строк следующего. В общем, способ не особо удобный. При нем надо чтобы первые строки везде были одинаковые. В общем, программа заработала, несколько аппаратов из имеющегося у меня хлама вообще не смогли ничего распечатать, но это были совсем старые модели, которые имели 2 ленты и ширину бумаги 45 мм. У них просто не было вообще команды печать графики.