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)

А смотрели работу Radu Cotescu http://radu.cotescu.com/2010/03/20/how-to-install-canon-lbp-printers-in-ubuntu/ ? Он его перекомпилял в 64бит, сделал скрипты - у меня отлично встал и работает (правда, у меня не 2900 а 1120, но 2900 у него в списке поддерживаемых есть).

az
()

Ещё один страдалец

Топик-стартер пропал окончательно? Если так, то это грустно. Я тоже обладатель Canon LBP 2900. Помочь в написании драйвера не смогу, но мог бы провести над ним какие-либо испытания.

krotozer
()

патч к текущей версии драйвера из svn, которую можно получить командой

svn co https://foo2capt.svn.sourceforge.net/svnroot/foo2capt foo2capt

Патч:

Index: captdrv.c
===================================================================
--- captdrv.c	(revision 10)
+++ captdrv.c	(working copy)
@@ -25,10 +25,10 @@
 void capt_init_printer(int fd)
 {
     capt_do_cmd(fd, CAPT_RESET);
-//    capt_do_cmd_expect(fd, CAPT_CHKXSTATUS, 0x8A31);
+    capt_do_cmd_expect(fd, CAPT_CHKXSTATUS, 0x8A31);
 
     capt_do_cmd_expect(fd, CAPT_START_0, 0x0000); // X 8A31 -> 8831 ?
-//    capt_do_cmd_expect(fd, CAPT_CHKSTATUS, 0x1000);
+//    capt_do_cmd_expect(fd, CAPT_CHKSTATUS, 0x1000);    
   //  capt_do_cmd_expect(fd, CAPT_CHKXSTATUS, 0x8831);
   //  capt_do_cmd_expect(fd, CAPT_CHKSTATUS, 0x1000);
   //  capt_do_cmd_expect(fd, CAPT_CHKXSTATUS, 0x8831);
@@ -43,9 +43,10 @@
   //  capt_do_cmd_expect(fd, CAPT_CHKXSTATUS, 0x8830);
   //  capt_do_cmd(fd, CAPT_CHKSTATUS);
 
-//    capt_do_cmd_expect(fd, CAPT_START_1, 0x0000);
-//    capt_do_cmd_expect(fd, CAPT_START_2, 0x0000);
-  //  capt_do_cmd_expect(fd, CAPT_START_3, 0x0000);
+	// printer dont want to start without  it
+    capt_do_cmd_expect(fd, CAPT_START_1, 0x0000);
+    capt_do_cmd_expect(fd, CAPT_START_2, 0x0000);
+    capt_do_cmd_expect(fd, CAPT_START_3, 0x0000);
     sleep(1);
 
 //    capt_wait_ready(fd, 0x0100);
@@ -77,4 +78,9 @@
 {
     uint8_t t[] = { 0x01, 0x00 };
     capt_send_packet(fd, CAPT_FIRE, t, sizeof(t));
+    capt_recv_ack(fd);
+    uint8_t page_end[] = { 0x01, 0x00}; //current page number here
+    capt_send_packet(fd, CAPT_PAGE_END,  page_end, sizeof(page_end));
+    capt_recv_ack(fd); //??
+
 }
Index: foo2capt.c
===================================================================
--- foo2capt.c	(revision 10)
+++ foo2capt.c	(working copy)
@@ -35,7 +35,7 @@
 
     {
         struct pam pf;
-        pnm_readpaminit(stdin, &pf, sizeof(pf));
+	pnm_readpaminit(stdin, &pf, PAM_STRUCT_SIZE(tuple_type)); // Fixed for newer netpbm lib
         capt_init_page(fd);
         tuple* row = pnm_allocpamrow(&pf);
         uint8_t crow[4736/8];
Index: Makefile
===================================================================
--- Makefile	(revision 10)
+++ Makefile	(working copy)
@@ -1,10 +1,10 @@
-COLORIZER = grc -e -c conf.gcc
+#COLORIZER = grc -e -c conf.gcc
 GCC = $(COLORIZER) gcc
 GPP = $(COLORIZER) g++
 PKGCONFIG = pkg-config
 
 OFLAGS = -O2
-DBGFLAGS =
+DBGFLAGS = -g
 
 CFLAGS = $(DBGFLAGS) $(OFLAGS) -Wall -Wextra --pedantic -fno-exceptions
 CPPFLAGS = $(CFLAGS) --std=c++0x
Index: captmagic.h
===================================================================
--- captmagic.h	(revision 10)
+++ captmagic.h	(working copy)
@@ -20,7 +20,8 @@
     CAPT_PRINT      = 0xC0A0,
     CAPT_PRINT_END  = 0xC0A4,
     CAPT_NOP        = 0xA0A0,
-    CAPT_FIRE       = 0xE0A7
+    CAPT_FIRE       = 0xE0A7,
+    CAPT_PAGE_END   = 0xE0A9
 };
 
 extern const void* const captmagic_0;

в патче исправлена совместимость с новыми версиями netpbm, из-за которой программа просто сегфолтилась при попытке прочитать файл, об этой ошибке я упоминал выше в треде, добавлен код команды CAPT_PAGE_END, которую необходимо посылать в конце каждой страницы, для того чтобы принтер был способен печатать что-то еще без сброса

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

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

./foo2capt < test.pgm

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

>А что если взять свободный драйвер сходной модели и поработать напильником?

так обычно и поступают, когда хотят написать драйвер:) главное, чтобы принтеры не использовали принципиально разных протоколов

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

>А что если взять свободный драйвер сходной модели и поработать напильником?

Так я так и сделал. Только после напильника не осталось ничего.

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

> патч к текущей версии драйвера из svn

Спасибо за патч! Сейчас в svn будет.

У меня еще есть непонятки насчет самого протокола - что там посылается между полосами? У меня получается только первую полосу печатать.

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

У меня еще есть непонятки насчет самого протокола - что там посылается между полосами? У меня получается только первую полосу печатать.

насколько я понял, из логов снятых в винде, там полностью все то, то закодировано в capt отправляется одним куском и отсылаются по 4096 байт, без дополнительных CAPT команд между ними. по крайней мере 4 первых байта этих пакетов по 4096 байт не являются командами CAPT, а скорее похожи на обычные сжатые данные

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

HighwayStar, могу дать r/w доступ на SVN (включить в разработчики).

да пока ненужно.

у меня вот такой вопрос: ты пробовал через реализованый алгоритм hiscoa прогонять весь файл и сравнивать результат с результатом captfilter? получается идентично или нет?

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

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

Мой файл отличается, но это потому, что hiscoa я делаю только на подмножестве известных мне команд (сложностей не делаю). В файле hiscoa, создаваемом драйвером, после каждой полосы есть какая-то страшная длинная последовательность битов - то ли очень длинная команда, то ли байтовая команда с последующей рассинхронизацией моей читалки, не знаю. Если картинка укладывается в одну полосу, проблем нет, а если больше, то после каждой полосы там в потоке какая-то дребедень должна быть вроде бы.

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

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

ну и дурак же ты, wfrr.

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

PS

Yampp, бог в помощь тебе. Подаешь хороший пример!

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

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

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

Я както собирал пакет под LBP2900 для слаки. Всё завелось с пол оборота. Скачивал с сайта разработчика набор rpm...ов, подогнал напильником и всё. Вот качай, ковыряй, конвертируй под Убунту. http://depositfiles.com/files/ieeyewwp4

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

>Я както собирал пакет под LBP2900 для слаки. Всё завелось с пол оборота.

Молодец. Эта тема об разработке открытого драйвера, а не об ариях красноглазиков про производственные достижения в деле освоения напильника, и об этом тут уже не раз писали.

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

Прямо сейчас тестирую в очередной раз. Так что не затык. Просто замедление.

Народ, кто хочет драйвер - подключайтесь. Там уже 90% работает, принтер печатает, только глючит в определенных случаях.

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

Появилось некоторое понимание того, что же там за страшная последовательность. В конце каждой (кроме последней?) полосы (104 строки пикселов) идут биты - то ли 7, то ли 8 единиц, потом 3 нуля - видимо, это символ конца полосы. Затем идет много единиц - это явно выравнивание по границе, кажется, 32 бит (но точно не меньше 32). В выходе captfilter после этого следует 8 байтов ВНЕ битового потока, и эти байты очень похожи на те, которые предшествуют потоку - похоже на какую-то управляющую последовательность, которая до принтера не доходит. Затем идет следующая полоса.

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

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

Залил новую функцию - добавление magic в конце полосы. Функцию вызывать не стал, она не помогла...

При анализе CAPT-файлов надо искать длинную последовательность единиц. Это выравнивание в конце полосы. Поскольку файл поXORен на 0x43, это выглядит как «BC BC BC». Потом идет что-то вроде «00 80 EC 00 00 00 46 00», что в точности совпадает с последовательностью, непосредственно предшествующей началу hiscoa-потока в файле. И дальше продолжается hiscoa-поток.

Yampp
() автор топика
Ответ на: комментарий от Yampp
$ make
gcc foo2capt.c
foo2capt.c: In function ‘main’:
foo2capt.c:38: warning: implicit declaration of function ‘PAM_STRUCT_SIZE’
foo2capt.c:38: error: ‘tuple_type’ undeclared (first use in this function)
foo2capt.c:38: error: (Each undeclared identifier is reported only once
foo2capt.c:38: error: for each function it appears in.)
make: *** [foo2capt.o] Ошибка 1

Это, собственно, как лечить? =)

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

Заменить PAM_STRUCT_SIZE(...) на sizeof(pf). Это из-за использования старого netpbm. На работе программы не скажется. Потом надо будет ifdef поставить.

Напоминаю, в том виде, в котором сейчас код написан, изображения высотой более 104 пикселей не печатаются.

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

Ага, captfilter бьет не по 104, а по 70 строк в полосе. Последняя полоса кончается на 111111001 + выравнивание, а непоследние - на 1111111000 + выравнивание. Тем не менее, продолжает виснуть во всех вариантах.

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

Данные в принтер идут НЕ одним блоком! Выглядит это примерно так:

A0 C0 04 FF (далее блоками по 4к) так 15 раз, каждый раз с A0 по 0xFF00+4 байта A0 E0 A8 A0 A0 C0 04 FF...

И все равно не понимаю, почему виснет. Есть какое-то требование к содержимому потока и к его разбиению, которое я никак не могу понять.

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

Собственно, драйвер заработал, и теперь пора переписывать его в бакэнд CUPS.

А еще, всех предупреждаю - там делается грязная работа с памятью. Он МОЖЕТ коркаться при печати больших страниц, поскольку там весьма некорректно обрабатывается megabuf.

TODO: - выяснить реальное разрешение принтера - избавиться от megabuf в коде и сделать нормальную посылку кусками - переделать в CUPS backend

Зачем libcaptfilter.so: для reverse-engineering. Драйвер самостоятельный и никаких бинарных файлов не содержит (не считая небольших блобов, написанных в captmagic.c). Но с ним рядом в SVN лежит фирменный файлик и утилитки для его хакинга.

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

Интересно. Он точно запущен в ровно одной инстанции? Точно никто больше не открывает /dev/usb/lp0 ?

У меня есть зависания на печати многостраничных документов из-за некорректного арбитража потока (точнее, из-за отсутствия арбитража). Но таких - нет.

В SVN активные изменения, обновляйте часто.

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