2013-10-27 5 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가 발생했습니다. "... 126987"의 각 줄에는 약 1 초가 걸립니다.

채널에 기록 된 데이터의 양과 채널이 플러시되었는지 여부에 따라 몇 가지 EOF (즉, .... 126987 라인 -이 경우 164 - 매우 반복 가능) 이후, EOF (164 행).

이 시점까지는 읽기 이벤트 인터럽트 속도는 견딜 수 있었지만 급격히 증가하여 처리하는 사이클을 많이 소모했습니다. 더 느린 머신에서는 유용 할 시간이 없습니다.

나는 이것에 대해 많은 설명을하기가 어렵다. 하지만 함께 시작하려면 :

왜 내가 읽기 처리기 보류중인 0 바이트 보류 및 비 - eof 조건으로 호출 얻을 이해가 안돼. 버퍼에 "읽을 수있는"바이트가 적어도 하나 있어야합니까?

왜 EOF가 일시적인지 이해할 수 없습니다. USB 포트의 EOF는 플러그가 꽂혀 있지 않은 것과 같은 것을 의미하지만, 그렇지 않습니다.

USB에 기록한 후 채널을 플러시하면 0 길이의 읽기가 발생하며 앱을 종료하고 다시 시작한 경우에도 계속 표시됩니다. 이것을 (슬로우 모드로) 해제하는 유일한 방법은 USB에서 장치의 플러그를 뽑고 처음부터 다시 시작하는 것입니다 (플래시없이). 나는 이것을 어떻게 만들지 모르겠다. 필자는 FTDI 칩에 실제로 쓰기 위해 채널을 플러시해야한다.

이것을 얻기 위해 고정 길이로 읽어야합니까?

+0

채널을 플러시 한 후 이상한 일이 발생하거나 플러시하지 않고 채널에 많은 내용을 쓰고 난 후에는 아무 것도 쓰지 않으면 작동하지 않는다고 생각합니다. 플러싱하지 않고 작성하면 버퍼가 채워질 때까지 데이터가 전송되지 않을 가능성이 높습니다. –

+0

내 실제 응용 프로그램에서는 물론 글을 게시하기 위해 플러시를 수행합니다. 실험 코드의 일부로 필자는 쓰기를 플러시하지 않습니다. 제가 생각하기에 이상한 것은 채널을 플러시하는 것입니다 (글쓰기?)는 독자의 생각을 독자적으로 생각하는 행동을 변경합니다. "puts"는 또한 바이너리 모드에서 --newewline 옵션을 가져야합니다. – user1967890

+1

수신 할 바이트에 대해 알지 못하는 한 어렵습니다. 채널은 바이너리 모드입니다. 이 경우 gets를 사용하는 것은 좋지 않을 수 있습니다. 도착하면 줄의 끝을 감지 할 수 없습니까? 대신에 읽기를 사용하십시오. 나는 FTDI 칩을 모른다 - 5V 칩인가? 일부 232 시리얼은 5V 칩 (RS232 표준은 +12V)에 문제가 있습니다. 나쁜 데이터를받을 수 있습니다. – tue

답변

0

특별히 ftd2xx 패키지에 대해 잘 모릅니다. 그러나 이상한 것을 봅니다.일반적으로 eof가 1을 반환하면 핸들러에서 채널을 닫는 것이 좋습니다. fileevent 핸들러는 데이터가 준비 될 때마다 또는 채널이 외부 적으로 닫히거나 (드라이버 나 OS가 닫을 때) 호출되며, 핸들러에서 채널을 닫으려는 TCL을 알리지 않으면 TCL은 반복적으로이를 영원히 계속 호출합니다 당신에게 뭔가를 말함). fileevent 설명서에서 :

"A 채널은 또한 파일 또는 오류 조건의 끝이 기본 파일 또는 장치에있는 경우 읽을 수 간주됩니다 스크립트가 이러한 조건을 확인하고 처리하는 것이 중요하다. 예를 들어, 파일 끝을 특별히 확인하지 않으면 무한 루프가 발생하여 스크립트가 데이터를 읽지 않고 반환되고 즉시 다시 호출됩니다. "

1

실제 코드를 gets 대신 읽음으로 구현했습니다. 고객을 테스트 벤치로 사용하여 문제가 해결되었다고보고했습니다. 지금부터 바이너리 채널에 대한 gets 대신에 read를 사용할 것이다.