《基于ARM的多終端自助打印系統(tǒng)》是以前和控制工程學(xué)院的建斌同學(xué)和儀器與電子學(xué)院的培松同學(xué)一起做的一個(gè)創(chuàng)新項(xiàng)目。
最終產(chǎn)品可以完成微信客戶端掃碼打印。感覺構(gòu)思不錯(cuò),現(xiàn)把開發(fā)過程記錄一下。
我們平時(shí)打印的一般流程是這樣:
趕去打印店。在電腦上打開文檔。然后打印。
這樣存在一些缺點(diǎn)。
1. U盤很容易丟。
2. 浪費(fèi)PC機(jī)資源。
打印店里面。每個(gè)人需要打印的話。都要占用一個(gè)臺(tái)式機(jī)。而打印機(jī)只有一臺(tái)。
用臺(tái)式機(jī)作為打印的終端未免太過奢侈??梢哉f除了打印程序所占用的那點(diǎn)內(nèi)存和CPU之外。其他資源都浪費(fèi)了。
3. 邊角零錢。
打印花的經(jīng)常是1角2角的這種邊角零錢。這種錢放在錢包里會(huì)感覺很不方便。于是考慮電子的支付方式。
這個(gè)系統(tǒng)的打印流程是這樣的。
1. 用戶上傳文檔到自己的賬戶。
2. 選擇支付文檔。
3. 掃二維碼打印。
上面的缺點(diǎn)取反就是這個(gè)系統(tǒng)的優(yōu)點(diǎn)了。
具體架構(gòu)是這樣的:
ARM板通過USB線和打印機(jī)連接。
這里采用的ARM板是TQ2440。打印機(jī)是惠普的一款激光打印機(jī)HP_LaserJet_1020。
完成后的系統(tǒng)可以每個(gè)ARM板連接一臺(tái)打印機(jī)。
ARM板還有一個(gè)功能就是動(dòng)態(tài)顯示二維碼。
客戶端和服務(wù)器網(wǎng)絡(luò)連接。
這保證了文檔可以從終端傳到服務(wù)器上。
服務(wù)器的主要功能是實(shí)現(xiàn)賬戶管理。還有激活在ARM板上運(yùn)行的打印后臺(tái)進(jìn)程。
大概整理一下這個(gè)數(shù)據(jù)流。
首先手機(jī)關(guān)注微信公眾號(hào)。可以登錄自己的個(gè)人賬戶。
可以上傳文檔到個(gè)人賬戶。
通過支付來獲得打印權(quán)限。
掃描平臺(tái)隨機(jī)產(chǎn)生的二維碼。就可以發(fā)送請(qǐng)求到服務(wù)器。
服務(wù)器處理請(qǐng)求。這包括檢查權(quán)限等。(看你有沒有付款等)。
服務(wù)器激活各ARM板上的后臺(tái)進(jìn)程。(這里的后臺(tái)進(jìn)程是Linux下的cupsd。打印管理程序。)
cupsd調(diào)用特定于ARCH的驅(qū)動(dòng)(這里的ARCH是指不同的打印機(jī)架構(gòu)。)
發(fā)送字符流到USB。
cupsd控制打印隊(duì)列。
當(dāng)然。如果覺得我說的不夠形象。可以下載演示的視頻。
part1:
part2:
ARM板上運(yùn)行Linux。Linux下的打印機(jī)分為幾大類。PostScript打印機(jī)和其他的。。PS語言是PostScript打印機(jī)和計(jì)算機(jī)交流的方式。應(yīng)用層程序?qū)⑸傻腜ostScript文檔直接發(fā)送給打印機(jī)。
如果打印機(jī)是PostScript的。就能打了。有些打印機(jī)不能打。
按照一貫的計(jì)算機(jī)思想。可以在中間加一層。就是GhostScript、他將PostScript轉(zhuǎn)換成比較低級(jí)的打印機(jī)能識(shí)別的格式。
driver程序(驅(qū)動(dòng))將轉(zhuǎn)化好的打印文件。按照各種打印機(jī)的不同格式發(fā)送給打印機(jī)。是應(yīng)用層程序與底層打印機(jī)硬件交互的媒介。
不同打印機(jī)映射到的驅(qū)動(dòng)程序是不同的。
我們使用的是HP_LaserJet_1020。CUPS版本是1.4.8、不附帶特定的PPD文件。
PostScript Printer Description file是描述打印功能的文件,包含頁面。字體。的一些描述數(shù)據(jù)結(jié)構(gòu)。,簡(jiǎn)稱PPD文件。與driver相對(duì)應(yīng)。
必須找到特定打印機(jī)的PPD文件。并安裝到打印管程上。
一旦牽涉到多進(jìn)程。各種stuff都變得不那么簡(jiǎn)單。為了讓打印作業(yè)之間不沖突。就需要打印管程。
在UNIX-like系統(tǒng)上。用的最多的就是CUPS了。她接收要打印的文件。判斷是否需要將其轉(zhuǎn)換成Postscript。一般是通過文件類型來判斷的。
判斷GhostScript應(yīng)使用什么樣的driver處理此PostScript文件。一般通過PPD文件中相應(yīng)的字段。把Ghostscript處理的結(jié)果輸出到打印設(shè)備上。
CUPS和Ghostscript之間。還有一個(gè)層面。就是打印過濾程序foomatic-rip。是一個(gè)用Perl編寫的腳本程序。
CUPS通過它來調(diào)用Ghostscript程序。從而把PostScript作業(yè)轉(zhuǎn)化成PPD文件描述的打印機(jī)自身能識(shí)別的格式。
在網(wǎng)上找了很長(zhǎng)時(shí)間。才先一篇介紹CUPS原理的。
關(guān)于CUPS的詳細(xì)原理:http://www.linuxidc.com/Linux/2010-12/30698.htm
好了關(guān)于這個(gè)軟硬架構(gòu)介紹到此為止。下面開始搭建環(huán)境。
嵌入式宿主機(jī)OS是RHEL6.3。
交叉編譯器是arm-linux-gcc-4.3.2。
宿主機(jī)網(wǎng)絡(luò)設(shè)置。IP配置為192.168.0.107。
修改網(wǎng)卡配置文件。
[root@bogon ~]# vi /etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE="eth0"
BOOTPROTO=dhcp
NM_CONTROLLED="yes"
ONBOOT="no"
TYPE="Ethernet"
UUID="bb46e64b-53d1-4229-8a36-8b53297b3601"
DEFROUTE=yes
IPV4_FAILURE_FATAL=yes
IPV6INIT=no
NAME="System eth0"
HWADDR=00:23:5A:DD:1E:57
PEERDNS=yes
PEERROUTES=yes
LAST_CONNECT=1442248415
將ONBOOT字段改成"yes"。
關(guān)閉NetworkManger。
[root@bogon ~]# service NetworkManager stop
重啟網(wǎng)絡(luò)服務(wù)。
[root@bogon ~]# /etc/init.d/network restart
關(guān)閉防火墻。
[root@bogon ~]# /etc/init.d/iptables stop
關(guān)閉SELinux。
[root@bogon ~]# setenforce 0
在宿主機(jī)上啟動(dòng)tftp服務(wù)。
安裝tftp服務(wù)器:
[root@bogon Packages]# rpm -ivh tftp-server-0.49-7.el6.i686.rpm
[root@bogon Packages]# rpm -ivh tftp-0.49-7.el6.i686.rpm
修改配置文件:
# default: off
# description: The tftp server serves files using the trivial file transfer \
#? ? ? protocol.? The tftp protocol is often used to boot diskless \
#? ? ? workstations, download configuration files to network-aware printers, \
#? ? ? and to start the installation process for some operating systems.
service tftp
{
socket_type? ? ? ? ? ? = dgram
protocol? ? ? ? ? ? ? ? = udp
wait? ? ? ? ? ? ? ? ? ? = yes
user? ? ? ? ? ? ? ? ? ? = root
server? ? ? ? ? ? ? ? ? = /usr/sbin/in.tftpd
server_args? ? ? ? ? ? = -s /
disable? ? ? ? ? ? ? ? = yes
per_source? ? ? ? ? ? ? = 11
cps? ? ? ? ? ? ? ? ? ? = 100 2
flags? ? ? ? ? ? ? ? ? = IPv4
}
將server_args改成-s /tftpboot,將disable字段改成no。
創(chuàng)建/tftpboot:
[root@bogon Packages]#mkdir /tftpboot
[root@bogon Packages]#chmod -R 777 /tftpboot
重啟xinetd:
[root@bogon Packages]#/etc/init.d/xinetd restart
在宿主機(jī)上啟動(dòng)NFS服務(wù)。
[root@bogon ~]# vi /etc/exports
添加一項(xiàng)。
#/rootfs 192.168.0.*(rw,sync,no_root_squash)
重啟NFS服務(wù)。
/etc/init.d/nfs restart
安裝引導(dǎo)程序到NorFlash。
要下載程序到NandFlash。首先要安裝開發(fā)板的啟動(dòng)引導(dǎo)程序到NorFlash。
連接JLink。這個(gè)不用介紹了吧。
然后打開J-Flash軟件。如圖所示。

然后就是操作JLink軟件。下面是指令流。不展開說明了。
file->open project->2440.jflash
target->connect
file->open->u-boot
target->earse chip
target->program
現(xiàn)在啟動(dòng)引導(dǎo)程序已經(jīng)安裝好了。
在宿主機(jī)上安裝交叉工具鏈。
交叉工具鏈采用的是arm-linux-gcc-4.3.2。
在開源社區(qū)下載arm-linux-gcc-4.3.2.tgz。
將交叉工具鏈解壓到相應(yīng)目錄。
[root@bogon Cross_Compiler]# tar xvzf arm-linux-gcc-4.3.2.tgz -C /usr/local/Cross_Compiler/arm/4.3.2
修改~/.bashrc。
[root@bogon Cross_Compiler]# vi ~/.bashrc
# .bashrc
# User specific aliases and functions
alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'
# Source global definitions
if [ -f /etc/bashrc ]; then
. /etc/bashrc
fi
export PATH=$PATH:/opt/arm-linux-gdb/bin
export PATH=$PATH:/opt/4.3.2/bin
#export PATH=$PATH:/opt/4.4.3/bin
vi ~/.bashrc{
export PATH=$PATH:/opt/4.3.2
}
擴(kuò)展PATH字段。將交叉工具鏈中的bin目錄也作為命令的搜索路徑。
export PATH=$PATH:/usr/local/Cross_Compiler/arm/4.3.2/bin
使修改生效。
source ~/.bashrc
重新登錄一下就可以使用arm-linux-gcc等交叉編譯命令了。
嵌入式環(huán)境搭建:
設(shè)置網(wǎng)絡(luò)環(huán)境。
Windows的IP是192.168.0.101,宿主機(jī)的IP是192.168.0.107,開發(fā)板的IP是192.168.0.110
燒寫UBoot映像。
編譯UBoot。
使用開發(fā)板提供的UBoot。
配置UBoot。
[root@bogon uboot_tq2440]# make TQ2440_config
Configuring for TQ2440 board...
[root@bogon uboot_tq2440]#
編譯UBoot。
[root@bogon uboot_tq2440]# make ARCH=arm CROSS_COMPILE=arm-linux-
用USB線連接PC。
安裝dnw驅(qū)動(dòng)。
[root@bogon dnw1]# insmod dnw_usb.ko
[root@bogon dnw1]#
Message from syslogd@bogon at Jan 16 09:19:02 ...
kernel:GuoQian USB driver for DNW!
[root@bogon dnw1]#
使用dnw工具將編譯生成的u-boot.bin下載到開發(fā)板。
[root@bogon dnw1]# ./dnw ../u-boot.bin 0x30008000
這之后從NandFlash啟動(dòng)就可以看到UBoot的啟動(dòng)界面??梢赃x擇燒寫內(nèi)核映像了。
燒寫內(nèi)核映像。
使用開發(fā)板提供的內(nèi)核。
配置內(nèi)核。只選擇要用到的組件。
[root@bogon linux-tq2440]# make menuconfig ARCH=arm

選項(xiàng)很多。查找資料才能完成。這里不展開。
有一項(xiàng)需要說明的。我們要使用USB來驅(qū)動(dòng)打印機(jī)。所以當(dāng)然應(yīng)該把打印機(jī)支持選上。如圖所示。

需要
編譯內(nèi)核。
[root@bogon linux-tq2440]# make uImage ARCH=arm CROSS_COMPILE=arm-linux-
經(jīng)過幾十分鐘的編譯之后。得到內(nèi)核映像。提示如下。
。。。。
SYSMAP? System.map
SYSMAP? .tmp_System.map
OBJCOPY arch/arm/boot/Image
Kernel: arch/arm/boot/Image is ready
GZIP? ? arch/arm/boot/compressed/piggy.gz
AS? ? ? arch/arm/boot/compressed/piggy.o
LD? ? ? arch/arm/boot/compressed/vmlinux
OBJCOPY arch/arm/boot/zImage
Kernel: arch/arm/boot/zImage is ready
UIMAGE? arch/arm/boot/uImage
Image Name:? Linux-2.6.30.4-EmbedSky
Created:? ? ? Sat Jan 16 09:35:43 2016
Image Type:? ARM Linux Kernel Image (uncompressed)
Data Size:? ? 2433840 Bytes = 2376.80 kB = 2.32 MB
Load Address: 30008000
Entry Point:? 30008000
Image arch/arm/boot/uImage is ready
[root@bogon linux-tq2440]#
燒寫內(nèi)核。
下載內(nèi)核:
tftp 0x31000000 uImage
制作根文件系統(tǒng)。
創(chuàng)建根目錄rootfs
[root@bogon /]# mkdir rootfs
[root@bogon /]# cd rootfs
[root@bogon rootfs]# mkdir usr dev sys bin sbin etc mnt lib proc tmp var
[root@bogon rootfs]# mkdir usr/bin usr/sbin usr/lib lib/modules
創(chuàng)建必要的設(shè)備文件。
[root@bogon rootfs]# cd dev
[root@bogon dev]# mknod -m 666 console c 5 1
[root@bogon dev]# mknod -m 666 null c 1 3
創(chuàng)建配置文件。
寫入相應(yīng)字段需要查閱資料。這里不展開了。就是在etc目錄下創(chuàng)建一些文件。
[root@bogon etc]# ls
fstab? init.d? inittab? profile
[root@bogon etc]#
添加內(nèi)核模塊。
進(jìn)入內(nèi)核代碼。編譯模塊。
[root@bogon etc]# cd /home/win/Kernel/TQ2440/linux-tq2440
[root@bogon linux-tq2440]# make modules ARCH=arm CROSS_COMPILE=arm-linux-
安裝模塊。
make modules_install ARCH=arm INSTALL_MOD_PATH=/rootfs
編譯busybox。支持一些常用的命令。
在開源社區(qū)下載busybox-1.7.0。
進(jìn)入busybox 根目錄。
[root@bogon APP_Src]# ls
busybox-1.7.0? busybox-1.7.0.tar.bz2? diffutils-2.8.1? diffutils-2.8.1.tar.gz
配置busybox
[root@bogon busybox-1.7.0]# make menuconfig
scripts/kconfig/mconf Config.in
#
# using defaults found in .config
#

將Busybox配置成靜態(tài)編譯。
切記取消使用/usr的選項(xiàng)。不然會(huì)將宿主機(jī)的文件覆蓋。配置選項(xiàng)以下面這種形式寫出。以后或許也會(huì)用到這種方式。
make menuconfig {
busybox setting -> build option -> static
compile -> arm-linux-
install option -> donnot use /usr
prefix = /rootfs
}
安裝busybox。
make && make install
HP_LaserJet_1020驅(qū)動(dòng)的安裝。下面有移植筆記。
很榮幸在開源社區(qū)找到了一些開源的打印機(jī)驅(qū)動(dòng):
http://www.openprinting.org/download/
關(guān)于Samba需要不需要。當(dāng)時(shí)移植的時(shí)候還真沒想過。不過Samba很常用。順便把Samba交叉編譯了一下。其過程出乎意料的痛苦。各種錯(cuò)誤。
下面的交叉配置選項(xiàng)是經(jīng)過很長(zhǎng)時(shí)間才完成的。實(shí)在是懶得遍歷這個(gè)過程了。下面是一些移植時(shí)候的記錄。
====================================================================================================================================================
Samba的移植:
下載Samba-3.0.37
1.Samba的交叉編譯
[root@bogon source]# pwd
/root/Desktop/Samba/samba-3.0.37/source
[root@bogon source]# ./configure CC=arm-linux-gcc LD=arm-linux-ld RANLIB=arm-linux-ranlib AR=arm-linux-ar --host=arm-linux? --target=arm-linux --build=i686-linux --prefix=/root/Desktop/Tmp/Samba/samba-test SMB_BUILD_CC_NEGATIVE_ENUM_VALUES=yes
SAMBA VERSION: 3.0.37
LIBREPLACE_LOCATION_CHECKS: START
checking build system type... i686-pc-linux-gnu
checking host system type... arm-unknown-linux-gnu
checking target system type... arm-unknown-linux-gnu
LIBREPLACE_LOCATION_CHECKS: END
LIBREPLACE_CC_CHECKS: START
checking for arm-linux-gcc... arm-linux-gcc
checking for C compiler default output file name... a.out
checking whether the C compiler works... yes
checking whether we are cross compiling... yes
checking for suffix of executables...
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether arm-linux-gcc accepts -g... ^C
。。。。。
[root@bogon source]# make --prefix=/rootfs.....
=======================================================================================================
交叉編譯cups-1.4.8
[root@bogon cups-1.4.8]# ./configure --prefix=/rootfs/usr/local/cups CC=arm-linux-gcc CXX=arm-linux-g++ AR=arm-linux-ar LD=arm-linux-ld RANLIB=arm-linux-ranlib --host=arm-linux --target=arm-linux --build=i686-linux --disable-gnutls --disable-gssapi --disable-dbus
checking for gawk... gawk
checking for arm-linux-gcc... arm-linux-gcc
checking for C compiler default output file name... a.out
checking whether the C compiler works... yes
checking whether we are cross compiling... yes
checking for suffix of executables...
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether arm-linux-gcc accepts -g... yes
checking for arm-linux-gcc option to accept ISO C89... none needed
checking how to run the C preprocessor... arm-linux-gcc -E
checking whether we are using the GNU C++ compiler... yes
checking whether arm-linux-g++ accepts -g... yes
checking for arm-linux-ranlib... arm-linux-ranlib
checking for ar... /usr/bin/ar
checking for chmod... /bin/chmod
在開發(fā)板上啟動(dòng)cupsd需要
./usr/local/cups/sbin/cupsd
./usr/local/cups/lib/cups/filter
./usr/local/cups/etc/cups/cupsd.conf
LogLevel info -> LogLevel debug
You can see some debug information in ./usr/local/cups/var/log/cups/error_log
=====================================================================================
交叉編譯foo2zjs
wget -O foo2zjs.tar.gz http://foo2zjs.rkkda.com/foo2zjs.tar.gz
tar xvzf foo2zjs.tar.gz
cd foo2zjs
make
make install
make install-hotplug
make cups
./getweb 1020
./arm2hpdl sihp1020.img > sihp1020.dl
cp sihp1020.dl /usr/share/foo2zjs/firmware/
cp /usr/share/foo2zjs/firmware/sihp1020.dl > /dev/usb/lp0
./foo2zjs -p9 -r600x600 test.pbm > /dev/lp0
=================================================================================
lpadmin -p HP_LaserJet_1020 -E -v usb:/dev/lp0 -P ./usr/local/cups/share/cups/model/HP_LaserJet_1020.ppd
lpstat -t
lpoptions -d HP_LaserJet_1020
lpr -P HP_LaserJet_1020 /etc/passwd
cat /etc/passwd | lp -d HP_LaserJet_1020
================================================================================
Compile the foomatic-rip:
./configure CC=arm-linux-gcc CXX=arm-linux-g++ LD=arm-linux-ld RANLIB=arm-linux-ranlib AR=arm-linux-ar --host=arm-linux --target=arm-linux --build=i686-linux --prefix=/root/Desktop/Test/foomatic-rip-4.3.2-test
modify the "config.h"
在服務(wù)器上添加打印機(jī)。

選擇Devices and Printers下的add printer

選擇鼠標(biāo)所指的那一項(xiàng)。添加網(wǎng)絡(luò)打印機(jī)。再選擇我要的打印機(jī)不在列表內(nèi)。
然后出現(xiàn)通過網(wǎng)絡(luò)添加打印機(jī)的菜單。CUPS的端口號(hào)是631,所以然后寫入目標(biāo)打印機(jī)的地址。就是,
http://192.168.0.110:631/printers/HP_LaserJet_1020
如下所示。

從服務(wù)器上可以看到打印機(jī)的網(wǎng)絡(luò)地址是多少。也是CUPS提供的一個(gè)界面。

在服務(wù)器上也能訪問ARM板上的CUPS進(jìn)程。然后服務(wù)器將打印任務(wù)發(fā)送到cups進(jìn)程。cups管理打印任務(wù)。調(diào)用ARM板上移植好的驅(qū)動(dòng)。通過USB驅(qū)動(dòng)打印機(jī)。
HP_LaserJet_1020驅(qū)動(dòng)的安裝。
原來打算自己寫一波Printer設(shè)備驅(qū)動(dòng),但是找了一個(gè)1020的代碼,代碼量超級(jí)大,其中核心部分移植起來耦合度也很大,所以就簡(jiǎn)單做了。
在開源社區(qū)找到了一些開源的打印機(jī)驅(qū)動(dòng):
http://www.openprinting.org/download/
行文至此,驅(qū)動(dòng)項(xiàng)目算結(jié)束咯。感謝建斌同學(xué)和培松同學(xué)的配合~。~
***
Linkerist
2017年12月1日于北京酒仙橋