LINUX.ORG.RU

Canon LBP-2900 и другие CAPT-принтеры - ПИШУ ДРАЙВЕР

 ,


23

21

Попытался запустить LBP-2900 в Ubuntu. Довольно быстро выяснилось, что фирменный драйвер Canon - полный отстой, не поддерживается, и с этим надо что-то делать. Обнаружил также попытки написания энтузиастами аналогичного драйвера, но для 2900 он не работает. В связь с этим начал обратный инжениринг принтера и решил написать СОБСТВЕННЫЙ ДРАЙВЕР.

UPD: ТЕКУЩЕЕ СОСТОЯНИЕ

Исходники доступны на Github: https://github.com/agalakhov/captdriver

Чеклист к первому релизу:
[X] Передача параметров компрессии Hi-SCoA
[X] Компрессия Hi-SCoA
[X] Поддержка LBP-2900 и LBP-3000
[X] Баг «only 10 bytes»
[X] Печать многих страниц
[X] Ожидание наличия бумаги
[ ] Генерация PPD-файлов

Чеклист ко второму релизу:
[ ] Компрессия SCoA
[ ] Поддержка LBP-810 и LBP-1120

(Текст исходного верхнего поста следует)

Ищу единомышленников для Reverse Engineering протокола принтера. На сегодняшний день мне удалось полностью расшифровать протокол нижнего уровня USB и частично - протокол верхнего уровня. Мой драйвер уже может отсылать страницы на печать. ТРЕБУЕТСЯ расшифровать алгоритм сжатия пиксельных данных (он оказался отличным от алгоритма LBP-810 и, по-видимому, является какой-то модификацией ALPC-сжатия). Попытки прикрутить алгоритм от 810 привели к тому, что принтер включается и печатает, но на бумаге получаются только полосы, линии и регулярные узоры из пикселей. У меня пока нет времени на расшифровку, поэтому прошу помощи.

ОПИСАНИЕ ТОГО, ЧТО УДАЛОСЬ РАСШИФРОВАТЬ

Работать с принтером можно с помощью простого open(«/dev/usb/lp0») - libusb не требуется. Общение идет пакетами довольно простого формата. Формат пакета:

байты 1,2 - код команды - 16 бит (младший байт первый)

байты 3,4 - длина посылки (полная) - 16 бит (очевидно, меньше 4 байт не бывает)

байты с 5 - данные (опционально)

Если суммарная длина посылки превышает 4096 байт, посылка делится на части по 4096 байт.

Компьютер посылает принтеру команду. Принтер отвечает пакетом, содержащим код той же команды и минимум 2 байта данных (код возврата), всего не менее 6 байт. Эти 6 байт читают одним read(). Если длина превышает 6 байт, то затем делается read() на оставшуюся длину (она у меня никогда не превышала 4 килобайта, так что про ограничения ничего не знаю). Если не прочитать ответ принтера и продолжить посылать данные, он зависнет, и его придется выключить и включить снова.

Коды команд:

0xA1A1 - начало работы. Параметров нет (4 байта). Принтер отвечает длинной последовательностью байтов - видимо, номером модели, серийным номером, характеристиками и чем-то еще, я не разбирался.

0xA0A0 - какая-то проверка статуса? Встречается на 810, ни разу не видел на 2900. Параметров нет. Принтер отвечает длинной простышей байтов.

0xA0A8 - запрос какого-то статуса. Параметров нет. В коде возврата - явно битовые флаги.

0xA3A2 - что-то включает, меняет флаги в предыдущей команде. Параметров нет. Ответ всегда 0x0000.

0xE0A0 - проверка готовности. Если в ответе поднят бит 0x0008, то буфер принтера полон, надо ждать и не посылать больше данные.

0xA0A1 - проверка кучи вещей, в том числе наличия бумаги. Как оно работает на 2900 - не знаю.

0xA2A0 - загрузка первой магической последовательности. Параметр: магическая последовательность байтов.

0xE1A1 - загрузка второй магической последовательности.

0xE0A3, 0xE0A2, 0xE0A4 - что-то включают. Всегда идут в начале и в такой последовательности. Их отсутствие никак на печать не влияет(?). Возвращают 0, а при попытке вызвать повторно - 0x8800.

0xE0A5 - третья магическая последовательность.

0xD0A9 - загрузка магической последовательности, непосредственно предшествующая загрузке данных печати. Ответа на эту команду не дожидаются (?).

0xC0A0 - Главная Команда. Загружает в принтер сжатое изображение или его часть. Ответа принтера нет.

0xC0A4 - Конец Загрузки. Выдается сразу после 0xC0A0.

0xE0A7 - Включение Печати. Когда принтер подтвердит готовность после загрузки, выдают эту команду, и принтер начинает печатать. Параметр: 16-битное число 0x0001 (видимо, означающее «включить»).

Дополнительная информация - в исходниках драйвера http://www.boichat.ch/nicolas/capt/

Исходники того, что написал на данный момент, могу прислать.



Последнее исправление: cetjs2 (всего исправлений: 5)

Ответ на: комментарий от Itaris

«новая» это начиная с которой?

Честно говоря, прозевал этот момент. Но 1.5 и новее точно работают. В какой там версии объявили ppdc как «deprecated»?

некоторые принтеры HP и Canon являются клонами

Они неполные клоны. У них одинаковая механика и печатающая часть, но при этом АБСОЛЮТНО разные процессоры. В протоколах нет вообще ничего общего.

Электроника HP лучше. (Точнее, электроника Canon - отстой).

Yampp
() автор топика
Ответ на: комментарий от Yampp

Ну так и я об этом :)

А маркировка то какая угодно может быть. Вот в характеристиках НР обычно указывается, что стоит RISC-процессор и его частота, а в Canon только объем памяти. Но я как-то сомневаюсь, что они стали бы велосипед изобретать. Если копнуть по глубже, то абсолютно все характеристики у принтеров-«клонов» абсолютно идентичны, только приподносятся по разному, особенно на всяких яндекс-маркетах.

С другой стороны, как раз таки памяти они и ставят по разному, так что хз, может и вправду электроника разная, а может просто «ревизия». Насколько реально это проверить?

Itaris
()
Ответ на: комментарий от Itaris

Сравнить разводку плат надо. Процессор - дешевая вещь, подключить процессор другого типа очень легко. Даже если у обоих принтеров процессоры одной архитектуры, но разных производителей, по прошивкам они совместимы уже не будут. Иногда даже при абсолютно идентичных процессорах прошивки не подходят (эта ситуация характерна для китайских планшетов на одинаковых процессорах).

Yampp
() автор топика
Ответ на: комментарий от Artificial_Thought

На гитхабе:

https://github.com/agalakhov/captdriver (пока не работает, какой-то баг то ли в компрессии, то ли в арбитраже)

https://github.com/agalakhov/anticapt (утилиты, которыми я пользовался при RE, в основном продублированы в captdriver)

Установки через make install пока нет, ставить надо руками. Внимание, отладочный файл пишется в /tmp/capt-debug.bin безусловно (времянка только на время отладки, но может стать security hole).

Yampp
() автор топика
Ответ на: комментарий от Yampp

Великолепно! Баг оказался в компрессии и обнаружился тестовым декомпрессором! Картинка на выходе captdefilter в точности совпадает с картинкой на бумаге принтера, абсолютно так же испорчена, пиксел к пикселу. Чиню.

После фикса бага принтер кое-как заработает! Останется в общем-то ерунда - улучшить взаимодействие с CUPS (там сейчас треш). Кто хочет, можете этим заняться. (Не чините порчу картинки при печати, это я сам.)

Yampp
() автор топика
Ответ на: комментарий от Yampp

для сборки captdriver необходимо поправить

diff --git a/configure.ac b/configure.ac
index 35bd087..aa8ab1d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,7 +1,7 @@
 AC_PREREQ([2.69])
 AC_INIT([captdriver], [0.1.0])
 
-AC_CONFIG_SRCDIR([src/common.h])
+AC_CONFIG_SRCDIR([src/hiscoa-common.h])
 
 AM_INIT_AUTOMAKE([1.9 no-dist-gzip dist-xz tar-ustar])
 AC_LANG([C])

драйвер собрался. вечером попробую с принтером 2900

HighwayStar ★★★★★
()
Последнее исправление: HighwayStar (всего исправлений: 1)
Ответ на: комментарий от tazhate

А ssh подойдет?

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

Yampp
() автор топика
Ответ на: комментарий от HighwayStar

для сборки captdriver необходимо поправить

Спасибо. Прозевал. Хотя правильнее src/std.h - он точно никуда не денется.

На 2900 пока печатать будет лажу (время от времени сбиваются строки). Где-то баг в кодировании длины. Баг воспроизводится без принтера на тестировании в hiscoa-decompress.c, так что я его, надеюсь, сегодня поправлю.

Yampp
() автор топика
Ответ на: комментарий от Yampp

В общем, с LBP3000 печатает страницу, твой фильтр под конец выдаёт такое:

CAPT: printer returned only 10 bytes of status
Если послать новый документ на печать, то печатает, но новую страницу нет.

Artificial_Thought ★★★★
()

у меня пока пишет в /var/log/cups/error_log

D [17/Sep/2013:01:11:49 +0900] [Job 7] Start rendering...
D [17/Sep/2013:01:11:49 +0900] [Job 7] Set job-printer-state-message to "Start rendering...", current level=INFO
D [17/Sep/2013:01:11:49 +0900] [Job 7] Processing page 1...
D [17/Sep/2013:01:11:49 +0900] [Job 7] Set job-printer-state-message to "Processing page 1...", current level=INFO
D [17/Sep/2013:01:11:49 +0900] [Job 7] CAPT: rastertocapt is rendering
D [17/Sep/2013:01:11:49 +0900] [Job 7] CAPT: rastertocapt: start job
D [17/Sep/2013:01:11:49 +0900] [Job 7] CAPT: send  A1 A1 04 00
D [17/Sep/2013:01:11:49 +0900] [Job 7] backendDrainOutput(print_fd=0, device_fd=5)
D [17/Sep/2013:01:11:49 +0900] [Job 7] Read 4 bytes of print data...
D [17/Sep/2013:01:11:49 +0900] [Job 7] Wrote 4 bytes of print data...
D [17/Sep/2013:01:11:49 +0900] [Job 7] Set job-printer-state-message to "CAPT: no reply from backend", current level=ERROR
D [17/Sep/2013:01:11:49 +0900] [Job 7] End of messages
D [17/Sep/2013:01:11:49 +0900] [Job 7] printer-state=3(idle)
D [17/Sep/2013:01:11:49 +0900] [Job 7] printer-state-message="CAPT: no reply from backend"
D [17/Sep/2013:01:11:49 +0900] [Job 7] printer-state-reasons=none

файла /tmp/capt-debug.bin почему-то нет

HighwayStar ★★★★★
()
Ответ на: комментарий от HighwayStar

если exit(1) после no reply from backend закомментировать, то дальше так и нет ответа от принтера

D [17/Sep/2013:01:48:50 +0900] [Job 24] Set job-printer-state-message to "CAPT: no reply from backend", current level=ERROR
D [17/Sep/2013:01:48:50 +0900] [Job 24] CAPT: waiting for 6 bytes
D [17/Sep/2013:01:48:50 +0900] [Job 24] End of messages
D [17/Sep/2013:01:48:50 +0900] [Job 24] printer-state=3(idle)
D [17/Sep/2013:01:48:50 +0900] [Job 24] printer-state-message="CAPT: no reply from printer"
D [17/Sep/2013:01:48:50 +0900] [Job 24] printer-state-reasons=none

cups 1.5.4, openSUSE 12.3

HighwayStar ★★★★★
()
Ответ на: комментарий от Artificial_Thought

В общем, с LBP3000 печатает страницу

Забавно. У меня - нет :) Спасибо. Какие-то определенные особенности изображения ломают компрессор, и я как раз на них наступил. Там еще один баг есть, серьезный, но редко играющий. Тоже уже исправил.

Про «10 байт статуса» знаю. Пока ленюсь чинить, потому что знаю как, а есть более серьезные проблемы, где не знаю и где надо разбираться. Хочу сначала их.

Yampp
() автор топика
Ответ на: комментарий от HighwayStar

а с какой версии cups драйвер должен нормально работать с usb:// ?

Я точно не знаю. С той, в которой починили back channel у бакэнда usb:// - точно работает с 1.6.2 и новее, а про более старые ничего сказать не могу.

Это старый баг в бакэнде usb - неумение отправлять ответы принтера обратно в драйвер (cupsBackChannelRead), из-за которого и пришлось написать capt://. Я внезапно обнаружил, что в 1.6.2 этого бага не стало, но не знаю, в какой именно момент его поправили. По-видимому, никакие другие принтеры не требуют полностью двустороннего обмена.

Yampp
() автор топика
Ответ на: комментарий от Yampp

Если что, проблемы у нового драйвера пока такие же, как у старого: не проверяет наличие бумаги, виснет после первой страницы. На самом деле я уже знаю арбитраж, но хочу сначала поправить баги. Все-таки полнофункциональное сжатие - не хухры-мухры, мало ли какие там еще сюрпризы.

Арбитраж, вероятно, одинаков у 2900, 3000, 3010, 3050 и может еще каких-то. Может даже вообще у всех 2900 и выше, но наверняка сказать не могу. В некоторых 3xxx есть quirk - они иногда отсылают длину не двоичным кодом, а BCD, поэтому и висли. Сжатие точно одинаково вообще у всех новых (включая цветные), но отличается формат картинки. (Итого есть два сжатия: старое 810 и новое 2900). Очень хочется расшифровать ответ принтера на команду A1 A1 - судя по всему, он там передает таблицу своих параметров, а это позволит поддержать даже неизвестные принтеры.

Сейчас драйвер опознает только LBP-2900 и LBP-3000, но это искусственное ограничение. Он опознает любой принтер, если его IEEE1284 MDL: указать в списке. Основной код поддержки принтера находится в prn_lbp2900.c, архитектура похожа на драйверы ядра Linux и, надеюсь, очевидна. Экспериментировать с любыми моделями принтеров легко.

Yampp
() автор топика
Ответ на: комментарий от Yampp

UPD: баг с отправкой данных в принтер исправлен. Теперь на LBP-2900 должна правильно печататься 1 страница любой сколь угодно большой сложности.

Чеклист к первому релизу:
[X] Передача параметров компрессии Hi-SCoA
[X] Компрессия Hi-SCoA
[X] Поддержка LBP-2900 и LBP-3000
[ ] Баг «only 10 bytes»
[ ] Печать многих страниц
[ ] Ожидание наличия бумаги
[ ] Генерация PPD-файлов

Чеклист ко второму релизу:
[ ] Компрессия SCoA
[ ] Поддержка LBP-810 и LBP-1120

Затем будут добавляться остальные модели принтеров.

Yampp
() автор топика
Последнее исправление: Yampp (всего исправлений: 1)
Ответ на: комментарий от Yampp

Пробную страницу напечатало, но кропнуло снизу, примерно в одном дюйме от нижнего края листа. На других тестовых изображениях также. После печати листа пишет «CAPT: no reply from backend» и принтер до перезагрузки не отвечает.

Artificial_Thought ★★★★
()
Ответ на: комментарий от Artificial_Thought

Какое последнее сообщение в логах?

Есть ли в логах предупреждение о кропе? Драйвер делает кроп, если картинка слишком велика. Размер картинки по вертикали для кропа стоит почти от фонаря, может быть дело в нем. (Функция lbp2900_page_setup(), число 6268, в общем-то оно как раз на дюйм меньше высоты листа - 600 dpi, весь лист 6898).

Там еще пара багов есть в арбитраже, но на печати одного листа они сказываться не должны. Дойдут руки и до них.

Yampp
() автор топика
Ответ на: комментарий от Artificial_Thought

D [18/Sep/2013:20:15:59 +0400] [Job 74] cutting image from 6794 to 6268 lines

Вот и срезанный дюйм нашелся. Надо 6268 на другое число заменить попробовать.

Зависание интересное, спасибо. Хотя баг во многом понятен. Если в функцию lbp2900_page_epilogue() перед capt_send(CAPT_FIRE, ...) добавить capt_send(CAPT_PRINT_DATA_END, NULL, 0); меняется ли поведение?

Yampp
() автор топика
Ответ на: комментарий от Yampp

Ну в общем добавил эту команду - теперь задание остаётся висеть с статусом про 10 байт, но принтер вполне принимает новые задания. И поменял то число на ту высоту картинки, которую ему сует cups - печатает страницу целиком.

Artificial_Thought ★★★★
()
Ответ на: комментарий от Artificial_Thought

И поменял то число на ту высоту картинки, которую ему сует cups - печатает страницу целиком.

Спасибо. Попробуй сделать вот так:

- if (height > 6268)                                                                                               
-         dims->num_lines = 6268;                                                                                  
- else                                                                                                             
-         dims->num_lines = height;
+ dims->num_lines = 6800; // подобрать

Вплоть до какого-то числа принтер будет нормально работать, а при увеличении хотя бы на единицу начнет дурить. Интересно это число.

Баг «10 байт» исправил.

Yampp
() автор топика

в сусе попробовал cups 1.6.2 и 1.7rc1 из билдсервиса — от принтера так же не ответа как и с 1.5.4.

все что удаётся получить это строка - идентификатор пртньера

может быть в убунте специальные патчи для cups, завтра попробую с livecd

HighwayStar ★★★★★
()
Ответ на: комментарий от HighwayStar

может быть в убунте специальные патчи для cups, завтра попробую с livecd

Я пробовал с дебиана. Специально только что проверил - эту часть cups не патчили.

Yampp
() автор топика
Ответ на: комментарий от Artificial_Thought

На 6800 и перестаёт работать, на 6799 ещё работает.

Спасибо. Ясно. Сам принтер поддерживает до 8192, высота листа A4 равна 6898. Значит, поля < 50 пикселей принтер не устраивают. По ширине запас требуется, похоже, побольше.

Yampp
() автор топика
Ответ на: комментарий от Artificial_Thought

От изменения этого числа картинка сдвигается по горизонтали, только при 592 поля совпадают с заданными.

Этого следовало ожидать: поля в PPD рассчитаны под 592. Но сдвиг не должен быть больше 8 пикселей... Странно.

Отказывает ли принтер при увеличении числа? Ширина листа 4960 пикселей, то есть 620 байт, а US Letter еще шире.

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

Yampp
() автор топика
Ответ на: комментарий от false

А. Кажись понял.

Напечатал пробную страницу, теперь в статусе висит:

Приостановлено пользователем Неизвестно Остановлено «CAPT: no reply from backend»

Хотя печатает, но задания остаются остановленными

false ★★★★★
()
Ответ на: комментарий от false

Хотя печатает, но задания остаются остановленными

Правильно. Драйвер-то еще не готов :)

Потому и установка через make install не работает, потому и инструкций нет - пока это ТОЛЬКО для разработчиков, готовых править баги.

Yampp
() автор топика

проверил на livecd ubuntu 13.04 cups 1.6.2. Здесь уже в логах что-то происходит, хотяд capt команды, но принтер все равно не печатает и заканчивается все на no reply from backend

логи: 1 2 3

PS на всякий случай проверил этот принтер в винде — печатает без проблем

HighwayStar ★★★★★
()
Последнее исправление: HighwayStar (всего исправлений: 1)
Ответ на: комментарий от HighwayStar

если в драйвере сделать

diff --git a/src/capt-command.c b/src/capt-command.c
index fbe5ad8..2c27a13 100644
--- a/src/capt-command.c
+++ b/src/capt-command.c
@@ -70,10 +70,10 @@ static void capt_send_buf(void)
                fflush(stdout);
 
                status = cupsSideChannelDoRequest(CUPS_SC_CMD_DRAIN_OUTPUT,
-                               (char *) tmpbuf, (int *) &tmpsize, 5.0);
+                               (char *) tmpbuf, (int *) &tmpsize, 10.0);
                if (status != CUPS_SC_STATUS_OK) {
                        fprintf(stderr, "ERROR: CAPT: no reply from backend\n");
-                       exit(1);
+//                     exit(1);
                }
        }
 }

то время от времения удается напечатать тестовую страницу cups в сусе и в убунте, но получается примерно 1 раз из 10. Похоже принтер не всегда принимает команды (не успевает?) или не всегда дает на них ответы.

HighwayStar ★★★★★
()
Ответ на: комментарий от HighwayStar

с моим принтером вот с таким кодом стабильная печать

diff --git a/src/capt-command.c b/src/capt-command.c
index fbe5ad8..5684f00 100644
--- a/src/capt-command.c
+++ b/src/capt-command.c
@@ -72,8 +72,11 @@ static void capt_send_buf(void)
                status = cupsSideChannelDoRequest(CUPS_SC_CMD_DRAIN_OUTPUT,
                                (char *) tmpbuf, (int *) &tmpsize, 5.0);
                if (status != CUPS_SC_STATUS_OK) {
-                       fprintf(stderr, "ERROR: CAPT: no reply from backend\n");
-                       exit(1);
+                       fprintf(stderr, "ERROR: CAPT: no reply from backend ERR: %d\n", (int)status);
+                       if (status != CUPS_SC_STATUS_TIMEOUT) 
+                           exit(1);
+                       else
+                           fprintf(stderr, "WARN: CAPT: skip timeout error\n");
                }
        }
 }

видимо принтер отвечает не на все посланные команды (на некоторые команды ответы необязательны(?))

вот вырезки из лога с игнорированием ошибки по таймауту http://paste.org.ru/?rvoko7 проблема возникает после отправки различных команд

интересно было бы глянуть логи захваченные с винды, есть ли там случаи пропусков ответов на команды

HighwayStar ★★★★★
()