2017-12-19 15 views
1

직렬 데이터 전송 완료를 기다리는 데 약간의 문제가있는 것처럼 보입니다. 출력 버퍼의 마지막 문자를 보낸 -Win32에서 직렬 전송 대기 완료

EV_TXEMPTY가 : 해당 MSDN article

내 해석은 EV_TXEMPTY 이벤트가 올바른 신호이며이되는 것을 나타낸다.

그러나 내 테스트에서 데이터가 버퍼에 제출되고 최종 결승전에 도달하기 오래 전에 즉시 이벤트가 발생합니다. 기간이 항상 0 인 아래의 재현 코드를 참조하십시오.

플래그의 목적을 잘못 이해 했습니까, 아니면 현대의 드라이버가 지원하지 않는 기능입니까? 후자의 경우에는 가능한 회피 방법이 있습니까, 동기 회선 상태 요청의 일부 형식을 말합니?

기록을 위해 테스트는 Windows 10 시스템에서 FTDI USB-RS485 및 TTL-232R 장치, Windows 7 시스템에서 USB-SERIAL CH340 인터페이스를 사용하여 수행되었으며 온보드 직렬 인터페이스는 2005 년 빈티지 Windows XP 기계. FTDI의 경우 USB 버스를 스니핑 (sniffing)하면 벌크 트랜잭션 (bulk out out)과 완료에 대한 명백한 인터럽트 알림이 나타나지 않습니다.

#include <stdio.h> 
#include <windows.h> 

static int fatal(void) { 
    fprintf(stderr, "Error: I/O error\n"); 
    return 1; 
} 

int main(int argc, const char *argv[]) { 
    static const char payload[] = "Hello, World!"; 
    // Use a suitably low bitrate to maximize the delay 
    enum { BAUDRATE = 300 }; 
    // Ask for the port name on the command line 
    if(argc != 2) { 
     fprintf(stderr, "Syntax: %s {COMx}\n", argv[0]); 
     return 1; 
    } 
    char path[MAX_PATH]; 
    snprintf(path, sizeof path, "\\\\.\\%s", argv[1]); 
    // Open and configure the serial device 
    HANDLE handle = CreateFileA(path, GENERIC_WRITE, 0, NULL, 
     OPEN_EXISTING, 0, NULL); 
    if(handle == INVALID_HANDLE_VALUE) 
     return fatal(); 
    DCB dcb = { 
     .DCBlength = sizeof dcb, 
     .BaudRate = BAUDRATE, 
     .fBinary = TRUE, 
     .ByteSize = DATABITS_8, 
     .Parity = NOPARITY, 
     .StopBits = ONESTOPBIT 
    }; 
    if(!SetCommState(handle, &dcb)) 
     return fatal(); 
    if(!SetCommMask(handle, EV_TXEMPTY)) 
     return fatal(); 
    // Fire off a write request 
    DWORD written; 
    unsigned int elapsed = GetTickCount(); 
    if(!WriteFile(handle, payload, sizeof payload, &written, NULL) || 
     written != sizeof payload) 
     return fatal(); 
    // Wait for transmit completion and measure time elapsed 
    DWORD event; 
    if(!WaitCommEvent(handle, &event, NULL)) 
     return fatal(); 
    if(!(event & EV_TXEMPTY)) 
     return fatal(); 
    elapsed = GetTickCount() - elapsed; 
    // Display the final result 
    const unsigned int expected_time = 
     (sizeof payload * 1000 /* ms */ * 10 /* bits/char */)/BAUDRATE; 
    printf("Completed in %ums, expected %ums\n", elapsed, expected_time); 
    return 0; 
} 

배경이 내가 장치 응답을 검증하기 위해 와이어에> 문자 사이에 3.5 문자 유휴 지연 주입을 시도하고 모드 버스 RTU 프로토콜 테스트 제품군의 일부라는 것이다. 틀림없이 임베디드 실시간 시스템이 작업에 훨씬 더 적합했을 것입니다.하지만 가능한 한 최상의 타이밍을 제어하면서 Windows 환경을 고수하는 것을 선호하는 여러 가지 이유가 있습니다.

+1

['SetupComm()'] (https://msdn.microsoft.com/en-us/library/windows/desktop/aa363439.aspx) 호출을 추가하여 버퍼 크기를 설정할 수 있습니다. 그것은 기본적으로입니다. 하지만 저는 Windows 프로그래머가 아닙니다. – unwind

+0

또한, 전송 지연을 구현하기 위해 ['SetCommBreak()'] (https://msdn.microsoft.com/en-us/library/windows/desktop/aa363433.aspx)를 사용할 수 있습니까? – unwind

+0

@unwind : 고맙습니다. 'SetupComm (handle, 2, 2)'(단일 문자 버퍼가'ERROR_INVALID_DATA' 오류를 낳습니다)를 시도했지만 불행히도 아무런 차이가 없었습니다. 적어도 Windows 10 시스템의 FTDI 인터페이스에는 해당되지 않습니다. 요청에서 볼 수있는 USB 버스에는 트래픽이 없습니다. – doynax

답변

0

@Hans Passant 및 @RbMm의 의견에 따르면 EV_TXEMPTY documentation에서 참조되는 출력 버퍼는 중간 버퍼이며 이벤트는 데이터가 드라이버에 전달되었음을 나타냅니다. 최종 장치 버퍼까지의 전체 체인을 포함하는 동등한 알림 이벤트가 정의되어 있지 않습니다.

대한 일반적인 해결책은 이송 될 현재 비트 레이트에 기초하여 수동 지연 짧은 그다지 명확하고 나머지 완충층의 중요한 최악의 마진을 추가하지 문자 간 갭, 클록 스큐 등

따라서 더 나은 대체 솔루션으로 답변을 주셔서 감사합니다.


그럼에도 불구하고, 내 특정 응용 프로그램 위해 나는 가능한 해결 방법을 구현했습니다.

대상 하드웨어는 FTDI RS485 인터페이스가있는 반이중 버스입니다. 이 특정 장치는 버스에 능동적으로 전송되는 데이터가 수신에서 능동적으로 필터링되지 않는 선택적 로컬 에코 모드를 제공합니다.

각 전송 후에 예상되는 반향이 왕복 확인으로 표시 될 때까지 기다릴 수 있습니다. 또한 단락 된 버스와 같은 특정 오류를 감지합니다.