• Linux下hp打印机驱动hplip分析


    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-Busserver端回调函数。

    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的server端。D-busserver端启动完成。

    2.D-busserverhp-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在收到这个消息后,会怎么处理,且看以后分析。以上是向server端请求事件。server端收到事件后会调用handleSessionSignal回调。

    handleSessionSignal -> handleStatusReply -> updateDevice。


    4.client与server端交互

            clienthp-toolbox,server端hp-systray.他们分别启动后,怎样进行交互是一个重点,基于server端是有自己的消息通知和界面显示的,只是仅仅是一般的事件信息。

    hp-toolbox能够主动获取打印机信息。

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

            

    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
    ", ret);
            len = strlen(data);
            if(ret == HPMUD_R_IO_TIMEOUT)
            {
                debug("I/O timeout
    ");
                break;
            }
            if(ret != HPMUD_R_OK)
            {
                debug("Channel read error
    ");
                break;
            }
    
            //debug("read_buf:%s
    ", data);
    
            if(!len)
            {
                debug("End of data
    ");
                break;
            }
    
            memcpy(p, data, len);
    
            if (num_bytes == bytes_to_read)
            {
                debug("Full read complete.
    ");
                break;
            }
    
            if (allow_short_read && (num_bytes < bytes_to_read))
            {
                debug("Allowed short read of %d of %d bytes complete.
    ", num_bytes, bytes_to_read);
                break;
            }
        }
    
        debug("Saved %d total bytes to stream.
    ", num_bytes);
        return num_bytes;
    }
    
    void readLEDMData()
    {
        int timeout = 6;
        const char* END_OF_DATA="0
    
    ";
        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!
    ");
            return;
        }
    
        bytes_read = __readChannel(bytes_requested, reply, 1, timeout);
        offset += bytes_read;
        //debug("%s:%s
    ", __func__, reply);
    
        // 默认chunked分块.
        chunkedFlag = 1;
    
        //result = strtok(reply, "
    ");
    
        //debug("result=%s
    ", 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
    ", __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
    ", __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)
    ", 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)
    ", res);
            return 1;
        }
    
        char buf[1024] = "GET /DevMgmt/ProductStatusDyn.xml HTTP/1.1
    Accept: text/plain
    Host:localhost
    User-Agent:hplip
    
    ";
        //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)
    ", 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 + "
    ");
                           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
    ", ver);
                 pSf+=12;
                 break;
           }
    
           /* Extract VStatus.*/
           status = 0;
           HEX2INT(*pSf, status);
           pSf++;
           status = status << 4;
           HEX2INT(*pSf, status);
        }
        printf("status:%d
    ", 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 device
    static HPMUD_DEVICE hd;
    
    #define MALLOC(type, n)  (type*)malloc(n*sizeof(type))
    
    // HPMUD_I_MAX
    #define HPMUD_I_MAX  18
    static 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 
    e%-12345X";
    static const char pjl_ustatus_cmd[] = "e%-12345X@PJL USTATUS DEVICE = ON 
    @PJL USTATUS JOB = ON 
    @PJL JOB 
    e%-12345X";
    static const char pjl_job_end_cmd[] = "e%-12345X@PJL EOJ 
    e%-12345X";
    static const char pjl_ustatus_off_cmd[] = "e%-12345X@PJL USTATUSOFF 
    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...
    ", 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)
    ", 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...
    ", 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)
    ", result_code);
                exit(1);
            }
            else
            {
                channels[ser_name_id] = channel_id;
                debug("channel-id=%d
    ", channel_id);
                ret = channel_id;
            }
        }
        else
        {
            printf("already open!
    ");
            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
    ", ret);
            len = strlen(data);
            if(ret == HPMUD_R_IO_TIMEOUT)
            {
                debug("I/O timeout
    ");
                break;
            }
            if(ret != HPMUD_R_OK)
            {
                debug("Channel read error
    ");
                break;
            }
    
            //debug("read_buf:%s
    ", data);
    
            if(!len)
            {
                debug("End of data
    ");
                break;
            }
    
            memcpy(p, data, len);
    
            if (num_bytes == bytes_to_read)
            {
                debug("Full read complete.
    ");
                break;
            }
    
            if (allow_short_read && (num_bytes < bytes_to_read))
            {
                debug("Allowed short read of %d of %d bytes complete.
    ", num_bytes, bytes_to_read);
                break;
            }
        }
    
        debug("Saved %d total bytes to stream.
    ", 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
    ", result_code);
            if (result_code != HPMUD_R_OK)
            {
                fprintf(stderr, "Channel write error
    ");
                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
    ", total_bytes_to_write, bytes_out);
            return -1;
        }
    
        //printf("%s end
    ", __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)
    ", __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)
    ", __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
    
    ";
        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!
    ");
            return;
        }
    
        bytes_read = func(bytes_requested, reply, timeout);
        offset += bytes_read;
        //debug("%s:%s
    ", __func__, reply);
    
        // 默认chunked分块.
        chunkedFlag = 1;
    
        //result = strtok(reply, "
    ");
    
        //debug("result=%s
    ", 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
    ", __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
    ", __func__, reply);
    
    }
    
    static int open_hp(const char* url, char* reply)
    {
        char data[512] = {0};
        debug("open_hp(%s)
    ", url);
    
    //    match_obj = http_pat_url.search(url)
    //    loc = url.split("=")[url.count("=")]
    
        openEWS_LEDM();
    
        sprintf(data, "GET %s HTTP/1.1
    Accept: text/plain
    Host:localhost
    User-Agent:hplip
    
    ", 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!
    ");
            return;
        }
    
        int fd = open("/home/kangear/bin.bin", O_RDONLY);
        if(fd == -1)
        {
            fprintf(stderr, "open file error!
    ");
            return;
        }
    
        int num = read(fd, buf, 107968);
        if(num == -1)
        {
            fprintf(stderr, "read file error!
    ");
            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"
    ");
    #else
          fprintf(stdout, "direct hp "Unknown" "HP Printer (HPLIP)"
    ");
    #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
    ", 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)
    ", 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
    ", 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
    ", old_state);
                }
    
                /* Display error. */
                //device_event(dev, printer, status, username, jobid, title);
                fprintf(stderr, "STATE: +%s
    ", pstate);
                old_state = pstate;
             }
             BUG("ERROR: %d %s; will retry in %d seconds...
    ", status, pstate, RETRY_TIMEOUT);
             sleep(RETRY_TIMEOUT);
             continue;
          }
    
          /* Clear any old state. */
          if (old_state)
             fprintf(stderr, "STATE: -%s
    ", 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!
    ", 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
    ", 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
    ", ver);
                 pSf+=12;
                 break;
           }
    
           /* Extract VStatus.*/
           status = 0;
           HEX2INT(*pSf, status);
           pSf++;
           status = status << 4;
           HEX2INT(*pSf, status);
           status += 1000;
        }
        printf("status:%d
    ", 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
    ", ver);
                 pSf+=12;
                 break;
           }
    
           /* Extract VStatus.*/
           status = 0;
           HEX2INT(*pSf, status);
           pSf++;
           status = status << 4;
           HEX2INT(*pSf, status);
           status += 1000;
        }
        printf("status:%d
    ", 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)"
    ");
        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
    ", 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!
    ");
            goto bugout;
        }
        printf("device discovery success!
    ");
    
        // step 2:解析一个device uri.
        if(make_device_uri(dev_uri) !=  EXIT_SUCCESS)
        {
            debug("make device uri failed!
    ");
            goto bugout;
        }
    
        // step 3:open hp device
        if(open_device(dev_uri) !=  EXIT_SUCCESS)
        {
            debug("open_device device failed!
    ");
            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号状态,建议提示提示语墨盒故障或墨盒丢失



  • 相关阅读:
    MySQL锁系列3 MDL锁
    MySQL锁系列2 表锁
    MySQL锁系列1
    MySQL open table
    MySQL优化器join顺序
    MySQL优化器cost计算
    MySQL源码 优化器
    MySQL源码 解析器
    MySQL源码 数据结构hash
    微信小程序爬坑日记
  • 原文地址:https://www.cnblogs.com/mfrbuaa/p/5065783.html
Copyright © 2020-2023  润新知