2017年1月26日 星期四

Raspberry Pi 筆記: 解決嵌入式系統列印困境

這年頭講求雲端、講求無紙化,需要印表機的場合已經很少了。但一些傳產或一些生產設備仍有列印報表的需求。

對 PC 來說當然不是問題,但對嵌入式系統來說就很痛苦了。這可以從幾點來分析。

1. 印表機廠商不願公開通訊協議

以筆者跟 ExxxN  交手的經驗,電話轉來轉去到最後就沒下文了(大哥我是在幫你賣印表機耶...)。而印表機市場很大一部份被日系廠商佔據,以日本人的保守習性,要他公開這些資訊很難。

更慘的是好不容易破解了一台印表機,結果破解完剛好他也快停產了,那我是要買一堆放在倉庫嗎?...

2. GDI 印表機極耗 CPU 資源

市面上幾千塊台幣的印表機,大多屬於 GDI(Graphic Device Interface)印表機,把很多影像處理、色彩學的東西丟給 PC 去算,以 HP CP1025nw 這個低價彩色雷射印表機來說,他的列印資料流程圖如下:


上面的解釋略嫌粗糙(詳細可以看 foo2zjs 這個 open source printer driver),不過也差不遠了。
  • RGB 轉 CMYK: 彩色雷射印表機實際上是用 Cyan, Magenta, Yellow, blacK 四個顏色噴出網點逼近原圖
  • 壓縮: CP1025nw 只接受把 RGB 轉 CMYK 後的壓縮資料
上面兩個動作對於 PC 還好,對嵌入式來說就悲劇了,以筆者實驗 ARM9 400MHz 的結果列印一張圖需要將近  1 分鐘,圖形越大、DPI 越高越慘。

至於可以接受 PostScript 的印表機價格都太過昂貴,不適合做為設備的報表產生器。

Raspberry Pi 架設印表機伺服器的優點

RPi 可說是解決嵌入式設備列印問題的救星,甚至比擺一台 PC + Windows 做印表機分享還厲害。這是因為 Linux LPD(Line Printer Daemon)可以接受以 lpr 指令傳過來的圖檔(下圖指令已經用 BusyBox 測試過):

重點是成本也只增加一點點,如果是搭配 Raspberry Zero 那就更殺了。

安裝 CUPS Server

在 RPi 上安裝 CUPS:
root@raspberrypi: ~ $ sudo apt-get install cups
CUPS Web interface 預設只能從 localhost 進入。如果你想讓 user 可以透過本機外的網路設定 CUPS,編輯 /etc/cups/cupsd.conf,將 Listen 修改如下:
Listen your_host_name:631
或是
Port 631
另外編輯以下區塊

    Order allow,deny
    Allow all       #add this line

...

  Order allow,deny
  Allow all         #add this line

重新啟動 CUPS server
root@raspberrypi: ~ $ sudo /etc/init.d/cups restart
接著就可以用打開瀏覽器以 http://192.168.0.xxx:631/ 的形式訪問 CUPS Web interface 了。

如果您想不開想自行編譯 CUPS,這裡有份教學,雖然是日文但不難看懂。

參考資料: How to Add a Printer to Your Raspberry Pi (or Other Linux Computer)

解決 USB 無法列印的問題

在 RPi 一代時碰到一個困擾是 HP CP1025nw 網路列印正常,但透過 USB 列印一直無法成功。現在傳授一招給大家

首先,HP 雷射印表機若是支援網路列印,印表機通常使用 TCP Port 9100 接收列印資料,HP 印表機只要聲稱 JetDirect 大都採用這個方式。

第二,其實 RPi 有抓到印表機,您可以檢查以下路徑是否存在
/dev/usb/lp0
這激發筆者一個想法,如果弄個假的網路印表機攔截 TCP 9100,然後重導到 /dev/usb/lp0 是不是就可以列印呢?

我們請 xinetd 幫我們實現願望,編輯 /etc/xinetd.d/usblp0d
service usblp0d
{
    socket_type = stream
    protocol = tcp
    port = 9100
    wait = no
    user = root
    group = lp
    passenv =
    server = /root/usblp0.sh
    disable = no
    flags = REUSE
    only_from = 127.0.0.1/24
}
usblp0.sh 如下,重導 stdin 到 /dev/usb/lp0
#!/bin/bash
cat - > /dev/usb/lp0
重新啟動 xinetd
root@raspberrypi: ~ $ /etc/init.d/xinetd stop
root@raspberrypi: ~ $ /etc/init.d/xinetd start
雖然說這個方案並沒有讓筆者賺到什麼錢,但卻十分振奮人心,RPi 不只是個玩具,在台灣也有機會走入商業應用!也請大家發表自己的看法,謝謝~

沒有留言:

張貼留言