Linux下hp打印机驱动hplip分析

来源:互联网 发布:mac安装win7 编辑:程序博客网 时间:2024/04/29 12:04

Hplip分析

        版本是2.14,源码位置:http://hplipopensource.com。图的来源:http://hplipopensource.com/node/128。实践中使用的打印机型号:Deskjet 1010.分析的目的就是搞清楚一个灰色地带---打印机通信.


1.D-Bus初始化流程

D-Bus的初始化同样是在ui4/devmgr5.py开始的。

ui4/devmgr5.py

01 class DevMgr5(QMainWindow,  Ui_MainWindow):

02     ......

03     # TODO: Make sbus init mandatory success, else exit

04     def initDBus(self):

05         self.dbus_loop = DBusQtMainLoop(set_as_default=True)

06         self.dbus_avail, self.service, self.session_bus = device.init_dbus(self.dbus_loop)

07     ......

08        # Receive events from the session bus

09          self.session_bus.add_signal_receiver(self.handleSessionSignal, sender_keyword='sender',

10              destination_keyword='dest', interface_keyword='interface',

11              member_keyword='member', path_keyword='path')

12     ......

这里调用了base/device.py中的init_dbus()。从第9行可以看出handleSessionSignalD-Bus服务器端回调函数。

base/device.py

01 #

02 # DBus Support

03 #

04 

05 def init_dbus(dbus_loop=None):

06     ......

07         try:

08             if dbus_loop is None:

09                 session_bus = dbus.SessionBus()

10             else:

11                 session_bus = dbus.SessionBus(dbus_loop)

12     ......

13         try:

14             log.debug("Connecting to com.hplip.StatusService (try #1)...")

15             service = session_bus.get_object('com.hplip.StatusService', "/com/hplip/StatusService")

16             dbus_avail = True

17         except dbus.exceptions.DBusException, e:

18             try:

19                 os.waitpid(-1, os.WNOHANG)

20             except OSError:

21                 pass

22 

23             path = utils.which('hp-systray')

24     ......

25             log.debug("Running hp-systray: %s --force-startup" % path)

26 

27             os.spawnlp(os.P_NOWAIT, path, 'hp-systray', '--force-startup')

28 

29             log.debug("Waiting for hp-systray to start...")

30             time.sleep(1)

31 

32             t = 2

33             while True:

34                 try:

35                     log.debug("Connecting to com.hplip.StatusService (try #%d)..." % t)

36                     service = session_bus.get_object('com.hplip.StatusService', "/com/hplip/StatusService")

37     ......

38 

39     return dbus_avail, service,  session_bus

40 

41     ......

42 

27行启动了hp-systray作为d-bus的服务器端。D-bus服务器端启动完毕。

2.D-bus服务器hp-systray端启动

启动命令如下:

$ hp-systray --force-startup -g

说明:-g是调试模式启动

if __name__ == '__main__':    ......    if child_pid1:        # parent (UI)        os.close(w1)        ......                        else: # qt4            try:                import ui4.systemtray as systray            except ImportError:                log.error("Unable to load Qt4 support. Is it installed?")                mod.unlockInstance()                sys.exit(1)                 try:            systray.run(r1)        finally:            mod.unlockInstance()     else:        # child (dbus & device i/o [qt4] or dbus [qt3])        os.close(r1)                if ui_toolkit == 'qt4':            r2, w2 = os.pipe()            r3, w3 = os.pipe()              child_pid2 = os.fork()            if child_pid2:                # parent (dbus)                os.close(r2)                                import hpssd                hpssd.run(w1, w2, r3)                                    else:                # child (device i/o)                os.close(w2)                                import hpdio                hpdio.run(r2, w3)    ......

启动了hpssdhpdiohpssd前者会从w3管道从读取hpdio写入的打印机状态信息。下面单说hpdio如何获取打印机状态当hpdio run起来的时候会做以下调用run(hpdio.py)->queryDevice(device.py)->status.StatusType10(status.py)->StatusType10Status(status.py)来获取打印机状态。

    在queryDevice这个函数中出现了6种与打印机通信方式,分别是:

  1. Type 1/2 (s: or VSTATUS:) status
  2. Type 3/9 LaserJet PML
  3. Type 6: LJ XML
  4. Type 8: LJ PJL
  5. Type 10: LEDM
  6. Type 11: LEDM_FF_CC_0

而我目前分析的这款打印机使用是第5种Type 10: LEDM通信协议 HPMUD_S_EWS_LEDM_CHANNEL。每种通信通信都有关于打印机状态值的定义,另外从这款打印机的DeviceId可以看出应该同时也是支持PJL的,这里先只说第5种LEDM通信方式.LEDM的大体通信方式是基于HTTP,通信USB传输一个HTTP的GET指令,然后再通过USB读取打印机返回的HTTP超文本,一个是XML.

StatusType10Status调用流程:

  1. StatusType10FetchUrl  从打印机获取状态数据
  2. # Parse the product status XML 解析xml,提取状态值
StatusType10FetchUrl调用流程:
  1. getUrl_LEDM
  2. LocalOpenerEWS_LEDM().openhp()
openhp调用流程:(进入LEDM处理流程)
  1. writeEWS_LEDM
  2. readEWS_LEDM
  3. readLEDMData

3.刷新状态的流程

toolbox.py

01 else: # qt4

02     ......

03     from ui4.devmgr5 import DevMgr5

04     ......

第三行可以看出启动了ui4目录下的devmgr5这个python

ui4/devmgr5.py

01 class DevMgr5(QMainWindow,  Ui_MainWindow):

02     ......

03     def initUI(self):

04     ......

05         self.DeviceRefreshAction.setIcon(QIcon(load_pixmap("refresh1", "16x16")))

06         self.connect(self.DeviceRefreshAction, SIGNAL("triggered()"), self.DeviceRefreshAction_activated)

07     ......

08    def DeviceRefreshAction_activated(self):

09        self.DeviceRefreshAction.setEnabled(False)

10        self.requestDeviceUpdate()

11        self.DeviceRefreshAction.setEnabled(True)

12        ......

13    def requestDeviceUpdate(self, dev=None, item=None):

14        """ Submit device update request to update thread. """

15

16       if dev is None:

17            dev = self.cur_device

18

19        if dev is not None:

20            dev.error_state = ERROR_STATE_REFRESHING

21            self.updateDevice(dev, update_tab=False)

22

23            self.sendMessage(dev.device_uri, '', EVENT_DEVICE_UPDATE_REQUESTED)

24      ......

25     def sendMessage(self, device_uri, printer_name, event_code, username=prop.username,

26                     job_id=0, title=''):

27 

28         device.Event(device_uri, printer_name, event_code, username,

29                     job_id, title).send_via_dbus(self.session_bus)

30     .....

从第06行可以看出DeviceRefreshAction的槽是DeviceRefreshAction_activated在行8行,接着调用了requestDeviceUpdate,然后调用了sendMessage,然后调用了device.Event。这个在device.py中。在

base/device.py

01 class Event(object):

02     ......

03     def send_via_dbus(self, session_bus, interface='com.hplip.StatusService'):

04         if session_bus is not None and dbus_avail:

05             log.debug("Sending event %d to %s (via dbus)..." % (self.event_code, interface))

06             msg = lowlevel.SignalMessage('/', interface, 'Event')

07             msg.append(signature=self.dbus_fmt, *self.as_tuple())

08             session_bus.send_message(msg)

09     ......

10 

这里调用的send_message是获取的d-bus实例的send_message,它在hpdio.py中。

hpdio.py

01 def send_message(device_uri, event_code, bytes_written=0):

02     args = [device_uri, '', event_code, prop.username, 0, '', '', bytes_written]

03     msg = lowlevel.SignalMessage('/', 'com.hplip.StatusService', 'Event')

04     msg.append(signature='ssisissi', *args)

05     SessionBus().send_message(msg)

这里是标准的d-bus通信。D-bus在收到这个消息后,会怎么处理,且看以后分析。以上是向服务器端请求事件,服务器端收到事件后会调用handleSessionSignal回调。

handleSessionSignal -> handleStatusReply -> updateDevice。


4.客户端与服务器端交互

        客户端hp-toolbox,服务器端hp-systray.他们分别启动后,如何进行交互是一个重点,基于服务器端是有自己的消息通知和界面显示的,不过只是一般的事件信息。hp-toolbox可以主动获取打印机信息。

        服务器端会主动向打印机设备获取状态信息,客户端获取的要是服务器保存好的状态信息,这个基本属于 生产者-消费者 之间的关系。

        

5.LEDM通信协议

       全称: Low End Data Model(在hplib的status.py中有介绍:def StatusType10(func): # Low End Data Model)。目前已经是HP一个专利专利EP2556480A1.

打开channel调用流程:

openEWS_LEDM -> __openChannel -> hpmudext.open_channel -> hpmud处理

读数据流程:

readEWS_LEDM -> __readChannel -> hpmudext.read_channel -> hpmud处理

写命令流程:

writeEWS_LEDM -> __writeChannel -> hpmudext.write_channel -> hpmud处理

 

       以获取ProductStatusDyn记录一下收发数据的情况。 

        发送命令(报文):

GET /DevMgmt/ProductStatusDyn.xml HTTP/1.1#015#012Accept: text/plain#015#012Host:localhost#015#012User-Agent:hplip#015#012#015#012
       接收数据:

<?xml version="1.0" encoding="UTF-8"?><!-- THIS DATA SUBJECT TO DISCLAIMER(S) INCLUDED WITH THE PRODUCT OF ORIGIN. --><psdyn:ProductStatusDyn xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:dd="http://www.hp.com/schemas/imaging/con/dictionaries/1.0/" xmlns:ad="http://www.hp.com/schemas/imaging/con/ledm/alertdetails/2007/10/31" xmlns:pscat="http://www.hp.com/schemas/imaging/con/ledm/productstatuscategories/2007/10/31" xmlns:locid="http://www.hp.com/schemas/imaging/con/ledm/localizationids/2007/10/31" xmlns:psdyn="http://www.hp.com/schemas/imaging/con/ledm/productstatusdyn/2007/10/31" xsi:schemaLocation="http://www.hp.com/schemas/imaging/con/dictionaries/1.0/ ../schemas/dd/DataDictionaryMasterLEDM.xsd http://www.hp.com/schemas/imaging/con/ledm/alertdetails/2007/10/31 ../schemas/AlertDetails.xsd http://www.hp.com/schemas/imaging/con/ledm/productstatuscategories/2007/10/31 ../schemas/ProductStatusCategories.xsd http://www.hp.com/schemas/imaging/con/ledm/localizationids/2007/10/31 ../schemas/LocalizationIds.xsd http://www.hp.com/schemas/imaging/con/ledm/productstatusdyn/2007/10/31 ../schemas/ProductStatusDyn.xsd"><dd:Version><dd:Revision>SVN-IPG-LEDM.216</dd:Revision><dd:Date>2011-02-08</dd:Date></dd:Version><psdyn:Status><pscat:StatusCategory>closeDoorOrCover</pscat:StatusCategory><locid:StringId>65568</locid:StringId></psdyn:Status><psdyn:AlertTable><dd:ModificationNumber>6</dd:ModificationNumber><psdyn:Alert><ad:ProductStatusAlertID>closeDoorOrCover</ad:ProductStatusAlertID><locid:StringId>65568</locid:StringId><dd:SequenceNumber>5</dd:SequenceNumber><ad:Severity>Error</ad:Severity><ad:AlertPriority>1</ad:AlertPriority><ad:AlertDetails><ad:AlertDetailsDoorCoverLocation>cover</ad:AlertDetailsDoorCoverLocation></ad:AlertDetails><dd:ResourceURI>/DevMgmt/ProductConfigDyn.xml</dd:ResourceURI><dd:ResourceType>ledm:hpLedmProductConfigDyn</dd:ResourceType></psdyn:Alert><psdyn:Alert><ad:ProductStatusAlertID>cartridgeMissing</ad:ProductStatusAlertID><locid:StringId>65537</locid:StringId><dd:SequenceNumber>4</dd:SequenceNumber><ad:Severity>Error</ad:Severity><ad:AlertPriority>11</ad:AlertPriority><ad:AlertDetails><ad:AlertDetailsMarkerColor>Black</ad:AlertDetailsMarkerColor><ad:AlertDetailsConsumableTypeEnum>inkCartridge</ad:AlertDetailsConsumableTypeEnum><ad:AlertDetailsMarkerLocation>1</ad:AlertDetailsMarkerLocation></ad:AlertDetails><dd:ResourceURI>/DevMgmt/ConsumableConfigDyn.xml</dd:ResourceURI><dd:ResourceType>ledm:hpLedmConsumableConfigDyn</dd:ResourceType></psdyn:Alert><psdyn:Alert><ad:ProductStatusAlertID>cartridgeMissing</ad:ProductStatusAlertID><locid:StringId>65537</locid:StringId><dd:SequenceNumber>3</dd:SequenceNumber><ad:Severity>Error</ad:Severity><ad:AlertPriority>11</ad:AlertPriority><ad:AlertDetails><ad:AlertDetailsMarkerColor>CyanMagentaYellow</ad:AlertDetailsMarkerColor><ad:AlertDetailsConsumableTypeEnum>inkCartridge</ad:AlertDetailsConsumableTypeEnum><ad:AlertDetailsMarkerLocation>0</ad:AlertDetailsMarkerLocation></ad:AlertDetails><dd:ResourceURI>/DevMgmt/ConsumableConfigDyn.xml</dd:ResourceURI><dd:ResourceType>ledm:hpLedmConsumableConfigDyn</dd:ResourceType></psdyn:Alert></psdyn:AlertTable></psdyn:ProductStatusDyn>
        pscat:StatusCategory字段记录的正是打印机的当前状态。

6.hpmud分析

        MUlti-point transport Driver or HPMUD represents the I/O layer for HPLIP. HPMUD does not depend on Linux specific libusb extensions. This means any UNIX/Linux derivative that supports libusb may work with HPLIP. A public HPLIP "C" API is exposed through hpmud. See hpmud.h for documentation. A python wrapper for hpmud, called hpmudext, is also available.

        以上是官网介绍,如开头图中所示,hpmud是负责真正和打印机设备进行通信的,它基于libusb开发,所以可以运行于所以含libusb的系统中。hpmud同样实现了多种通信方式:

  1. musb                       基于目前常用的libusb通信.(本次采用打印机正是用这种方式)
  2. musb_libusb01     基于目前较老版本的libusb通信.
  3. jd                              基于jetdirect 的打印机通信.
  4. pml                          和python层对应,是一种打印语言
  5. pp                             Parallel port 并口通信方式
        这里只说musb通信方式,由于基于libusb,所以这里的musb就类似于java和c中的jni只是一个接口的转接,musb会把python传送过来的指令通过libusb直接丢给打印机设备。
        另符上hpmud的调试方法,调试宏DBG的实现是syslog,把这个宏打开会将log信息输出到/var/log/syslog中。

7.C语言实现状态获取

        经过20多天的,无情的看源码,终于有所获。终于把Device.py中获取状态的部分用C语言实现了。提取了关键部分,现在可以正常获取打印机状态。由于之前没有接触过HTTP协议,一个错误的报文格式使得我连续很多天都处于迷茫之中,现在看来在于心智还是不完全成熟,在感觉要成功的时候就静不下心来了,不在阅读最后一段代码,然后有时那段代码才是最重要的。"Door Open"从打印机到PC屏幕的流程终于走通了。
#include <stdio.h>#include <string.h>#include <hpmud.h>#include <malloc.h>#ifdef  DEBUG#define debug(fmt,args...)  debug (fmt ,##args)#define debugX(level,fmt,args...) if (DEBUG>=level) debug(fmt,##args);#else#define debug(fmt,args...)#define debugX(level,fmt,args...)#endif  /* DEBUG */static HPMUD_DEVICE dd;static HPMUD_CHANNEL cd;#define MALLOC(type, n)  (type*)malloc(n*sizeof(type))static int __readChannel(int bytes_to_read, int* reply, int allow_short_read, int timeout){    bytes_to_read = 1024;    char data[1024] = {0};    int ret = 0;    int num_bytes = 0;    int len = 0;    int *p = reply;    while (1)    {        ret = hpmud_read_channel(dd, cd, data, 1024, timeout, &num_bytes);        debug("Result code=%d\n", ret);        len = strlen(data);        if(ret == HPMUD_R_IO_TIMEOUT)        {            debug("I/O timeout\n");            break;        }        if(ret != HPMUD_R_OK)        {            debug("Channel read error\n");            break;        }        //debug("read_buf:%s\n", data);        if(!len)        {            debug("End of data\n");            break;        }        memcpy(p, data, len);        if (num_bytes == bytes_to_read)        {            debug("Full read complete.\n");            break;        }        if (allow_short_read && (num_bytes < bytes_to_read))        {            debug("Allowed short read of %d of %d bytes complete.\n", num_bytes, bytes_to_read);            break;        }    }    debug("Saved %d total bytes to stream.\n", num_bytes);    return num_bytes;}void readLEDMData(){    int timeout = 6;    const char* END_OF_DATA="0\r\n\r\n";    int bytes_read = 0;    int bytes_requested = 1024;    char temp_buf[1024] = {0};  //大小要一致    int chunkedFlag = 1;    char* result = NULL;    char *reply = (int*)MALLOC(unsigned char, 5*1024);    char *offset = reply;    if(reply == NULL)    {        fprintf(stderr, "MALLC FAILURE!\n");        return;    }    bytes_read = __readChannel(bytes_requested, reply, 1, timeout);    offset += bytes_read;    //debug("%s:%s\n", __func__, reply);    // 默认chunked分块.    chunkedFlag = 1;    //result = strtok(reply, "\n");    //debug("result=%s\n", result);    while (bytes_read > 0)    {        bytes_read = __readChannel(bytes_requested, (int*)temp_buf, 1, timeout);        //reply.write(temp_buf.getvalue());        memcpy(offset, temp_buf, bytes_read);        debug("%s:%s\n", __func__, offset);        offset += bytes_read;        if(!chunkedFlag) // Unchunked data        {            // do nothing!        }        else // Chunked data end        {            //END_OF_DATA == temp_buf.getvalue();            if(!strncmp(temp_buf, END_OF_DATA, sizeof(END_OF_DATA)))                break;        }    }    printf("%s:%s\n", __func__, reply);    free(reply);    reply = NULL;}int main(void){    enum HPMUD_RESULT res;    const char *device_uri = "hp:/usb/Deskjet_1010_series?serial=CN39I18M1805S8";    enum HPMUD_IO_MODE io_mode = HPMUD_RAW_MODE;    // 打开设备获得    res = hpmud_open_device(device_uri, io_mode, &dd);    if (res != HPMUD_R_OK)    {        fprintf(stderr, "error opening device (code=%d)\n", res);        return 1;    }    // 打开频道获得频道id    res = hpmud_open_channel(dd, HPMUD_S_EWS_LEDM_CHANNEL, &cd);    if (res != HPMUD_R_OK)    {        fprintf(stderr, "error opening channel (code=%d)\n", res);        return 1;    }    char buf[1024] = "GET /DevMgmt/ProductStatusDyn.xml HTTP/1.1\r\nAccept: text/plain\r\nHost:localhost\r\nUser-Agent:hplip\r\n\r\n";    //char ConsumableConfigDyn[] = "GET /DevMgmt/ConsumableConfigDyn.xml HTTP/1.1#015#012Accept: text/plain#015#012Host:localhost#015#012User-Agent:hplip#015#012#015#012";    int bit = 0;    // 写入命令    res = hpmud_write_channel(dd, cd, buf, 100, 6, &bit);    if (res != HPMUD_R_OK)    {        fprintf(stderr, "error hpmud_write_channel (code=%d)\n", res);        return 1;    }    readLEDMData();    return 0;    hpmud_close_channel(dd, cd);    hpmud_close_device(dd);    return 0;}

        本程序会从打印出所得到状态的数据,pscat:StatusCategory字段中的就是状态值了,其实能到了如《关于打印机状态的获取》提到15个左右的状态,但是这个协议所规定的状态全部罗列出来:

字串

状态

编号

processing

STATUS_PRINTER_PRINTING

1002

ready

STATUS_PRINTER_IDLE

1000

closeDoorOrCover

STATUS_PRINTER_DOOR_OPEN

1802

shuttingDown

STATUS_PRINTER_TURNING_OFF

1003

cancelJob

STATUS_PRINTER_CANCELING

1005

trayEmptyOrOpen

STATUS_PRINTER_OUT_OF_PAPER

1009

jamInPrinter

STATUS_PRINTER_MEDIA_JAM

1014

hardError

STATUS_PRINTER_HARD_ERROR

1018

outputBinFull

STATUS_PRINTER_OUTPUT_BIN_FULL

1002

unexpectedSizeInTray

sizeMismatchInTray

STATUS_PRINTER_MEDIA_SIZE_MISMATCH

1023

insertOrCloseTray2

STATUS_PRINTER_TRAY_2_MISSING

1029

scannerError

EVENT_SCANNER_FAIL

2002

scanProcessing

EVENT_START_SCAN_JOB

2000

scannerAdfLoaded

EVENT_SCAN_ADF_LOADED

2004

scanToDestinationNotSet

EVENT_SCAN_TO_DESTINATION_NOTSET

2005

scanWaitingForPC

EVENT_SCAN_WAITING_FOR_PC

2006

scannerAdfJam

EVENT_SCAN_ADF_JAM

2007

scannerAdfDoorOpen

EVENT_SCAN_ADF_DOOR_OPEN

2008

faxProcessing

EVENT_START_FAX_JOB

3000

faxSending

STATUS_FAX_TX_ACTIVE

3004

faxReceiving

STATUS_FAX_RX_ACTIVE

3005

faxDialing

EVENT_FAX_DIALING

3006

faxConnecting

EVENT_FAX_CONNECTING

3007

faxSendError

EVENT_FAX_SEND_ERROR

3008

faxErrorStorageFull

EVENT_FAX_ERROR_STORAGE_FULL

3009

faxReceiveError

EVENT_FAX_RECV_ERROR

3010

faxBlocking

EVENT_FAX_BLOCKING

3011

inPowerSave

STATUS_PRINTER_POWER_SAVE

1046

incorrectCartridge

STATUS_PRINTER_CARTRIDGE_WRONG

1047

cartridgeMissing

STATUS_PRINTER_CARTRIDGE_MISSING

1048

missingPrintHead

STATUS_PRINTER_PRINTHEAD_MISSING

 

1049

scannerADFMispick

STATUS_SCANNER_ADF_MISPICK

1050

mediaTooShortToAutoDuplex

STATUS_PRINTER_PAPER_TOO_SHORT_TO_AUTODUPLEX

1051

insertOrCloseTray

STATUS_PRINTER_TRAY_2_3_DOOR_OPEN

1052

inkTooLowToPrime

STATUS_PRINTER_INK_TOO_LOW_TO_PRIME

1053

cartridgeVeryLow

STATUS_PRINTER_VERY_LOW_ON_INK

1054

wasteMarkerCollectorAlmostFull

STATUS_PRINTER_SERVICE_INK_CONTAINER_ALMOST_FULL

1055

wasteMarkerCollectorFull

STATUS_PRINTER_SERVICE_INK_CONTAINER_FULL

1056

wasteMarkerCollectorFullPrompt

STATUS_PRINTER_SERVICE_INK_CONTAINER_FULL_PROMPT

1057

missingDuplexer

STATUS_PRINTER_DUPLEX_MODULE_MISSING

1058

printBarStall

STATUS_PRINTER_PRINTHEAD_JAM

1059

outputBinClosed

STATUS_PRINTER_CLEAR_OUTPUT_AREA

1060

outputBinOpened

STATUS_PRINTER_CLEAR_OUTPUT_AREA

1060

reseatDuplexer

STATUS_PRINTER_RESEAT_DUPLEXER

1061

unexpectedTypeInTray

STATUS_PRINTER_MEDIA_TYPE_MISMATCH

1042

manuallyFeed

STATUS_MANUALLY_FEED

1062

 

STATUS_UNKNOWN_CODE

1065

         扩展:目前只是上一个课题的总结。这之后的应用还有不少的问题,如何应用。以及和利用设备节点打印是否冲突,以及能否打印也基于hpmud。。。


8.意外收获

        老天真的会眷恋努力的人,刚在PC上实现基于HPMUD的状态获取,考虑着进行三步走中的更为繁琐的后两步(移植到嵌入式Linux+移植到Android)的时候,上天又送我一份大礼--打印机状态获取的另一种方式:通过DeviceId

        这个可能不一定适合所有打印机,但是可以确定的是完全适应我现在正在调试的这款。关于DeviceId从一开始看打印机相关的东西的时候最先接触到的就是这个DeviceId,可以说我对它的感情也是跌宕起伏。从一喜得DeviceId,到觉得其作用单一,到现在的强大无比。

        下面说点正经的,在《互联网打印协议-rfc2911》的printer-state-reasons章节规定了打印机异常状态码。也就是说除了使用HP自定义的LEDM获取的状态外,同样还可以通过标准的IPP协议得到状态值。由此也能延伸出一个问题,CUPS应该也可以获取打印机状态了,但是却没有做任何显示。至于是为什么,这个还是比较玄乎。

        具体来看DeviceID中含有状态的“S”字段:S:038000C484a01021002c1f01100c2881100;首先说明的是这个其中的都是16进制的数。前两位是版本信息,根据版本信息不同,状态码所在的位置也不同,比如这里的版本号为03,那么状态码在第16位的两位数这里为00转换为10进制也是0,这个状态代表空闲。有时候代码比语言更有说服力。

java版本:

      public int getPrinterStatusCode() {          String deviceId = getPrinterDeivceId();          int ippStatus = -1;          int pSf = 2;            if(deviceId == null)              return ippStatus;                    // somthing          String str[] = deviceId.split(";S:");          if(str.length > 1)          {              if(str[1] != null)              {                  int ver=Integer.parseInt(str[1].substring(0,2), 16);                         /* Position pointer to printer state subfield. */                  switch (ver)                  {                    case 0:                    case 1:                    case 2:                       pSf+=12;                       break;                    case 3:                       pSf+=14;                       break;                    case 4:                       pSf+=18;                       break;                    default:                       Slog.w(LOG_TAG, "WARNING: unknown S-field version=" + ver + "\n");                       pSf+=12;                       break;                  }                  ippStatus = Integer.parseInt(str[1].substring(pSf, pSf + 2), 16);              }          }          return ippStatus;      }

C版本:

static int get_printer_status_code(const char* device_id){const char* id = device_id;    char *pSf;    int ver;    int status = 0;    /* Check for valid S-field in device id string. */    if ((pSf = strstr(id, ";S:")) == NULL)    {    /* No S-field, use status register instead of device id. */    /* do nothing */    goto bugout;    }    else    {       /* Valid S-field, get version number. */       pSf+=3;       ver = 0;       HEX2INT(*pSf, ver);       pSf++;       ver = ver << 4;       HEX2INT(*pSf, ver);       pSf++;       /* Position pointer to printer state subfield. */       switch (ver)       {          case 0:          case 1:          case 2:             pSf+=12;             break;          case 3:             pSf+=14;             break;          case 4:             pSf+=18;             break;          default:             printf("WARNING: unknown S-field version=%d\n", ver);             pSf+=12;             break;       }       /* Extract VStatus.*/       status = 0;       HEX2INT(*pSf, status);       pSf++;       status = status << 4;       HEX2INT(*pSf, status);    }    printf("status:%d\n", status);bugout:    return status;}

状态码对应关系:

   VSTATUS_IDLE = 0,   VSTATUS_BUSY = 1,   VSTATUS_PRNT = 2,      /* io printing */   VSTATUS_OFFF = 3,      /* turning off */   VSTATUS_RPRT = 4,      /* report printing */   VSTATUS_CNCL = 5,      /* canceling */   VSTATUS_IOST = 6,      /* io stall */   VSTATUS_DRYW = 7,      /* dry time wait */   VSTATUS_PENC = 8,      /* pen change */   VSTATUS_OOPA = 9,      /* out of paper */   VSTATUS_BNEJ = 10,      /* banner eject needed */   VSTATUS_BNMZ = 11,      /* banner mismatch */   VSTATUS_PHMZ = 12,      /* photo mismatch */   VSTATUS_DPMZ = 13,      /* duplex mismatch */   VSTATUS_PAJM = 14,      /* media jam */   VSTATUS_CARS = 15,      /* carriage stall */   VSTATUS_PAPS = 16,      /* paper stall */   VSTATUS_PENF = 17,      /* pen failure */   VSTATUS_ERRO = 18,      /* hard error */   VSTATUS_PWDN = 19,      /* power down */   VSTATUS_FPTS = 20,      /* front panel test */   VSTATUS_CLNO = 21       /* clean out tray missing */

    文章至此该结束了。


其它:

Linux打印驱动知识点

1.关于DeviceId各段意义见《ieee_1284

2.关于LEDM见《DISCOVERING PC-CONNECTED DEVICES

3.Syslog见《syslog-example》经过实践输出到了/var/log/syslog.

4.关于Eclipse CD高版本的Memory View不能显示对应的Text.换成Helios Service Release 2使用New Rendrings->Traditional.

5.关于PJL(打印机控制语言)《Printer Job Language Technical Reference Manual》

6.最终选择了基于deviceId的方法来实现,所以暂时不再用hpmud的方法了,但是已经代码已经实现了printDate和基于ledm获取打印机的状态信息。

#include <stdio.h>#include <string.h>#include <hpmud.h>#include <malloc.h>#include <fcntl.h>#include <unistd.h>#include <stdlib.h>#include <pthread.h>#include <stdlib.h>#include <stdarg.h>//#define DEBUG#ifdef  DEBUG#define debug(fmt,args...)  printf (fmt ,##args)#define debugX(level,fmt,args...) if (DEBUG>=level) debug(fmt,##args);#else#define debug(fmt,args...)#define debugX(level,fmt,args...)#endif  /* DEBUG */// hp printer devicestatic HPMUD_DEVICE hd;#define MALLOC(type, n)  (type*)malloc(n*sizeof(type))// HPMUD_I_MAX#define HPMUD_I_MAX  18static int channels[HPMUD_I_MAX] = {0};typedef HPMUD_CHANNEL(open_channel)(void);typedef int(read_func)(int bytes_requested, char* reply, int timeout);enum BACKEND_RESULT{  BACKEND_OK = 0,  BACKEND_FAILED = 1,           /* use error-policy */  BACKEND_HOLD = 3,             /* hold job */  BACKEND_STOP = 4,             /* stop queue */  BACKEND_CANCEL = 5            /* cancel job */};struct pjl_attributes{   int pjl_device;   /* 0=disabled, 1=enabled */   int current_status;   int eoj_pages;        /* end-of-job pages */   int abort;         /* 0=no, 1=yes */   int done;          /* 0=no, 1=yes */   HPMUD_DEVICE dd;   HPMUD_CHANNEL cd;   pthread_t tid;   pthread_mutex_t mutex;   pthread_cond_t done_cond;};#define _STRINGIZE(x) #x#define STRINGIZE(x) _STRINGIZE(x)#define BUG(args...) bug(__FILE__ " " STRINGIZE(__LINE__) ": " args)#ifdef HP_DEBUG   #define DBG(args...) syslog(LOG_INFO, __FILE__ " " STRINGIZE(__LINE__) ": " args)   #define DBG_DUMP(data, size) sysdump((data), (size))   #define DBG_SZ(args...) syslog(LOG_INFO, args)#else   #define DBG(args...)   #define DBG_DUMP(data, size)   #define DBG_SZ(args...)#endif#define RETRY_TIMEOUT 30  /* seconds */#define EXCEPTION_TIMEOUT 45 /* seconds */#define NFAULT_BIT  0x08#define PERROR_BIT  0x20#define OOP             (NFAULT_BIT | PERROR_BIT)#define JAMMED          (PERROR_BIT)#define ERROR_TRAP      (0)#define STATUS_MASK (NFAULT_BIT | PERROR_BIT)#define DEVICE_IS_OOP(reg)  ((reg & STATUS_MASK) == OOP)#define DEVICE_PAPER_JAMMED(reg)  ((reg & STATUS_MASK) == JAMMED)#define DEVICE_IO_TRAP(reg)       ((reg & STATUS_MASK) == ERROR_TRAP)#define HEX2INT(x, i) if (x >= '0' && x <= '9')      i |= x - '0'; \                       else if (x >= 'A' && x <= 'F') i |= 0xA + x - 'A'; \                       else if (x >= 'a' && x <= 'f') i |= 0xA + x - 'a'/* Definitions for hpLogLevel in cupsd.conf. */#define BASIC_LOG          1#define SAVE_PCL_FILE      2#define SAVE_INPUT_RASTERS 4#define SEND_TO_PRINTER_ALSO    8/* Actual vstatus codes are mapped to 1000+vstatus for DeviceError messages. */typedef enum{   VSTATUS_IDLE = 1000,   VSTATUS_BUSY,   VSTATUS_PRNT,      /* io printing */   VSTATUS_OFFF,      /* turning off */   VSTATUS_RPRT,      /* report printing */   VSTATUS_CNCL,      /* canceling */   VSTATUS_IOST,      /* io stall */   VSTATUS_DRYW,      /* dry time wait */   VSTATUS_PENC,      /* pen change */   VSTATUS_OOPA,      /* out of paper */   VSTATUS_BNEJ,      /* banner eject needed */   VSTATUS_BNMZ,      /* banner mismatch */   VSTATUS_PHMZ,      /* photo mismatch */   VSTATUS_DPMZ,      /* duplex mismatch */   VSTATUS_PAJM,      /* media jam */   VSTATUS_CARS,      /* carriage stall */   VSTATUS_PAPS,      /* paper stall */   VSTATUS_PENF,      /* pen failure */   VSTATUS_ERRO,      /* hard error */   VSTATUS_PWDN,      /* power down */   VSTATUS_FPTS,      /* front panel test */   VSTATUS_CLNO       /* clean out tray missing */} VSTATUS;#define EVENT_START_JOB 500#define EVENT_END_JOB 501//const char pjl_status_cmd[] = "\e%-12345X@PJL INFO STATUS \r\n\e%-12345X";static const char pjl_ustatus_cmd[] = "\e%-12345X@PJL USTATUS DEVICE = ON \r\n@PJL USTATUS JOB = ON \r\n@PJL JOB \r\n\e%-12345X";static const char pjl_job_end_cmd[] = "\e%-12345X@PJL EOJ \r\n\e%-12345X";static const char pjl_ustatus_off_cmd[] = "\e%-12345X@PJL USTATUSOFF \r\n\e%-12345X";static int bug(const char *fmt, ...){   char buf[256];   va_list args;   int n;   va_start(args, fmt);   if ((n = vsnprintf(buf, 256, fmt, args)) == -1)      buf[255] = 0;     /* output was truncated */   fprintf(stderr, "%s", buf);   //syslog(LOG_ERR, "%s", buf);   fflush(stderr);   va_end(args);   return n;}/** * 由于使用的数组来实现python中的字典 * 所以要将字符串转化为对应数字 * openChannle和closeChannel中会用到 */static int get_service_name_num(char* service_name){    int ser_name_id = 0;    if(!strncmp(HPMUD_S_PRINT_CHANNEL, service_name, strlen(service_name)))        ser_name_id = 1;    else if(!strncmp(HPMUD_S_PML_CHANNEL, service_name, strlen(service_name)))        ser_name_id = 2;    else if(!strncmp(HPMUD_S_SCAN_CHANNEL, service_name, strlen(service_name)))        ser_name_id = 3;    else if(!strncmp(HPMUD_S_FAX_SEND_CHANNEL, service_name, strlen(service_name)))        ser_name_id = 4;    else if(!strncmp(HPMUD_S_CONFIG_UPLOAD_CHANNEL, service_name, strlen(service_name)))        ser_name_id = 5;    else if(!strncmp(HPMUD_S_CONFIG_DOWNLOAD_CHANNEL, service_name, strlen(service_name)))        ser_name_id = 6;    else if(!strncmp(HPMUD_S_MEMORY_CARD_CHANNEL, service_name, strlen(service_name)))        ser_name_id = 7;    else if(!strncmp(HPMUD_S_EWS_CHANNEL, service_name, strlen(service_name)))        ser_name_id = 8;    else if(!strncmp(HPMUD_S_EWS_LEDM_CHANNEL, service_name, strlen(service_name)))        ser_name_id = 9;    else if(!strncmp(HPMUD_S_SOAP_SCAN, service_name, strlen(service_name)))        ser_name_id = 10;    else if(!strncmp(HPMUD_S_SOAP_FAX, service_name, strlen(service_name)))        ser_name_id = 11;    else if(!strncmp(HPMUD_S_DEVMGMT_CHANNEL, service_name, strlen(service_name)))        ser_name_id = 12;    else if(!strncmp(HPMUD_S_MARVELL_SCAN_CHANNEL, service_name, strlen(service_name)))        ser_name_id = 13;    else if(!strncmp(HPMUD_S_MARVELL_FAX_CHANNEL, service_name, strlen(service_name)))        ser_name_id = 14;    else if(!strncmp(HPMUD_S_LEDM_SCAN, service_name, strlen(service_name)))        ser_name_id = 15;    else if(!strncmp(HPMUD_S_WIFI_CHANNEL, service_name, strlen(service_name)))        ser_name_id = 16;    else        ser_name_id = 0;    return ser_name_id;}static int __closeChannel(char* service_name){    int result_code = 0;    int ser_name_id = get_service_name_num(service_name);    //if not self.mq['io-mode'] == IO_MODE_UNI and    //  if self.io_state == IO_STATE_HP_OPEN://        service_name = service_name.upper();    if(channels[ser_name_id] != 0)    {        printf("Closing %s channel...\n", service_name);        result_code = hpmud_close_channel(hd, channels[ser_name_id]);        if (result_code != HPMUD_R_OK)        {            fprintf(stderr, "error hpmud_close_channel (code=%d)\n", result_code);            return 1;        }        else        {            channels[ser_name_id] = 0;        }    }    return 0;}/* * open channel */static int __openChannel(char* service_name){    int result_code = 0;    int channel_id  = 0;    HPMUD_CHANNEL ret = 0;    int ser_name_id = get_service_name_num(service_name);    if (channels[ser_name_id] == 0)    {        printf("Opening %s channel...\n", service_name);        result_code = hpmud_open_channel(hd, service_name, &channel_id);        if (result_code != HPMUD_R_OK)        {            fprintf(stderr, "error opening channel (code=%d)\n", result_code);            exit(1);        }        else        {            channels[ser_name_id] = channel_id;            debug("channel-id=%d\n", channel_id);            ret = channel_id;        }    }    else    {        printf("already open!\n");        ret = channels[ser_name_id];    }    return ret;}/* * read channel */static int __readChannel(open_channel opener, int bytes_to_read, char* reply, int allow_short_read, int timeout){    bytes_to_read = 1024;    char data[1024] = {0};    int ret = 0;    int num_bytes = 0;    int len = 0;    char *p = reply;    HPMUD_CHANNEL channel_id = opener();    while (1)    {        ret = hpmud_read_channel(hd, channel_id, data, 1024, timeout, &num_bytes);        debug("Result code=%d\n", ret);        len = strlen(data);        if(ret == HPMUD_R_IO_TIMEOUT)        {            debug("I/O timeout\n");            break;        }        if(ret != HPMUD_R_OK)        {            debug("Channel read error\n");            break;        }        //debug("read_buf:%s\n", data);        if(!len)        {            debug("End of data\n");            break;        }        memcpy(p, data, len);        if (num_bytes == bytes_to_read)        {            debug("Full read complete.\n");            break;        }        if (allow_short_read && (num_bytes < bytes_to_read))        {            debug("Allowed short read of %d of %d bytes complete.\n", num_bytes, bytes_to_read);            break;        }    }    debug("Saved %d total bytes to stream.\n", num_bytes);    return num_bytes;}/** * write channel */static int __writeChannel(open_channel opener, const char* data, int total_bytes_to_write){    HPMUD_DEVICE  device_id  = hd;    HPMUD_CHANNEL channel_id = opener();    int          result_code = 0;    int        bytes_written = 0;    const char*             buffer = data;    int            bytes_out = 0;    int      max_message_len = 16384;    int              timeout = 45;    int       bytes_to_write = total_bytes_to_write;    while(bytes_to_write > 0)    {        result_code = hpmud_write_channel(device_id, channel_id, buffer, bytes_to_write < max_message_len ? bytes_to_write : max_message_len, timeout, &bytes_written);        printf("Result code=%d\n", result_code);        if (result_code != HPMUD_R_OK)        {            fprintf(stderr, "Channel write error\n");            return -1;        }        buffer += max_message_len;        bytes_out += bytes_written;        bytes_to_write -= bytes_written;    }    if (total_bytes_to_write != bytes_out)    {        printf("total_bytes_to_write =%d =\\= bytes_out=%d\n", total_bytes_to_write, bytes_out);        return -1;    }    //printf("%s end\n", __func__);    return bytes_out;}static HPMUD_CHANNEL openEWS_LEDM(){    return __openChannel(HPMUD_S_EWS_LEDM_CHANNEL);}static HPMUD_CHANNEL openPrint(){    return __openChannel(HPMUD_S_PRINT_CHANNEL);}static int closePrint(void){    return __closeChannel(HPMUD_S_PRINT_CHANNEL);}static int closeEWS_LEDM(void){    return __closeChannel(HPMUD_S_EWS_LEDM_CHANNEL);}static int readEWS_LEDM(int bytes_requested, char* reply, int timeout){    open_channel* opener = openEWS_LEDM;    return __readChannel(opener, bytes_requested, reply, 1, timeout);}static int writePrint(const char* data, int len){    open_channel* opener = openPrint;    int ret = EXIT_FAILURE;    int result_code = 0;    //TODO:delect hpmud_write_channel    /* Enable unsolicited status. */    //ret = hpmud_write_channel(hd, channel_id, pjl_ustatus_cmd, sizeof(pjl_ustatus_cmd)-1, 5, &bytes_written);    result_code = __writeChannel(opener, data, len);    if(result_code != len)    {    printf("ret != len(%s:%u,%s)\n", __FILE__, __LINE__, __func__);    goto bugout;    }    /* Look for job end status. */    //ret = hpmud_write_channel(hd, channel_id, pjl_ustatus_off_cmd, sizeof(pjl_ustatus_off_cmd)-1, 5, &bytes_written);    result_code = __writeChannel(opener, pjl_job_end_cmd, sizeof(pjl_job_end_cmd)-1);    if(result_code != (sizeof(pjl_job_end_cmd)-1))    {    printf("ret != len(%s:%u,%s)\n", __FILE__, __LINE__, __func__);    goto bugout;    }    ret = EXIT_SUCCESS;bugout:    return ret;}static int writeEWS_LEDM(const char* data, int len){    open_channel* opener = openEWS_LEDM;    return __writeChannel(opener, data, len);}static void readLEDMData(read_func* func, char *reply){    int timeout = 6;    const char* END_OF_DATA="0\r\n\r\n";    int bytes_read = 0;    int bytes_requested = 1024;    char temp_buf[1024] = {0};  //大小要一致    int chunkedFlag = 1;    char *offset = reply;    if(reply == NULL)    {        fprintf(stderr, "MALLC FAILURE!\n");        return;    }    bytes_read = func(bytes_requested, reply, timeout);    offset += bytes_read;    //debug("%s:%s\n", __func__, reply);    // 默认chunked分块.    chunkedFlag = 1;    //result = strtok(reply, "\n");    //debug("result=%s\n", result);    while (bytes_read > 0)    {        bytes_read = readEWS_LEDM(bytes_requested, (char*)temp_buf, timeout);        //reply.write(temp_buf.getvalue());        memcpy(offset, temp_buf, bytes_read);        debug("%s:%s\n", __func__, offset);        offset += bytes_read;        if(!chunkedFlag) // Unchunked data        {            // do nothing!        }        else // Chunked data end        {            //END_OF_DATA == temp_buf.getvalue();            if(!strncmp(temp_buf, END_OF_DATA, sizeof(END_OF_DATA)))                break;        }    }    printf("%s:%s\n", __func__, reply);}static int open_hp(const char* url, char* reply){    char data[512] = {0};    debug("open_hp(%s)\n", url);//    match_obj = http_pat_url.search(url)//    loc = url.split("=")[url.count("=")]    openEWS_LEDM();    sprintf(data, "GET %s HTTP/1.1\r\nAccept: text/plain\r\nHost:localhost\r\nUser-Agent:hplip\r\n\r\n", url);    writeEWS_LEDM(data, strlen(data));    //while dev.readEWS_LEDM(512, reply, timeout=3):        //pass    read_func* func = readEWS_LEDM;    readLEDMData(func, reply);    //reply.seek(0);    //return reply.getvalue();    return 0;}void getEWSUrl_LEDM(const char* url, char* reply){//    int self, url, stream, footer;//    url2 = "%s&loc=%s" % (self.device_uri.replace('hpfax:', 'hp:'), url);//    data = self;//    opener = LocalOpenerEWS_LEDM({});//    opener.open_hp(url2, data);    open_hp(url, reply);    closeEWS_LEDM();}void printData(){    char *buf = (char*)MALLOC(unsigned char, 107968);    if(buf == NULL)    {        fprintf(stderr, "MALLC FAILURE!\n");        return;    }    int fd = open("/home/kangear/bin.bin", O_RDONLY);    if(fd == -1)    {        fprintf(stderr, "open file error!\n");        return;    }    int num = read(fd, buf, 107968);    if(num == -1)    {        fprintf(stderr, "read file error!\n");        return;    }    writePrint(buf, num);    close(fd);    free(buf);    buf = NULL;}/** * device discovery * if there is hp device return EXIT_SUCCESS, but EXIT_FAILURE. */static int device_discovery(){   char buf[HPMUD_LINE_SIZE*64];   int cnt=0, bytes_read, r=EXIT_FAILURE;   enum HPMUD_RESULT stat;   stat = hpmud_probe_devices(HPMUD_BUS_ALL, buf, sizeof(buf), &cnt, &bytes_read);   if (stat != HPMUD_R_OK)      goto bugout;   if (cnt == 0)   {#ifdef HAVE_CUPS11      fprintf(stdout, "direct hp:/no_device_found \"Unknown\" \"hp no_device_found\"\n");#else      fprintf(stdout, "direct hp \"Unknown\" \"HP Printer (HPLIP)\"\n");#endif      goto bugout;   }   else      fprintf(stdout, "%s", buf);   r = EXIT_SUCCESS;bugout:   return r;}static int open_device(const char* device_uri){    //int io_mode = 0;    HPMUD_DEVICE device_id = -1;    int result_code = 0, r = EXIT_FAILURE;    enum HPMUD_IO_MODE io_mode = HPMUD_RAW_MODE;    debug("I/O mode=%d\n", io_mode);    // 打开设备获得    result_code = hpmud_open_device(device_uri, io_mode, &device_id);    if (result_code != HPMUD_R_OK)    {        fprintf(stderr, "error opening device (code=%d)\n", result_code);        goto bugout;    }    hd = device_id; //TODO:delect.    r = EXIT_SUCCESS;bugout:    return r;}/* Map printer status to IPP printer-state-reasons (see RFC-2911). */static int map_ipp_printer_state_reason(int status, const char **state_msg){   if (status >= 1000 && status <= 1999)   {      /* inkjet vstatus */      switch (status)      {         case VSTATUS_IDLE:         case VSTATUS_PRNT:            *state_msg = "none";            break;         case VSTATUS_OOPA:            *state_msg = "media-empty-error";            break;         case(VSTATUS_PAJM):            *state_msg = "media-jam-error";            break;         default:            *state_msg = "other";            break;      }   }   else if (status >= 10000 && status <= 55999)   {      /* laserjet pjl status */      if (status >= 10000 && status <= 10999)         *state_msg = "none";      else if (status >= 41000 && status <= 41999)         *state_msg = "media-empty-error";      else if ((status >= 42000 && status <= 42999) || (status >= 44000 && status <= 44999) || (status == 40022))         *state_msg = "media-jam-error";      else if (status == 40021)         *state_msg = "cover-open-error";      else if (status == 40600)         *state_msg = "toner-empty-error";      else         *state_msg = "other";      /* 40017 - cartridge E-LABEL is unreadable (ie: ljp1005) */   }   else   {      /* Assume hpmud error */      *state_msg = "other";   }   return 0;}/* * get_printer_status * * inputs: *   dd - device descriptor *   pa - see pjl_attributes definition * * outputs: *   return - printer status, 1000 to 1999 = inkjet vstatus, 5000 to 5999 = hpmud error, 10000 to 55999 = pjl status code * */static int get_printer_status(HPMUD_DEVICE dd, HPMUD_CHANNEL cd, struct pjl_attributes *pa){   char id[1024];   char *pSf;   int status, ver, len;   enum HPMUD_RESULT r;   if (pa->pjl_device)   {      pthread_mutex_lock(&pa->mutex);      status = pa->current_status;      pthread_mutex_unlock(&pa->mutex);   }   else   {      status = VSTATUS_IDLE; /* set default */      r = hpmud_get_device_id(dd, id, sizeof(id), &len);//      if (!(r == HPMUD_R_OK || r == HPMUD_R_DEVICE_BUSY))      if (r != HPMUD_R_OK)      {         status = 5000+r;      /* no deviceid, return some error */         goto bugout;      }      /* Check for valid S-field in device id string. */      if ((pSf = strstr(id, ";S:")) == NULL)      {         /* No S-field, use status register instead of device id. */         unsigned int bit_status;         r = hpmud_get_device_status(dd, &bit_status);//         if (!(r == HPMUD_R_OK || r == HPMUD_R_DEVICE_BUSY))         if (r != HPMUD_R_OK)         {            status = 5000+r;      /* no 8-bit status, return some error */            goto bugout;         }         if (DEVICE_IS_OOP(bit_status))            status = VSTATUS_OOPA;         else if (DEVICE_PAPER_JAMMED(bit_status))            status = VSTATUS_PAJM;         else if (DEVICE_IO_TRAP(bit_status))            status = VSTATUS_CARS;      }      else      {         /* Valid S-field, get version number. */         pSf+=3;         ver = 0;         HEX2INT(*pSf, ver);         pSf++;         ver = ver << 4;         HEX2INT(*pSf, ver);         pSf++;         /* Position pointer to printer state subfield. */         switch (ver)         {            case 0:            case 1:            case 2:               pSf+=12;               break;            case 3:               pSf+=14;               break;            case 4:               pSf+=18;               break;            default:               BUG("WARNING: unknown S-field version=%d\n", ver);               pSf+=12;               break;         }         /* Extract VStatus.*/         status = 0;         HEX2INT(*pSf, status);         pSf++;         status = status << 4;         HEX2INT(*pSf, status);         status += 1000;      }   }bugout:   return status;}/* Check printer status, if a valid error state, loop until error condition is cleared. */static int loop_test(HPMUD_DEVICE dd, HPMUD_CHANNEL cd, struct pjl_attributes *pa,        const char *dev, const char *printer, const char *username, const char *jobid, const char *title){   int status, stat;   const char *pstate, *old_state=NULL;   while (1)   {      status = get_printer_status(dd, cd, pa);      map_ipp_printer_state_reason(status, &pstate);      /* Check for user intervention errors. */      if (strstr(pstate, "error"))      {         if (pstate != old_state)         {            if (old_state)            {               /* Clear old error. *///               device_event(dev, printer, status, username, jobid, title);               fprintf(stderr, "STATE: -%s\n", old_state);            }            /* Display error. */            //device_event(dev, printer, status, username, jobid, title);            fprintf(stderr, "STATE: +%s\n", pstate);            old_state = pstate;         }         BUG("ERROR: %d %s; will retry in %d seconds...\n", status, pstate, RETRY_TIMEOUT);         sleep(RETRY_TIMEOUT);         continue;      }      /* Clear any old state. */      if (old_state)         fprintf(stderr, "STATE: -%s\n", old_state);      /* Check for system errors. */      if (status >= 5000 && status <= 5999)      {         /* Display error. */         //device_event(dev, printer, status, username, jobid, title);         BUG("ERROR: %d device communication error!\n", status);         stat = 1;      }      else         stat = 0;      break;   /* done */   }   return stat;}int get_device_id(HPMUD_DEVICE hd){    char id[1024] = {0};    char *pSf;    int status, ver, len;    enum HPMUD_RESULT r;    int ret = EXIT_FAILURE;    r = hpmud_get_device_id(hd, id,sizeof(id), &len);    printf("device_id:%s\n", id);    if (r != HPMUD_R_OK)    {       /* no deviceid, return some error */       goto bugout;    }    /* Check for valid S-field in device id string. */    if ((pSf = strstr(id, ";S:")) == NULL)    {       /* No S-field, use status register instead of device id. */       unsigned int bit_status;       r = hpmud_get_device_status(hd, &bit_status);//         if (!(r == HPMUD_R_OK || r == HPMUD_R_DEVICE_BUSY))       if (r != HPMUD_R_OK)       {          status = 5000+r;      /* no 8-bit status, return some error */          goto bugout;       }//       if (DEVICE_IS_OOP(bit_status))//          status = VSTATUS_OOPA;//       else if (DEVICE_PAPER_JAMMED(bit_status))//          status = VSTATUS_PAJM;//       else if (DEVICE_IO_TRAP(bit_status))//          status = VSTATUS_CARS;    }    else    {       /* Valid S-field, get version number. */       pSf+=3;       ver = 0;       HEX2INT(*pSf, ver);       pSf++;       ver = ver << 4;       HEX2INT(*pSf, ver);       pSf++;       /* Position pointer to printer state subfield. */       switch (ver)       {          case 0:          case 1:          case 2:             pSf+=12;             break;          case 3:             pSf+=14;             break;          case 4:             pSf+=18;             break;          default:             printf("WARNING: unknown S-field version=%d\n", ver);             pSf+=12;             break;       }       /* Extract VStatus.*/       status = 0;       HEX2INT(*pSf, status);       pSf++;       status = status << 4;       HEX2INT(*pSf, status);       status += 1000;    }    printf("status:%d\n", status);    ret = EXIT_SUCCESS;bugout:    return ret;}static int get_printer_status_code(const char* device_id){const char* id = device_id;    char *pSf;    int ver;    int status = 0;    /* Check for valid S-field in device id string. */    if ((pSf = strstr(id, ";S:")) == NULL)    {    /* No S-field, use status register instead of device id. */    /* do nothing */    goto bugout;    }    else    {       /* Valid S-field, get version number. */       pSf+=3;       ver = 0;       HEX2INT(*pSf, ver);       pSf++;       ver = ver << 4;       HEX2INT(*pSf, ver);       pSf++;       /* Position pointer to printer state subfield. */       switch (ver)       {          case 0:          case 1:          case 2:             pSf+=12;             break;          case 3:             pSf+=14;             break;          case 4:             pSf+=18;             break;          default:             printf("WARNING: unknown S-field version=%d\n", ver);             pSf+=12;             break;       }       /* Extract VStatus.*/       status = 0;       HEX2INT(*pSf, status);       pSf++;       status = status << 4;       HEX2INT(*pSf, status);       status += 1000;    }    printf("status:%d\n", status);bugout:    return status;}static int get_cups_uri(char* cups_uri){    char buf[HPMUD_LINE_SIZE*64];    int cnt=0, bytes_read, r=EXIT_FAILURE;    enum HPMUD_RESULT stat;    stat = hpmud_probe_devices(HPMUD_BUS_ALL, buf, sizeof(buf), &cnt, &bytes_read);    if (stat != HPMUD_R_OK)      goto bugout;    if (cnt == 0)        fprintf(stdout, "direct hp \"Unknown\" \"HP Printer (HPLIP)\"\n");    else        sprintf(cups_uri, buf, strlen(buf));    r = EXIT_SUCCESS;bugout:    return r;}static int make_device_uri(char* dev_uri){    int ret = EXIT_FAILURE;    enum HPMUD_RESULT stat;    char cups_uri[HPMUD_LINE_SIZE*64];    char* p = NULL;    stat = get_cups_uri(cups_uri);    if (stat != EXIT_SUCCESS)      goto bugout;    p = strtok(cups_uri, " ");    if(p == NULL)        goto bugout;    p = strtok(NULL, " ");    if(p == NULL)        goto bugout;    // copy only one device uri and others ignore.    sprintf(dev_uri, p, strlen(p));    debug("dev_uri:%s\n", dev_uri);    ret = EXIT_SUCCESS;bugout:    return ret;}int main(void){    int ret = EXIT_FAILURE;    //const char *device_uri = "hp:/usb/Deskjet_1010_series?serial=CN39I18M1805S8";    //const char *device_uri = "hp:/usb/Deskjet_1000_J110_series?serial=CN2C818N3605YD";    char dev_uri[HPMUD_LINE_SIZE] = {0};    // step 1.    if(device_discovery() != EXIT_SUCCESS)    {        debug("device discovery failed!\n");        goto bugout;    }    printf("device discovery success!\n");    // step 2:解析一个device uri.    if(make_device_uri(dev_uri) !=  EXIT_SUCCESS)    {        debug("make device uri failed!\n");        goto bugout;    }    // step 3:open hp device    if(open_device(dev_uri) !=  EXIT_SUCCESS)    {        debug("open_device device failed!\n");        goto bugout;    }    // step 4: get device id.    get_device_id(hd);    //printData();    //readAttributeFromXml_EWS    //StatusType10();    char* reply = (char*)MALLOC(char, 500*1024);    //获取状态XML    getEWSUrl_LEDM("/DevMgmt/ProductStatusDyn.xml", reply);  // 获取状态    //getEWSUrl_LEDM("/DevMgmt/ConsumableConfigDyn.xml", reply); // 获取耗材配置    free(reply);    reply = NULL;    if (hd >= 0)       hpmud_close_device(hd);    ret = EXIT_SUCCESS;bugout:    return ret;}

打印机异常状态:

N

Windows状态

0

正常

STATUS_PRINTER_IDLE(1000)

1

无法与打印机通信

x

2

出纸盒已关闭

STATUS_PRINTER_OUTPUT_TRAY_CLOSED(1035)

3

门己打开

STATUS_PRINTER_PEN_CHANGE(1008)

4

缺纸

STATUS_PRINTER_OUT_OF_PAPER(1009)

5

卡纸

STATUS_PRINTER_PAPER_STALL(1016)

6

墨盒故障-黑色

STATUS_PRINTER_PEN_FAILURE(1017)

7

墨盒故障-三色

-

8

墨盒故障-黑色-三色

-

9

墨盒丢失

10

单墨盒模式-缺黑色

STATUS_PRINTER_IDLE(1000)

11

单墨盒模式-缺彩色

STATUS_PRINTER_IDLE(1000)

12

无墨  黑色

x

13

无墨  彩色

x

14

无墨  黑色-彩色

x

15

已经安装HP保护墨盒

x

16

检测到使用过的或仿制墨盒

x

 

...

 

注:x代表暂无条件获取, -代表和上条相同。

如果出现6号状态,建议提示提示语墨盒故障或墨盒丢失

 



0 0
原创粉丝点击