2019年3月26日

Linux Graphics Study

前言:
這篇是我以前針對Linux X-Window和Qt寫的Study文件。

Linux GUI架構:
下圖是Linux Qt視窗系統的最簡架構圖:


對Qt來說,根據不同的下層和硬體,區分為:
  • Qt/Embedded
  • Qt/X11
  • Qt/Windows(針對Microsoft Windows環境)
  • Qt/Mac(針對MacOS環境)


Qt/Embedded:
Qt/Embedded主要是用於嵌入式系統的環境,Qt/Embedded本身包含了類似X-window的視窗處理,
它的下層直接界接驅動程式,驅動程式部份可以有3種,分別是:
  • Qt直接操作FrameBuffer(VGA模式)
  • Qt透過DirectFB操作FrameBuffer
  • Qt直接操作DirectFB


Qt直接操作FrameBuffer是Qt最早的作法,但缺點是,FrameBuffer是以VGA模式直接處理,
因此FrameBuffer沒有提供和使用任何的顯示晶片加速器。
因為這原因,德國一家公司提供DirectFB,號稱能夠透過一個中間層,
來統一Embedded的圖形開發,並使用顯示晶片的硬體加速能力,
但後來細看後得知,DirectFB的硬體加速能力,
事實上是需要顯示晶片的廠商撰寫DirectFB的顯示晶片驅動程式,
這樣一來,上層應用程式(包括Qt)直接呼叫DirectFB即可使用顯示晶片的硬體加速能力。
如果沒有DirectFB的顯示晶片驅動程式,那麼DirectFB還是只能用FrameBuffer,
像是Intel就沒有提供DirectFB的驅動程式。


Qt/X11:
Qt/X11是針對X-window的環境,Qt/X11中,Qt使用X-window來進行視窗操作,
X-window則透過X-window的顯示晶片驅動程式來操作顯示晶片硬體。


Linux X-window驅動程式簡單架構圖:


X-window本身架構龐大且複雜,但從驅動程式的角度來看,可以將架構簡化。
在目前的X-window中,針對2D和3D的加速,
Intel提供了X-window 2D的顯示驅動程式和X-window 3D的顯示驅動程式。
其中2D的驅動程式為(xf86-video-intel Driver),
3D的驅動程式的部份,Intel則提供了X-window專用的mesa介面的Driver,
Intel沒有另外提供它名稱,就叫做mesa driver。

X-window和Driver對應架構圖:


X-window的2D:
顯示晶片針對2D的驅動程式,其實是在VGA模式之上加入了許多圖像處理的加速器,
像是圖像重繪(redraw)、圖像縮放(resize)、旋轉(rotation)…等。
X-window本身提供了XLib來和X-window溝通,
而X-window提供了許多所謂的Extension來針對不同的需要進行處理,
在這裡我只看了XRender、XVideo(XV)、DGA這三種Extension。
選擇這三種Extension的原因和它們和Qt的關係,再之後說明。


X-window的3D:
X-window針對3D的處理,提供了一個稱為DRI(Direct Rendering Infrastructure)的介面,
上面提供給3D Library(OpenGL)操作顯示晶片的3D驅動程式,
下面則透過mesa這個驅動程式介面提供給顯示晶片廠商開發3D加速的驅動程式。

Qt/X11和X-win Extension/3D OpenGL關係架構圖:


在Qt中,目前我已經看到針對顯示相關的Class有3個,分別是:
  • QPainter
  • QX11EmbedWidget
  • QGL Module


QPainter:
QPainter是Qt中最基本的繪圖Class,Qt中所有的視窗繪製行為都是透過QPainter。
而在X-window中,QPainter事實上是透過了XLib操作XRender Extension來讓顯示晶片顯示,
XRender Extension實際上就是X-Window基本的Render(繪製器),
它和Microsoft Windows的GDI地位雷同。


QX11EmbedWidget:
QX11EmbedWidget事實上可以說是Qt針對X-window直接操作提供的洞,
QX11EmbedWidget讓GUI應用程式能夠透過QX11EmbedWidget直接和XLib溝通和操作,
我們可以透過QX11EmbedWidget來操作X-window其他的Extension。


  • XVideo(XV) Extension:
XVideo(XV) Extension是X-window針對影片播放提供的Extension,
目前在Linux上主流的播放器,包括vlc、mplayer、gstream,
預設的Video Output都是使用XVideo(XV) Extension。
從XV的說明來看,它使用了顯示晶片上圖片縮放、旋轉、重繪的加速器,
讓播放器在播放時,可以直接利用顯示晶片進行影片的縮放和重繪。


  • DGA Extension:
DGA全名是Direct Graphics Architecture,
它主要的能力是能夠讓程式透過DGA跨過整個X-window直接操作顯示驅動程式上的FrameBuffer。
我認為在X-window架構上,如果要像嵌入式系統一樣直接處理FrameBuffer,
DGA Extension應該是個不錯的選擇。


選擇瞭解XRender、XVideo(XV)、DGA這三種Extension的原因是:
  • XRender是Qt QPainter使用的Extension,整個視窗介面都透過它來進行繪製
  • XV是目前幾個主流播放器預設使用的Video Output
  • DGA具有能最直接操作顯示晶片上FrameBuffer的能力


QGL Module:
QGL Module是Qt針對OpenGL提供的一整組Class,透過QGL Module,Qt可以使用OpenGL Library。
OpenGL Library在X-window中,它會透過DRI介面和mesa Driver直接溝通,
雖然DRI是X-window架構中的一部分,但目前我的理解,它事實上是獨立的一塊,
並沒有和XLib界接。

X-win基本架構:
X-win的基本架構如下圖:


所有的應用程式都是X Client,而所有的操作和螢幕顯示則是透過X Server,
因為X-win的設計是以TCP/IP為基礎的設計,X Client和X Server的溝通都是透過TCP/IP,
就算是在本機,也同樣需要透過TCP/IP溝通。
前面提到的Extension,都是在X Server上用來顯示使用的,
而XLib,實際上是將整個X-win的X Server、X Client溝通(X Protocol)封裝隱藏起來。

X-win繪圖與影片播放:
X-win的基本繪圖顯示,就如前面提到的,是使用XRender進行繪圖,使用格式為BGRA。
流程如下:


首先,在應用程式(X Client)中使用XImage結構建立圖片,接著將圖片送到X Server端並顯示。
Qt的繪圖模式相同,在Qt中,QImage Class其實就是在X Client上建立圖片,
QPixmap Class則是在X Server端的顯示晶片記憶體中放置圖片。
X-win的這種繪圖方式,會有load(負載)在X Client和X Server的溝通以及TCP/IP的資料交換。


XVideo(XV) Extension前面提到過,它能加快X-win的影片播放,
Wiki的說明裡面寫得很詳細,XVideo(XV) Extension實際上是使用顯示晶片的加速能力,
來達成以下幾件事情:
  1. 影片播放時,由顯示晶片處理圖片的縮放或全螢幕顯示
  2. 由顯示晶片處理Color Space的轉換(主要是YUV的處理)
  3. 由顯示晶片來處理影片播放時,圖片的飽和度、亮度、彩度…等設定的處理


XVideo(XV) Extension的支援性,是相依在顯示晶片上的,
顯示晶片是否支援XVideo(XV) Extension?
顯示晶片的XVideo(XV) Extension支援哪些Color Space操作?
都由顯示晶片決定。
以例子中的Intel GMA 3100來說,這顆顯示晶片支援XVideo(XV) Extension,
支援的Color Space轉換包括:
  1. YUY2
  2. YV12
  3. I420
  4. UYVY
  5. XvMC


其中XvMC(Wiki)是類似Windows上Microsoft的DirectX Video Acceleration (DxVA) API,
主要是能透過它使用顯示卡上的GPU運算,這部份我沒有再進一步下去看。
其他幾個Color Space轉換都是支援YUV。
因此如果圖片原始格式是YUV的,建議直接使用XVideo(XV) Extension,
如果圖片原始格式是RGB的,建議使用XRender。

X-win的XSHM Extension:
前面提到過X-win的繪圖流程,
會需要用TCP/IP在X Client和X Server之間溝通(X Protocol)和傳遞資料,
其中用TCP/IP進行圖片資料(XImage)的傳遞會消耗很多系統資源,
因此提出XSHM Extension來解決這問題。
XSHM Extension流程如下:


和原始的流程相比,X Protocol通訊的部份不變,
但圖片部份的操作改用Share Memory進行圖片交換,
因此省去了XImage在X Client與X Server間傳遞的消耗,減輕負載。
目前XSHM Extension提供了XRender和XVideo(XV) Extension的操作的加速,
其他方式它都不支援。


幾種方式的測試:
環境:Intel Q35晶片組主機板
圖片:480x640圖片(XV使用UYVY、XRender使用RGBA、QT使用BMP)
圖片:1920x1080圖片(XRender使用RGBA)
速度:每秒30張循環



Qt
(直接讀圖到QPixmap Class)
XRender
XRender
(XSHM)
XVideo(XV)
XVideo(XV)
(XSHM)
CPU
13%~18%
2%~6%
1%~4%
2%~5%
2%~4%
1920x1080圖片
11%~22%


Blog要更新囉~~~

有近4年沒更新Blog了,
最近會陸續將先前的一些技術心得分享出來。

2015年11月25日

Acer Chromebook 13 Chrubuntu UPower修正

前言:
因為Ubuntu 14.04沒有MATE for armhf,
加上網路上建議用Ubuntu 15.04加上BlueZ 5來解決Bluetooth Smart的問題,
因此目前正著手將chrubuntu 15.04放上Acer Chromebook 13。

目前狀態還不錯,整體支援性感覺比Ubuntu 14.04還要好得多,
需要修正的比較少,
但這次有個大問題,電池電量無法顯示,
這問題在Ubuntu 14.04有出現,但xfce4上面能夠顯示就將就不管它,
Ubuntu 15.04沒這麼幸運,因此就下去Debug了。

問題原因:
問題的關鍵很容易透過systemctl看得出來,就是UPower Daemon無法啟動,
UPower Daemon執行檔在
/usr/lib/upower/upowerd

可以透過
/usr/lib/upower/upowerd -v

取得執行過程的訊息。

出問題的訊息如下:
問題解法:
經過Trace和gdb追蹤,還有拿桌上型電腦正常運作的upowerd比對後,
得到的root cause如下:
1. native-path錯誤
2. object path錯誤

native-path錯誤:
其實從訊息可以注意到,upowerd不認識bq24735@5-0009這顆電源管理IC,
Google後發現,它在新版Kernel中有針對名稱有Patch,
但我們的使用情境中,Kernel不能變動,且驅動程式已經處理過了,
因此我們要改的就是upowerd這端。

針對native-path的修改如下:
up-native.c



修改up-native.c,檢查名稱,如果開頭沒有「/」,
就加上Acer Chromebook 13的prefix名稱。

這邊的修改用了malloc,但因為這行程式碼grep看起來,用的位置不多,
所以應該是不會有memory leak的問題。

object path錯誤:
針對object path的修改如下:
另一個問題則是object path,這個問題是真正會引發Segfault的問題所在,
參考:
http://upower.freedesktop.org/docs/UPower.html


在upowerd中,DBus的名稱必須是固定如上圖所示,
但在前面的問題截圖中可以注意到,它名稱變成:
/org/freedesktop/UPower/devices/line_power_bq24735@5-0009

這造成upowerd後面程式碼parse時出現問題而Segfault。

針對up-device.c修改如下:
up-device.c



這邊只是簡單的查詢bq24735電源管理IC和sbs電池管理IC,
然後根據這2顆IC的情況修改成相對應的字串。

結果:
修改後執行結果。

upowerd執行如下:


看起來upowerd運作正常。

MATE的電源統計程式:



從電源統計程式看起來,能夠正確取得AC和電池狀態。

UPower檔案下載:
Ubuntu ARM 15.04 UPower deb下載
Ubuntu ARM 15.10 UPower deb下載

Ubuntu ARM 15.04 UPower完整deb打包
Ubuntu ARM 15.10 UPower完整deb打包

Ubuntu ARM 15.04 UPower完整程式碼含修改打包
Ubuntu ARM 15.10 UPower完整程式碼含修改打包

Chrubuntu 15.04修整好後,也會和先前一樣放tar檔提供下載。

2015年8月16日

COSCUP 2015 Jserv 封麥的感慨

我竟然有資訊業老人的感慨出現,太可怕了!
我從來不是 Linux 的名人,但我的確很早就在玩 Linux,
因此我覺得我可以從旁觀者角度看這些。

我的啟蒙是 李建達 的黑皮書(FreeBSD入門與應用),
黑皮書的那些年,名人當屬 李建達、woju,
顯學是 FreeBSD,ipfw、陽光沙灘BBS、news、bind、sendmail...等,
還記得當時的中文系統 big5con 嗎?還記得加密終端機 SNP?

就在某個 moment,RedHat CLE 出現了,Debian 無痛起步出現了,
鳥哥 出現了,Jserv 出現了!
顯學變成了 Linux,busybox、u-boot、RedBoot、Embedded Linux,
還記得當時的入門開發板,S3C4510B、S3C2410X,
努力一星期,只是為了把BootLoader放上去,
或是patch Kernel讓它能開機、網路能運作。

現在,Big Data 興起、物聯網興起、機器人興起,
顯學變成了Python、GoLang、Hadoop...等,而 Jserv,封麥了,
我感覺到資訊業一個世代隨著 Jserv 封麥,正式結束了。

在感慨一個世代結束的同時,也對新的世代充滿期待,
資訊業不缺名人,也永遠有新的顯學,
在這個新世代興起的 moment,除了以高速學習新顯學外,
就是繼續以旁觀者的角度,期待新的名人出現,
帶領大家往偉大的新航路前進。

附上我自己的黑皮書封面照片,
(舊版黑皮書暫時找不到,這本是新版)。

2015年1月25日

HPLIP bb-soap解析 - 4 - bb_end_page 和 bb_end_scan

前言:
接續前篇,這篇會將bb_end_page和bb_end_scan一起po完,主要會是解析bb_end_scan,
因為從前面的flow可以發現,bb_end_page實際動作應該只有做hpmud_channel_close(),
其他幾乎沒看到在幹嘛,所以這篇主要就變成了bb_end_scan的解析。

在一開始時,嘗試要把Close Code Library自己實做,覺得似乎非常困難,
要知道這可是現成的事務機,要破解它的Protocol應該很難吧......

實際下去理解並dump它的通訊內容後,其實並不難,
整個flow看完理解後,我就在想,真的還需要補充實做bb_soap嗎?
自己參考SANE backends範例寫個CM1015專用的SANE backends算了,
反正底層一樣呼叫hpmud,其他就自己解決了。

而且看到現在,感覺已經偏了,怎麼好像在研究SOAP的感覺(加油,魔王只剩SOAP DIME了),
我並沒有想要理解SOAP啊.........

bb_end_page:
目前瞭解,看起來就只有呼叫hpmud_channel_close()。

所以這裡描述就是:
  • bb_end_page
    • hpmud_channel_close()
結束。

bb_end_scan:
動作流程如下:
  • bb_end_scan
    • hpmud_channel_open()
    • hpmud_channel_write()
    • hpmud_channel_write()
    • hpmud_channel_write()
    • hpmud_channel_write()
    • hpmud_channel_read()
    • hpmud_channel_read()
    • hpmud_channel_read()
    • hpmud_channel_read()
    • hpmud_channel_close()
bb_end_scan解析:
同前面,一樣把它溝通內容列出,共4個write、4個read。

write:
cat hpmud_write_channel_7.dump
POST / HTTP/1.1
Host: http:0
User-Agent: gSOAP/2.7
Content-Type: application/soap+xml; charset=utf-8
Transfer-Encoding: chunked
Connection: close



cat hpmud_write_channel_8.dump
1b9
前面已經知道,多出的部份就只是buffer沒清除,因此只列出神秘HEX數值。

cat hpmud_write_channel_9.dump
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" xmlns:SOAP-ENC="http://www.w3.org/2003/05/soap-encoding" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wscn="http://tempuri.org/wscn.xsd"><SOAP-ENV:Body><wscn:CancelJob><ScanIdentifier>scanjob 10153</ScanIdentifier></wscn:CancelJob></SOAP-ENV:Body></SOAP-ENV:Envelope>


cat hpmud_write_channel_10.dump
0

前面已經知道,多出的部份就只是buffer沒清除,因此只列出神秘HEX數值。

read:
cat hpmud_read_channel_16.dump
HTTP/1.1 200 OK
Server: gSOAP/2.7
Content-Type: application/soap+xml; charset=utf-8
Transfer-Encoding: chunked
Connection: close



cat hpmud_read_channel_17.dump
1B7
前面已經知道,多出的部份就只是buffer沒清除,因此只列出神秘HEX數值。

cat hpmud_read_channel_18.dump
<?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" xmlns:SOAP-ENC="http://www.w3.org/2003/05/soap-encoding" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wscn="http://tempuri.org/wscn.xsd"><SOAP-ENV:Body><wscn:CancelJobResponse><succeeded>false</succeeded></wscn:CancelJobResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>


cat hpmud_read_channel_19.dump
0

前面已經知道,多出的部份就只是buffer沒清除,因此只列出神秘HEX數值。

write解析:
雖然從XML看得出來,明顯很單純,但我們一樣用瀏覽器來看看,如下:

這裡訊息很簡單,就只有CancelJob和ScanIdentifier。
裡面帶的參數,就是前面bb_start_scan裡面帶的scanjob。

所以這裡合理的懷疑,
前面bb_start_scan,除了送出Scan參數外,
會對事務機發出一個掃描工作的request。

當掃描工作結束時,也就是這裡bb_end_scan,
會對事務機發出取消掃描工作的request,
通知事務機,掃描工作已結束或已完成,
事務機應該會在內部把這項掃描工作相關的資料結構刪除。

read解析:
同樣用瀏覽器看看,如下:

這裡可以看到,回傳的參數也很簡單,就只有successed。

這裡的false我不確定是固定回傳false,
還是因為我是測試,所以沒有成功取消。

HPLIP bb-soap解析 - 3 - bb_start_scan - 上集

前言:
接續前篇,通過整個flow的拆解和bb_open內容的解析,
我們大致可以知道CM1015的溝通過程。

針對bb_start_scan,我考慮分成上、下2集,
上集可以先po,下集我不確定能不能po得成,因為目前還沒有參透。

因此,po的順序會是:
  • bb_start_scan上集 
  • bb_end_page 
  • bb_end_scan
最後再回頭看能不能po得出bb_start_scan。

bb_start_scan和hpmud動作流程:
  • bb_open
    • hpmud_channel_open()
    • hpmud_channel_write()
    • hpmud_channel_write()
    • hpmud_channel_read()
    • hpmud_channel_read()
    • hpmud_channel_read()
    • hpmud_channel_read()
    • hpmud_channel_close()
  • bb_start_scan
    • hpmud_channel_open()
    • hpmud_channel_write()
    • hpmud_channel_write()
    • hpmud_channel_write()
    • hpmud_channel_write()
    • hpmud_channel_read()
    • hpmud_channel_read()
    • hpmud_channel_read()
    • hpmud_channel_read()
    • hpmud_channel_read()
    • hpmud_channel_read()
    • hpmud_channel_read()
    • hpmud_channel_read()
    • hpmud_channel_read()
    • hpmud_channel_read()
    • hpmud_channel_read()
  • bb_get_parameters
  • bb_get_parameters
  • bb_end_page
    • hpmud_channel_close()
  • bb_end_scan
    • hpmud_channel_open()
    • hpmud_channel_write()
    • hpmud_channel_write()
    • hpmud_channel_write()
    • hpmud_channel_write()
    • hpmud_channel_read()
    • hpmud_channel_read()
    • hpmud_channel_read()
    • hpmud_channel_read()
    • hpmud_channel_close()
      • bb_close
      • bb_unload
      這裡我們注意到紅字標示的部份,也就是hpmud_channel_open/hpmud_channel_close的部份。

      我們會發現,bb_start_scan和其他幾個bb function的特異之處,
      bb_start_scan只有做hpmud_channel的open,但並沒有close,
      它實際的close動作是到bb_end_page才做。

      bb_start_scan溝通內容:
      照例,我們打印出bb_start_scan的溝通內容,bb_start_scan有4個write,和一堆read,
      上集我們只印出前面3個,
      後面的我還看不懂,而且內容大部分應該是掃描出的圖片內容,
      我就不列了。

      內容:
      write:
      cat hpmud_write_channel_3.dump
      POST / HTTP/1.1
      Host: http:0
      User-Agent: gSOAP/2.7
      Content-Type: application/soap+xml; charset=utf-8
      Transfer-Encoding: chunked
      Connection: close
      
      

      cat hpmud_write_channel_4.dump
      54f

      cat hpmud_write_channel_5.dump
      <?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wscn="http://tempuri.org/wscn.xsd"><SOAP-ENV:Body><wscn:InitiateScanRequest><ScanTicket><JobDescription><JobName>scanjob 10153</JobName><JobOriginatingUsername>Eric Cartman</JobOriginatingUsername></JobDescription><DocumentParameters><Format>scanJFIF</Format><InputSource>scanPlaten</InputSource><ContentType>scanAuto</ContentType><DocumentCompression><CompressionType>scanJPEG</CompressionType><JPEGQualityFactor>10</JPEGQualityFactor></DocumentCompression><Contrast>0</Contrast><Brightness>0</Brightness><ScanRegion><ScanRegionXOffset>0</ScanRegionXOffset><ScanRegionYOffset>0</ScanRegionYOffset><ScanRegionWidth>8499</ScanRegionWidth><ScanRegionHeight>11689</ScanRegionHeight></ScanRegion><ColorProcessing>scanGrayScale8</ColorProcessing><Resolution><ResolutionWidth>75</ResolutionWidth><ResolutionHeight>75</ResolutionHeight></Resolution><PadImage>true</PadImage><GammaCorrection>2.2</GammaCorrection></DocumentParameters></ScanTicket><DestinationID>PC</DestinationID><ScanIdentifier>linux-rocks</ScanIdentifier></wscn:InitiateScanRequest></SOAP-ENV:Body></SOAP-ENV:Envelope>

      cat hpmud_write_channel_6.dump
      0
      
      

      read:
      cat hpmud_read_channel_5.dump
      HTTP/1.1 200 OK
      Server: gSOAP/2.7
      Content-Type: application/dime
      Transfer-Encoding: chunked
      Connection: close
      
      

      cat hpmud_read_channel_6.dump
      800
      1.1 200 OK
      Server: gSOAP/2.7
      Content-Type: application/dime
      Transfer-Encoding: chunked
      Connection: close
      
      

      cat hpmud_read_channel_7.dump
       )▒cid:id0http://schemas.xmlsoap.org/soap/envelope/
      
      linux-rocksid1image/jpeg▒▒▒▒JFIF▒▒C
       $.' ",#(7),01444'9=82<.342▒▒
                                  l}▒▒
      
      ...............
      
      HEX表示:

      write解析:
      送給事務機的XML內容訊息很多,原則上就是提供事務機掃描的參數,
      但這邊有幾個訊息是重點,而且有藏彩蛋,哈.....作者還真是幽默啊......

      一堆不好看,我們把這串另存成XML,用瀏覽器打開看看,如下:

      這裡注意到,裡面除了掃描資訊外,有幾個重點:
      • JobName
      • JobOriginatingUsername
      • DestinationID
      • ScanIdentifier
      這幾條看起來並不像是掃描參數,其中JobName是關鍵,會在後面其他function使用到。

      作者的幽默感來自於JobOriginatingUsername的名稱Eric Cartman,這是誰?
      是作者本人嗎?還是描述什麼?Google看看......
      Google找到他......

      read解析:
      read的內容我還沒搞懂,把目前知道的部份po出來。

      我們從SOAP的HTTP Header理解,從Content-Type: application/dime來看,
      我們可以知道這是一個application/dime類型的資料,
      Google後得知,SOAP有2種夾帶附件的資料格式:
      • MIME
      • DIME
      這裡使用了SOAP DIME做為傳遞的資料格式。

      目前我對SOAP DIME還不清楚,還在解譯中,僅把我找到的參考資料列出,
      其他等解譯後,下集再寫。

      SOAP DIME參考:

      JPEG格式參考:
      http://en.wikipedia.org/wiki/JPEG_File_Interchange_Format
      http://bbs.csdn.net/topics/190036200
      上述2個JPEG參考可以知道,JPEG Header的最開頭是
      FF D8 FF E0
      • FF D8
        • 表示圖片開頭
      • FF E0
        • 表示JPEG APP0的開頭

      HPLIP bb-soap解析 - 2 - bb_open

      前言:
      接續前篇,在前篇大致知道了整個CM1015掃描的flow,
      搭配AAA的印出的訊息, 我們可以知道bb_soap幾個function和hpmud的呼叫關聯。

      進一步搭配從hpmud_read和hpmud_write寫出的dump內容,
      我們可以知道它們溝通的訊息內容。

       這篇,前半段會簡單解析bb_soap和hpmud的動作,
      然後這篇重點會針對bb_open進行描述,
      原則上,bb_open動作知道了,我目前認為和CM1015的溝通,就大致清楚了。

      bb_soap和hpmud動作:
      由前一篇的幾個dump,加上bb_soap整個flow,拆解對照後,可以得到下面的動作流程:
      • bb_open
        • hpmud_channel_open()
        • hpmud_channel_write()
        • hpmud_channel_write()
        • hpmud_channel_read()
        • hpmud_channel_read()
        • hpmud_channel_read()
        • hpmud_channel_read()
        • hpmud_channel_close()
      • bb_start_scan
        • hpmud_channel_open()
        • hpmud_channel_write()
        • hpmud_channel_write()
        • hpmud_channel_write()
        • hpmud_channel_write()
          • 這裡看AAA訊息,中間有摻雜許多function動作,甚至bb_get_parmameters呼叫時,都還有read動作,目前相當懷疑下面的read是在額外的thread處理的
        • hpmud_channel_read()
        • hpmud_channel_read()
        • hpmud_channel_read()
        • hpmud_channel_read()
        • hpmud_channel_read()
        • hpmud_channel_read()
        • hpmud_channel_read()
        • hpmud_channel_read()
        • hpmud_channel_read()
        • hpmud_channel_read()
        • hpmud_channel_read()
      • bb_get_parameters
      • bb_get_parameters
      • bb_end_page
        • hpmud_channel_close()
      • bb_end_scan
        • hpmud_channel_open()
        • hpmud_channel_write()
        • hpmud_channel_write()
        • hpmud_channel_write()
        • hpmud_channel_write()
        • hpmud_channel_read()
        • hpmud_channel_read()
        • hpmud_channel_read()
        • hpmud_channel_read()
        • hpmud_channel_close()
          • bb_close
          • bb_unload
          由這段列出的流程中可以看出來,
          bb_open是第1個關卡,裡面包含了完整的open/write/read/close動作,
          下段開始,我們就進入本篇主題,將bb_open內容列出並解析。

          bb_open解析:
          前面我們得知,bb_open內包含了2個write,4個read,這邊我們按順序列出內容:
          write:
          cat hpmud_write_channel_1.dump
          POST / HTTP/1.1
          Host: http:0
          User-Agent: gSOAP/2.7
          Content-Type: application/soap+xml; charset=utf-8
          Transfer-Encoding: chunked
          Connection: close
          
          
          cat hpmud_write_channel_2.dump
          19E
          <?xml version="1.0" encoding="UTF-8"?>
          <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" xmlns:SOAP-ENC="http://www.w3.org/2003/05/soap-encoding" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wscn="http://tempuri.org/wscn.xsd"><SOAP-ENV:Body><wscn:GetScannerElements></wscn:GetScannerElements></SOAP-ENV:Body></SOAP-ENV:Envelope>
          0
          
          

          read:
          cat hpmud_read_channel_1.dump
          HTTP/1.1 200 OK
          Server: gSOAP/2.7
          Content-Type: application/soap+xml; charset=utf-8
          Transfer-Encoding: chunked
          Connection: close
          
          

          cat hpmud_read_channel_2.dump
          7CB
          1.1 200 OK
          Server: gSOAP/2.7
          Content-Type: application/soap+xml; charset=utf-8
          Transfer-Encoding: chunked
          Connection: close
          
          

          cat hpmud_read_channel_3.dump
          <?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" xmlns:SOAP-ENC="http://www.w3.org/2003/05/soap-encoding" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wscn="http://tempuri.org/wscn.xsd"><SOAP-ENV:Body><wscn:ScanElements><ScannerConfiguration><DeviceSettings><FormatSupported xsi:type="SOAP-ENC:Array" SOAP-ENC:itemType="xsd:eDocumentFormat" SOAP-ENC:arraySize="3"><item>scanDIB</item><item>scanJFIF</item><item>scanMMRf</item></FormatSupported><CompressionSupported xsi:type="SOAP-ENC:Array" SOAP-ENC:itemType="xsd:eCompressionType" SOAP-ENC:arraySize="3"><item>scanNoCompression</item><item>scanJPEG</item><item>scanMMR</item></CompressionSupported><JPEGQualityFactorSupported>false</JPEGQualityFactorSupported><ContentSupported xsi:type="SOAP-ENC:Array" SOAP-ENC:itemType="xsd:eDocumentType" SOAP-ENC:arraySize="4"><item>scanAuto</item><item>scanText</item><item>scanMixed</item><item>scanPhoto</item></ContentSupported><DocumentSizeAutoDetectSupported>true</DocumentSizeAutoDetectSupported></DeviceSettings><Platen><ColorSupported xsi:type="SOAP-ENC:Array" SOAP-ENC:itemType="xsd:eColorEntryType" SOAP-ENC:arraySize="4"><item>scanBlackandWhite1</item><item>scanGrayScale8</item><item>scanRGB24</item><item>scanRGB48</item></ColorSupported><PlatenMinimumSize><DimensionsWidth>500</DimensionsWidth><DimensionsHeight>300</DimensionsHeight></PlatenMinimumSize><PlatenMaximumSize><DimensionsWidth>8500</DimensionsWidth><DimensionsHeight>11690</DimensionsHeight></PlatenMaximumSize><PlatenOpticalResolution><ResolutionWidth>1200</ResolutionWidth><ResolutionHeight>1200</ResolutionHeight></PlatenOpticalResolution></Platen></ScannerConfiguration><ScannerStatus><ScannerCurrentTime>0001-01-01T01:01:01Z</ScannerCurrentTime><ScannerState>scanIdle</ScannerState><ActiveCondition>scanNone</ActiveCondition></ScannerStatus></wscn:ScanElements></SOAP-ENV:Body></SOAP-ENV:Envelope>

          cat hpmud_read_channel_4.dump
          0
          
          ersion="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" xmlns:SOAP-ENC="http://www.w3.org/2003/05/soap-encoding" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wscn="http://tempuri.org/wscn.xsd"><SOAP-ENV:Body><wscn:ScanElements><ScannerConfiguration><DeviceSettings><FormatSupported xsi:type="SOAP-ENC:Array" SOAP-ENC:itemType="xsd:eDocumentFormat" SOAP-ENC:arraySize="3"><item>scanDIB</item><item>scanJFIF</item><item>scanMMRf</item></FormatSupported><CompressionSupported xsi:type="SOAP-ENC:Array" SOAP-ENC:itemType="xsd:eCompressionType" SOAP-ENC:arraySize="3"><item>scanNoCompression</item><item>scanJPEG</item><item>scanMMR</item></CompressionSupported><JPEGQualityFactorSupported>false</JPEGQualityFactorSupported><ContentSupported xsi:type="SOAP-ENC:Array" SOAP-ENC:itemType="xsd:eDocumentType" SOAP-ENC:arraySize="4"><item>scanAuto</item><item>scanText</item><item>scanMixed</item><item>scanPhoto</item></ContentSupported><DocumentSizeAutoDetectSupported>true</DocumentSizeAutoDetectSupported></DeviceSettings><Platen><ColorSupported xsi:type="SOAP-ENC:Array" SOAP-ENC:itemType="xsd:eColorEntryType" SOAP-ENC:arraySize="4"><item>scanBlackandWhite1</item><item>scanGrayScale8</item><item>scanRGB24</item><item>scanRGB48</item></ColorSupported><PlatenMinimumSize><DimensionsWidth>500</DimensionsWidth><DimensionsHeight>300</DimensionsHeight></PlatenMinimumSize><PlatenMaximumSize><DimensionsWidth>8500</DimensionsWidth><DimensionsHeight>11690</DimensionsHeight></PlatenMaximumSize><PlatenOpticalResolution><ResolutionWidth>1200</ResolutionWidth><ResolutionHeight>1200</ResolutionHeight></PlatenOpticalResolution></Platen></ScannerConfiguration><ScannerStatus><ScannerCurrentTime>0001-01-01T01:01:01Z</ScannerCurrentTime><ScannerState>scanIdle</ScannerState><ActiveCondition>scanNone</ActiveCondition></ScannerStatus></wscn:ScanElements></SOAP-ENV:Body></SOAP-ENV:Envelope>

          由上述可以知道下列資訊:

          • 傳送時
            • 傳送的是SOAP格式的HTTP + XML,中間會帶後續資料長度的神秘HEX數值
          • 接收時
            • 第1條是SOAP的HTTP
            • 第2條看起來,內容只有神秘HEX數值,其他應該只是buffer沒清除
            • 第3條是SOAP的XML,也就是實際事務機回應的內容
            • 第4條看起來,內容只是神秘HEX數值0,標示後面沒資料,同樣的,buffer沒清除

          內容我沒有細看,
          粗淺看起來,事務機回覆的內容應該是描述事務機的能力,和支援的項目、格式。

          傳送部份看起來只是制式化的訊息,應該是不用特別處理,
          要掃描時,固定按這個訊息送即可,應該不用特別處理。

          至於回覆的資料要不要parse,目前我還不清楚,可能要看SANE需不需要這些資訊。

          結論:
          bb_open看起來,應該就跟hello沒啥不同,
          大致就是跟事務機通知一下,取得事務機狀態,
          確定事務機目前可以準備掃描工作而已。

          傳遞的訊息雖然是XML,但應該都是制式化的,
          不用特別parse處理,應該都是千篇一律。

          總之,bb_open就是按上述訊息丟,大概確定收到訊息和上面差不多即可。

          2015年1月24日

          HPLIP bb-soap解析 - 1

          前言:
          接續前面2篇網樂通Scanner Server文章,
          這篇開始,會將我針對HP Color LaserJet CM1015掃描功能的Close Code解析,
          因為目前尚未破解,所以這系列會不會有完結篇不確定,
          解析到哪,又剛好有空、有興趣,就po到哪。

          背景資訊:
          HP Color LaserJet CM1015這台HP事務機功能如下:
          • USB介面
          • 有彩色掃描功能
          • 有彩色列印功能
          • 是雷射列印
          這台事務機在Linux上,從HPLIP 2.8.10開始支援,Linux上提供
          • 黑白、彩色掃描
          • 黑白、彩色列印
          • 印表機狀態資訊
          相關資訊可以參考:
          HP Color LaserJet cm1015 Multifunction Printer

          而根據HPLIP 2.8.10的Release時間回推,這台應該是在2008年的款式,
          我的購買時間我已經忘了。

          HPLIP本身雖然是OpenSource的專案,但HP並沒有將全部的檔案都OpenSource,
          HPLIP在大部分機種上要求要安裝Driver Plugin,
          這個Driver Plugin提供了這些機種需要的Close Code Library,
          它們包括:
          • bb_marvell-x86_32.so
          • bb_marvell-x86_64.so
          • bb_soapht-x86_32.so
          • bb_soapht-x86_64.so
          • bb_soap-x86_32.so
          • bb_soap-x86_64.so
          • fax_marvell-x86_32.so
          • fax_marvell-x86_64.so
          • hbpl1-x86_32.so
          • hbpl1-x86_64.so
          • lj-x86_32.so
          • lj-x86_64.so
          以CM1015來說,CM1015需要bb_soap。

          從程式碼看起來,
          HP不同機種使用了不同的Protocol,不同Protocol使用不同的Close Code Library檔案,
          CM1015的Protocol看起來只是單純的SOAP,使用的是bb_soap。

          怎麼知道是用bb_soap?
          因為我在網樂通上手動把Driver Plugin放上去,執行scanimage後,
          在/var/log/syslog出現類似如下:
          scanimage: common/utils.c 188: unable to load library /usr/local/hplip/share/hplip/scan/plugins/bb_soap.so: /usr/local/hplip/share/hplip/scan/plugins/bb_soap.so: wrong ELF class: ELFCLASS32

          當然,這是示意訊息,原始錯誤訊息印象中是Segfault,但它的確標明了使用的library。

          因為HP只將Protocol Close,掃描的上層是SANE,下層是HPMUD + libusb,示意圖如下:
          所以透過修改程式,
          可以在HPMUD和sane-hpaio backend加上printf,
          就能知道它的呼叫flow,儘管它沒有Open,
          也能知道傳遞什麼給事務機,步驟是什麼。

          解析開始:
          建立環境:
          建個VM,USB map進去,按網樂通類似步驟把HPLIP、SANE、CUPS build出來。

          找程式起始點:
          首先先找hpaio backend的呼叫點,找到是在
          hplip-3.14.10/scan/sane/

          繼續找bb_soap的呼叫點,找到主要是
          hplip-3.14.10/scan/sane/soap.c

          再來找hpmud,找到是
          hplip-3.14.10/io/hpmud/

          主要應該是
          hplip-3.14.10/io/hpmud/hpmud.c

          至於hplip-3.14.10/io/mudext不用管它,看裡面有註明是給python用的library。

          查看程式,修改程式碼,加printf:
          看soap.c,看到
          • ps->bb_open = get_library_symbol(ps->bb_handle, "bb_open")
          • ps->bb_close = get_library_symbol(ps->bb_handle, "bb_close")
          • ps->bb_get_parameters = get_library_symbol(ps->bb_handle, "bb_get_parameters")
          • ps->bb_is_paper_in_adf = get_library_symbol(ps->bb_handle, "bb_is_paper_in_adf")
          • ps->bb_start_scan = get_library_symbol(ps->bb_handle, "bb_start_scan")
          • ps->bb_end_scan = get_library_symbol(ps->bb_handle, "bb_end_scan")
          • ps->bb_get_image_data = get_library_symbol(ps->bb_handle, "bb_get_image_data")
          • ps->bb_end_page = get_library_symbol(ps->bb_handle, "bb_end_page")
          非常好,它將bb_soap的所有function都列好了,不用辛苦找。
          接著在這些呼叫點前後加上printf,把原本的DBG改成printf。

          hpmud裡面也是,把DBG都改成printf,看到open、close、read、write,都加上printf。

          重新編譯後,執行
          scanimage > AAA

          看看AAA裡面有什麼,如下:
          [10153] hpmud_probe_devices() bus=3
          sane_hpaio_open(/usb/HP_Color_LaserJet_CM1015?serial=00CNF87DL012)
          io_mode = 1
          [10153,13449,0,0,0,0] hpmud_device_open() uri=hp:/usb/HP_Color_LaserJet_CM1015?serial=00CNF87DL012 iomode=1
          bb_open(session)
          [10153] hpmud_channel_open() dd=1 name=HP-SOAP-SCAN
          [10153] hpmud_channel_write() dd=1 cd=19 buf=0x7fca030fd380 size=154 sectime=45
          [10153] hpmud_channel_write() dd=1 cd=19 buf=0x7fca030fd458 size=426 sectime=45
          [10153] hpmud_channel_read() dd=1 cd=19 buf=0xd7b5c8 size=4096 sectime=45
          [10153] hpmud_channel_read() dd=1 cd=19 buf=0xd7b5c8 size=4096 sectime=45
          [10153] hpmud_channel_read() dd=1 cd=19 buf=0xd7b5c8 size=4096 sectime=45
          [10153] hpmud_channel_read() dd=1 cd=19 buf=0xd7b5c8 size=4096 sectime=45
          [10153] hpmud_channel_close() dd=1 cd=19
          bb_open end
          sane_hpaio_control_option (option=mode action=auto value=na)
          sane_hpaio_control_option (option=resolution action=auto value=na)
          sane_hpaio_control_option (option=brightness action=auto value=na)
          sane_hpaio_control_option (option=contrast action=auto value=na)
          sane_hpaio_control_option (option=compression action=auto value=na)
          sane_hpaio_control_option (option=jpeg-quality action=auto value=na)
          sane_hpaio_control_option (option=tl-x action=auto value=na)
          sane_hpaio_control_option (option=tl-y action=auto value=na)
          sane_hpaio_control_option (option=br-x action=auto value=na)
          sane_hpaio_control_option (option=br-y action=auto value=na)
          sane_hpaio_get_option_descriptor(option=option-cnt)
          sane_hpaio_control_option (option=option-cnt action=get value=14)
          sane_hpaio_get_option_descriptor(option=option-cnt)
          sane_hpaio_control_option (option=option-cnt action=get value=14)
          sane_hpaio_get_option_descriptor(option=mode-group)
          sane_hpaio_get_option_descriptor(option=mode)
          sane_hpaio_get_option_descriptor(option=resolution)
          sane_hpaio_get_option_descriptor(option=advanced-group)
          sane_hpaio_get_option_descriptor(option=brightness)
          sane_hpaio_get_option_descriptor(option=contrast)
          sane_hpaio_get_option_descriptor(option=compression)
          sane_hpaio_get_option_descriptor(option=jpeg-quality)
          sane_hpaio_get_option_descriptor(option=geometry-group)
          sane_hpaio_get_option_descriptor(option=tl-x)
          sane_hpaio_get_option_descriptor(option=tl-y)
          sane_hpaio_get_option_descriptor(option=br-x)
          sane_hpaio_get_option_descriptor(option=br-y)
          sane_hpaio_control_option (option=br-x action=get value=14149222)
          sane_hpaio_control_option (option=tl-x action=get value=0)
          sane_hpaio_control_option (option=br-y action=get value=19459342)
          sane_hpaio_control_option (option=tl-y action=get value=0)
          sane_hpaio_control_option (option=tl-x action=get value=0)
          sane_hpaio_get_option_descriptor(option=br-x)
          sane_hpaio_control_option (option=br-x action=set value=14149222)
          sane_hpaio_control_option (option=tl-y action=get value=0)
          sane_hpaio_get_option_descriptor(option=br-y)
          sane_hpaio_control_option (option=br-y action=set value=19459342)
          sane_hpaio_start()
          bb_start_scan
          [10153] hpmud_channel_open() dd=1 name=HP-SOAP-SCAN
          [10153] hpmud_channel_write() dd=1 cd=19 buf=0x7fca030fd380 size=154 sectime=45
          [10153] hpmud_channel_write() dd=1 cd=19 buf=0x7fffda5ca8f0 size=5 sectime=1
          [10153] hpmud_channel_write() dd=1 cd=19 buf=0x7fffda5ca910 size=1359 sectime=1
          [10153] hpmud_channel_write() dd=1 cd=19 buf=0x7fca030fd8a9 size=7 sectime=1
          [10153] hpmud_channel_read() dd=1 cd=19 buf=0xd83a68 size=4096 sectime=45
          [10153] hpmud_channel_read() dd=1 cd=19 buf=0xd83a68 size=4096 sectime=45
          [10153] hpmud_channel_read() dd=1 cd=19 buf=0xd83a68 size=4096 sectime=45
          bb_start_scan end
          bb_get_parameters
          bb_get_parameters end
          set traits iPixelsPerRow=632 iBitsPerPixel=8 lNumRows=876 iComponentsPerPixel=1
          cnt=1024 index=0 input=0xd68e10 inputAvail=1024 inputUsed=1024 inputNextPos=1024 output=(nil) outputAvail=0 outputThisPos=0
          [10153] hpmud_channel_read() dd=1 cd=19 buf=0xd83a68 size=4096 sectime=45
          cnt=1024 index=0 input=0xd68e10 inputAvail=1024 inputUsed=1024 inputNextPos=2048 output=(nil) outputAvail=0 outputThisPos=0
          cnt=1024 index=0 input=0xd68e10 inputAvail=1024 inputUsed=1024 inputNextPos=3072 output=(nil) outputAvail=0 outputThisPos=0
          [10153] hpmud_channel_read() dd=1 cd=19 buf=0xd83a68 size=4096 sectime=45
          [10153] hpmud_channel_read() dd=1 cd=19 buf=0xd83a68 size=4096 sectime=45
          cnt=1024 index=0 input=0xd68e10 inputAvail=1024 inputUsed=1024 inputNextPos=4096 output=(nil) outputAvail=0 outputThisPos=0
          cnt=1024 index=0 input=0xd68e10 inputAvail=1024 inputUsed=1024 inputNextPos=5120 output=(nil) outputAvail=0 outputThisPos=0
          [10153] hpmud_channel_read() dd=1 cd=19 buf=0xd83a68 size=4096 sectime=45
          cnt=1024 index=0 input=0xd68e10 inputAvail=1024 inputUsed=1024 inputNextPos=6144 output=(nil) outputAvail=0 outputThisPos=0
          cnt=1024 index=0 input=0xd68e10 inputAvail=1024 inputUsed=1024 inputNextPos=7168 output=(nil) outputAvail=0 outputThisPos=0
          [10153] hpmud_channel_read() dd=1 cd=19 buf=0xd83a68 size=4096 sectime=45
          [10153] hpmud_channel_read() dd=1 cd=19 buf=0xd83a68 size=4096 sectime=45
          cnt=1024 index=0 input=0xd68e10 inputAvail=1024 inputUsed=1024 inputNextPos=8192 output=(nil) outputAvail=0 outputThisPos=0
          cnt=1024 index=0 input=0xd68e10 inputAvail=1024 inputUsed=1024 inputNextPos=9216 output=(nil) outputAvail=0 outputThisPos=0
          [10153] hpmud_channel_read() dd=1 cd=19 buf=0xd83a68 size=4096 sectime=45
          cnt=1024 index=0 input=0xd68e10 inputAvail=1024 inputUsed=1024 inputNextPos=10240 output=(nil) outputAvail=0 outputThisPos=0
          [10153] hpmud_channel_read() dd=1 cd=19 buf=0xd83a68 size=4096 sectime=45
          cnt=450 index=0 input=0xd68e10 inputAvail=450 inputUsed=450 inputNextPos=10690 output=(nil) outputAvail=0 outputThisPos=0
          cnt=0 index=0 input=(nil) inputAvail=0 inputUsed=0 inputNextPos=10690 output=(nil) outputAvail=0 outputThisPos=0
          act traits iPixelsPerRow=637 iBitsPerPixel=1 lNumRows=876 iComponentsPerPixel=1
          bb_getparameters
          bb_getparameters end
          sane_hpaio_get_parameters(): format=0, last_frame=1, lines=876, depth=1, pixels_per_line=637, bytes_per_line=80
          P4
          # SANE data follows
          637 876
          sane_hpaio_read() handle=0xd68720 data=0xd7ba40 maxLength=32768
          cnt=0 index=0 input=(nil) inputAvail=0 inputUsed=0 inputNextPos=10690 output=0xd7ba40 outputAvail=32768 outputThisPos=0
          -sane_hpaio_read() output=0xd7ba40 bytes_read=32768 maxLength=32768 status=0
          ▒       ▒sane_hpaio_read() handle=0xd68720 data=0xd7ba40 maxLength=32768
          cnt=0 index=0 input=(nil) inputAvail=0 inputUsed=0 inputNextPos=10690 output=0xd7ba40 outputAvail=32768 outputThisPos=32768
          -sane_hpaio_read() output=0xd7ba40 bytes_read=32768 maxLength=32768 status=0
          ▒       ▒sane_hpaio_read() handle=0xd68720 data=0xd7ba40 maxLength=32768
          cnt=0 index=0 input=(nil) inputAvail=0 inputUsed=0 inputNextPos=10690 output=0xd7ba40 outputAvail=32768 outputThisPos=65536
          -sane_hpaio_read() output=0xd7ba40 bytes_read=4544 maxLength=32768 status=0
          sane_hpaio_read() handle=0xd68720 data=0xd7ba40 maxLength=32768
          cnt=0 index=0 input=(nil) inputAvail=0 inputUsed=0 inputNextPos=10690 output=0xd7ba40 outputAvail=32768 outputThisPos=70080
          bb_end_page
          [10153] hpmud_channel_close() dd=1 cd=19
          bb_end_page end
          -sane_hpaio_read() output=0xd7ba40 bytes_read=0 maxLength=32768 status=5
          sane_hpaio_cancel()
          bb_end_scan
          [10153] hpmud_channel_open() dd=1 name=HP-SOAP-SCAN
          [10153] hpmud_channel_write() dd=1 cd=19 buf=0x7fca030fd380 size=154 sectime=45
          [10153] hpmud_channel_write() dd=1 cd=19 buf=0x7fffda5cb190 size=5 sectime=1
          [10153] hpmud_channel_write() dd=1 cd=19 buf=0x7fffda5cb1b0 size=442 sectime=1
          [10153] hpmud_channel_write() dd=1 cd=19 buf=0x7fca030fd8a9 size=7 sectime=1
          [10153] hpmud_channel_read() dd=1 cd=19 buf=0xd83a68 size=4096 sectime=45
          [10153] hpmud_channel_read() dd=1 cd=19 buf=0xd83a68 size=4096 sectime=45
          [10153] hpmud_channel_read() dd=1 cd=19 buf=0xd83a68 size=4096 sectime=45
          [10153] hpmud_channel_read() dd=1 cd=19 buf=0xd83a68 size=4096 sectime=45
          [10153] hpmud_channel_close() dd=1 cd=19
          bb_end_scan end
          sane_hpaio_close()
          bb_close
          close end bb_unload
          bb unload end
          [10153] hpmud_device_close() dd=1
          這整段一長串,會注意到:
          1. bb_soap function呼叫流程,如下:
          • bb_open
          • bb_start_scan
          • bb_get_parameters
          • bb_get_parameters
          • bb_end_page
          • bb_end_scan
          • bb_close
          • bb_unload
          2. 和USB的動作都使用下列這些function:
          • hpmud_channel_open
          • hpmud_channel_close
          • hpmud_channel_read
          • hpmud_channel_write
          查看hpmud傳輸內容:
          修改hpmud.c,在hpmud_channel_read和hpmud_channel_write裡面加上寫檔,
          讀取和寫入的資料統統寫到檔案中,我是如下:
          讀取部份:
          hpmud_read_channel_1.dump
          hpmud_read_channel_2.dump
          .....

          寫入部份:
          hpmud_write_channel_1.dump
          hpmud_write_channel_2.dump
          .....

          精彩的來了,我們看看它到底傳什麼給事務機,又從事務機收什麼回來?
          cat /tmp/hpmud_write_channel_1.dump
          POST / HTTP/1.1
          Host: http:0
          User-Agent: gSOAP/2.7
          Content-Type: application/soap+xml; charset=utf-8
          Transfer-Encoding: chunked
          Connection: close
          

          cat /tmp/hpmud_write_channel_2.dump
          19E
          
          <?xml version="1.0" encoding="UTF-8"?>
          <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" xmlns:SOAP-ENC="http://www.w3.org/2003/05/soap-encoding" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wscn="http://tempuri.org/wscn.xsd"><SOAP-ENV:Body><wscn:GetScannerElements></wscn:GetScannerElements></SOAP-ENV:Body></SOAP-ENV:Envelope>
          0
          

          cat /tmp/hpmud_read_channel_1.dump
          HTTP/1.1 200 OK
          Server: gSOAP/2.7
          Content-Type: application/soap+xml; charset=utf-8
          Transfer-Encoding: chunked
          Connection: close
          

          cat /tmp/hpmud_read_channel_2.dump
          7CB
          1.1 200 OK
          Server: gSOAP/2.7
          Content-Type: application/soap+xml; charset=utf-8
          Transfer-Encoding: chunked
          Connection: close
          

          dump出來的訊息好面熟,看起來很像是HTTP和XML啊.....
          Google soap,查到:
          SOAP Wiki

          原來SOAP是以HTTP + XML為核心的物件描述語言,
          而CM1015以SOAP做為溝通的通訊協定。

          這裡有個部份我一開始想不通,它每份資料的斷點在哪裡?為何會出現19E這樣的神秘字串?
          後來比對hpmud_read_channel和hpmud_write_channel的動作,搭配神秘數字0,
          終於搞清楚它神秘字串是表示後面還有多少字要傳送或接收,
          當這段資料後面沒東西時,就傳遞個0,表示後面沒資料,
          有資料時,神秘字串是後一筆資料的字串長度的HEX表示。

          以19E為例,19E表示:
          <?xml version="1.0" encoding="UTF-8"?>
          <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" xmlns:SOAP-ENC="http://www.w3.org/2003/05/soap-encoding" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wscn="http://tempuri.org/wscn.xsd"><SOAP-ENV:Body><wscn:GetScannerElements></wscn:GetScannerElements></SOAP-ENV:Body></SOAP-ENV:Envelope>
          
          這整段的資料長度。

          本篇先到此為止,後續再戰。