2013-10-27 37 views
1

我在BitBash模式下使用FTDI D2xx驅動程序在Windows上運行tcl8.5/tk8.5應用程序(問題發生在XP,7和8)。還使用ftd2xx c擴展來訪問FTDI dll。在非阻塞的情況下在tcl讀取處理程序中處理非持久性eof

我有一個來自用戶的報告,最初的應用程序工作正常,但經過一天的不使用,居住在後臺,它突然從5M增長到100M,並開始消耗99%的CPU。 (這是不好的!)

在此之前,我曾遇到USB問題,特別是如果USB「拔下電源」。它可能會導致應用程序阻止,而Windows無法將其殺死。我的應用程序永遠不需要讀取USB,它只是寫入(控制它),但我發現在BitBash模式下,FTDI芯片會發送連續的數據流。處理讀操作會清除讀緩衝區,所以如果USB被拔出,沒有待處理的讀取被阻塞,我可以正常退出。

但現在,我認爲閱讀處理程序給我的問題。我寫了一小段測試代碼,它模仿了我認爲可以解決問題根源的實際應用程序。無論如何,我不明白tcl的行爲。

下面是代碼:

package require -exact ftd2xx 1.2.1 

    # define a read handler 
    # gets called by a fileevent readable 
    # 
    proc readchan {} { 
     variable cnt 
     set len [gets $::handle buf] 

     # buffer is non zero 

     if {$len > 0} { 
      incr cnt 
      set end [eof $::handle] 
      puts "$len ($cnt) eof $end"; 
      # if it wasn't an eof output the buffer 
      if {!$end} { 
        puts $buf 
      } 
     } elseif {$len == 0} { 
      # was a zero length read 
      puts -nonewline "0" 
      set end [eof $::handle] 
      if { !$end } { 
        # eof makes the $len invalid? 
        puts "-0" 
        #puts "\nlen is 0 and eof is $end - exit!"; 
        #exit 
      } 
     } else { 
      # len was negative (-1) so data in buffer but no end of line (in binary mode) 
      if { [eof $::handle] } { 
        puts "EOF w/len 0" 
      } else { 
        puts -nonewline "." 
      } 
     } 
} 

# main code 
# 
# find the usb device and open it 
set usb [ftd2xx list] 
lassign $usb d 
lassign $d d id e loc f serial 
puts "found USB $serial" 
set handle [ftd2xx open -serial $serial] 
puts "Opened USB $handle" 
# 
# configure it for bitbash mode and for binary, non blocking 
# 
set bitmode 0xFF01 
chan configure $handle -tranlation binary -bitmode $bitmode -blocking 0 
fileevent $handle readable readchan 

# output something to the usb every 100ms or so required to cause failure 
# 
while {1} { 
    set continue 0 
    after 100 {set continue 1} 

    # putting: 
    # "a" made it crash after 245 "timeouts" - no flush 
    # null made it past 255 - no flush 
    # "aa" made it crash after 164 "timeouts - no flush 

    puts $handle "aa" 

    #flushing $handle makes it crash after first flush 
    #flush $handle 
    puts -nonewline "w" 
    vwait continue 
} 

這裏是從上面的代碼的輸出:

$ tclsh85 usbfailtest.tcl 
found USB AH009L40 
Opened USB ftd2xx0 
w...w....w....w....w....w....w...w....w.126976 (1) eof 1 <<< 126K length with eof true 
..w....w....w....w...w....w....w....w..126976 (2) eof 1 <<< "w" output for usb write 
.w....w....w...w....w....w....w....w...126976 (3) eof 1 <<< this is 3rd non-zero read 
w...w....w....w....w....w...w....w....w.126976 (4) eof 1 <<< "." output when len -1 
..w....w...w....w....w....w....w...w...126976 (5) eof 1 <<< line takes about 1 sec 
w....w....w....w....w...w....w....w....w126976 (6) eof 1 
. 
. (output skipped) 
. 
.w....w....w....w...w....w....w....w...126976 (156) eof 1 
w....w....w...w....w....w....w....w....w126976 (157) eof 1 
..w....w....w....w....w....w...w....w..126976 (158) eof 1 
.w....w....w...w....w....w....w....w...126976 (159) eof 1 
w....w...w....w....w....w....w....w...w.126976 (160) eof 1 
..w....w....w....w....w...w....w....w..126976 (161) eof 1 
.w....w....w....w...w....w....w....w...126976 (162) eof 1 
w....w...w....w....w....w....w....w...w.126976 (163) eof 1 
..w....w....w....w....w...w....w102695 (164) eof 0 << a 102K buffer with EOF false 
aa << all but two of the 102K buffer were null? 
0-0 << zero length buffer with no eof 
2 (165) eof 0 
aa << two length buffer, no eof, and we got two chars 
3 (166) eof 0 
aaa << three length bufffer, no eof, and we got three chars 
2 (167) eof 0 
aa << etc. 
0-0 << another zero zero these scroll out *very* fast. 
0-0 
0-0 
0-0 
2 (168) eof 0 
aa << an so forth 
0-0 
0-0 
. 
. (output skipped) 
. 
43 (268) eof 0 
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 
..w...22192 (269) eof 1 
w...w....w....w....w....w...w....w....w.126976 (270) eof 1 << revert to "slow" mode 
..w....w....w....w...w....w....w....w..126976 (271) eof 1 
.w....w....w...w....w....w....w....w...126976 (272) eof 1 
w....w...w....w....w....w....w....w...w.126976 (273) eof 1 
..w....w....w....w....w...w....w....w..126976 (274) eof 1 

輸出的解釋:

首先,讀出處理程序是被調用多次(每個「。」)與一個不完整的緩衝區(長度-1)和沒有eof條件。最終,某些內容超時或者內部緩衝區限制被觸發,強制讀取完成。同時EOF提出。 「... 126987」的每一行需要大約一秒鐘的時間來編寫。

經過一定數量的EOF(即...... 126987的行 - 在本例中爲164 - 非常可重複),取決於寫入通道的數據量以及通道是否刷新,讀取完成後沒有EOF(第164行)。

到目前爲止,讀事件中斷率是可以接受的,但是,它會突然間升高並消耗大量處理它的週期。在較慢的機器上,沒有時間做任何有用的事情。

我有很多關於這個難題的問題。但開始於:

我不明白爲什麼讀取處理程序將被調用與0字節掛起和非eof條件。緩衝區中是否必須至少有一個字節是「可讀的」?

我不明白爲什麼EOF是暫時的。我期望在USB端口上的EOF意味着它被拔掉,但事實並非如此。

如果我在寫入USB之後刷新頻道,我所得到的全部長度都是0,即使殺掉應用程序並重新啓動它,這仍然存在。清除此(到慢速模式)的唯一方法是從USB拔下設備並重新開始(不沖洗)。我不知道該怎麼做。我必須刷新頻道才能寫入實際的FTDI芯片。

我應該使用一個固定長度的讀取而不是獲取這個?

+0

如果在刷新頻道之後發生了一些奇怪的事情,或者在沒有刷新頻道的情況下將很多內容寫入頻道之後,我會認爲編寫任何內容都不起作用。如果寫入時沒有刷新,那麼在填充緩衝區之前數據可能永遠不會發送。 –

+0

在我的實際應用當然,我做了一個刷新發布寫入。作爲實驗代碼的一部分,我會/不會沖洗寫入。我認爲奇怪的是,沖洗「渠道」(寫作)改變了人們認爲獨立閱讀的行爲。 「puts」也必須在二進制模式下具有-nonewline選項。 – user1967890

+1

只要您不知道要接收的字節,它就很難。該通道處於二進制模式。在這種情況下,使用gets可能不太好。獲取無法檢測到行結束?改爲使用read。我不知道FTDI芯片 - 它是5V芯片嗎?一些232系列在5V芯片(RS232標準爲+ -12V)方面存在問題。可能會收到錯誤的數據。 – tue

回答

0

我對ftd2xx軟件包沒有什麼特別的瞭解,但是我看到一些奇怪的東西。通常,當eof返回1時,最好關閉處理程序中的通道。當數據準備就緒或者通道關閉時(可能是驅動程序或操作系統關閉它),fileevent處理程序會被調用,如果您不告訴TCL關閉處理程序中的通道,TCL將一直重複調用它(告訴你要做點什麼)。 從fileevent手冊:

「A信道也被認爲是可讀的,如果文件或錯誤條件的端部存在於底層文件或設備用於腳本來檢查這些條件和處理是重要的。它們適當;例如,如果沒有對文件結尾進行特殊檢查,則腳本無法讀取數據,返回並立即再次調用時可能會出現無限循環。「

1

我用讀取而不是獲取實現了實際的代碼。他用我的客戶作爲測試臺,報告問題已經解決。從現在開始,我將使用read而不是獲取二進制通道。

相關問題