關於印表機狀態的獲取
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow
也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!
關於這個需求很早就考慮了,一直沒敢下手,也不是不敢,是之前下過一次手但是沒有成功。一直過了幾個月騰出一些空閒來解決這個問題。另外說明一下,截止到目前對於這個需求我還沒有一個完全的解決方案。這篇也只是捋下思緒。
關於印表機狀態的問題我在stackoverflow上也作過提問,結果問題就被刪除了,原因有二有人說這個問題是硬體上的問題,所以不在stackoverflow所討論的範圍。另一個或許是自己的英文著實爛的不行了,問題都解釋不清楚。
由於一直沒有死心,所以在平時無聊的時候也會掏出手機搜尋一番,當時唯一的收穫是參考文件[1]中提到的USBHostPrinterGetStatus(),這個神奇的函式沒有寫任何來源,但作者將其描述成是可以獲取印表機狀態的,我著實有那麼一點興奮。但是苦於沒有來源,有點不知所措。不過我還是將其作為一個方向進行了深挖了的。順便找到了
以上是走過的錯路,下面說下我這次走能的小路:1.從Linux中標準的USB印表機驅動著手;2.從HP Device Manager入手。前後者都小有所獲,以下逐個來分析。逐個分析前先把印表機在
NO |
中文 |
英文 |
limit |
1 |
無法與印表機通訊 |
Unable to Communicate with Printer |
E |
2 |
出紙盒已關閉 |
Output Tray Closed |
E |
3 |
門己開啟 |
Door Open |
E |
4 |
缺紙 |
Out of Paper |
E |
5 |
卡紙 |
Paper Jam |
E |
6 |
墨盒故障-黑色 |
Ink Cartridge Failure |
E |
7 |
墨盒故障-三色 |
- |
E |
8 |
墨盒故障-黑色-三色 |
- |
E |
9 |
墨盒丟失 |
Ink Cartrideges Missing |
E |
10 |
單墨盒模式-缺黑色 |
Single Ink Cartridge Mode |
W |
11 |
單墨盒模式-缺彩色 |
- |
W |
12 |
無墨 黑色 |
x |
E |
13 |
無墨 彩色 |
x |
E |
14 |
無墨 黑色-彩色 |
x |
E |
15 |
已經安裝HP保護墨盒 |
HP Protected Cartridge Installed |
I |
16 |
檢測到使用過的或仿製墨盒 |
Used or Counterfeit Cartridge Detected |
I |
方向1是從usblp.c中的驅動著手
結合印表機核心驅動原始碼usblp.c以及Usb協議[5]規定印表機狀態:
驅動的具體實現是在ioctl方法中的LPGETSTATUS命令中返回的狀態,經過實驗確實能獲得一個比較顯著的狀態Out of Paper/Paper Empty這樣一個狀態,應用層的程式碼如下:
#include <stdio.h> #include <sys/types.h> #include <unistd.h> #include <sys/wait.h> #include <dirent.h> #include <string.h> #include <signal.h> #include <fcntl.h> #include <sys/ioctl.h> #include <linux/lp.h>
void getDeviceStatus(int fd) { if(fd < 0) return; int status = 0; ioctl(fd, LPGETSTATUS, &status); printf("%x\n", status); printf("Hello world\n"); }
int main() { int fd = open("/dev/usb/lp0", O_RDWR); getDeviceStatus(fd); close(fd); return 0; } |
不過遺憾的是,這個狀態碼的規律是這樣的:正常0x18;缺紙 0x38;其它統統是0x10。等於我現在只拿到了一個狀態。我的高興勁頭僅僅持續了幾分鐘。
方向2從HP Device Manager的原始碼入手
如下圖,該軟體可以顯示更多的狀態,且還是開源的hplib。從實驗得出該神器可以獲得以上列出的每個狀態。
推導一下這個神器的真實身份:HP Device Manager -> hp-boolbox -> hplib最終確定了hplib。hplib的架構是這樣的:
Hplip的原始碼中有這麼一段,用到libusb.可以獲取印表機狀態:
static int device_status(int fd, unsigned int *status) { libusb_device_handle *hd; int interface; int len, stat=1; unsigned char byte;
hd = fd_table[fd].hd; interface = fd_table[fd].interface;
if (hd == NULL) { BUG("invalid device_status state\n"); goto bugout; }
len = libusb_control_transfer(hd, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE, /* bmRequestType */ LIBUSB_REQUEST_CLEAR_FEATURE, /* bRequest */ 0, /* wValue */ interface, /* wIndex */ &byte, 1, LIBUSB_CONTROL_REQ_TIMEOUT);
if (len < 0) { BUG("invalid device_status: %m\n"); goto bugout; }
*status = (unsigned int)byte; stat = 0; DBG("read actual device_status successfully fd=%d\n", fd);
bugout: return stat; } |
就這幾行程式碼,但卻難住了我,還是靜下心來看看<libusb Developers Guide>。回頭再來繼續。從hplib追蹤到APDK(hp官方支援的非PC平臺的列印驅動),其中包含了與列印通訊以及印表機的錯誤程式碼。只Google出這麼一個好的資料《APDK Developer’s Guide Reference Manual》。這個《hpmud》也相當好,可以清晰的顯示出hplip原始碼結構。
$ sudo apt-get install libhpmud-dev
標準標頭檔案hpmud.h,基於這個開發。Hp.c就是一個獨立的基於libhpmud的程式。我在libhpmud中新增的這個除錯資訊在執行hp.c的時候可以看到,但是在執行hp-toolbox的時候根本沒有反應,又有點懷疑,它的底層沒有用libhpmud這個庫。
如果能將Door open這句話從印表機到螢幕的流程走通,這個狀態的問題基本就可以宣告解決了。但是這個只是設想,真正實現起來並沒有那麼容易。這是一個開篇。
參考文件:
3.《USB Printer Class on an Embedded Host》
4.《How to retrieve USB printer status?》
5.《Universal Serial Bus Device Class Definition for Printing Devices》