다음을 통해 공유


USB 대량 전송 요청을 보내는 방법(UWP 앱)

이 항목에서는 USB 대량 전송 및 USB 디바이스와 통신하는 UWP 앱에서 전송 요청을 시작하는 방법에 대해 알아봅니다.

USB 최고 속도, 고속 및 SuperSpeed 디바이스는 대량 엔드포인트를 지원할 수 있습니다. 이러한 엔드포인트는 USB 플래시 드라이브 간 데이터 전송과 같은 대량의 데이터를 전송하는 데 사용됩니다. 대량 전송은 오류 검색을 허용하고 호스트 또는 디바이스에서 데이터를 수신하도록 제한된 수의 재시도를 포함하기 때문에 안정적입니다. 대량 전송은 시간이 중요하지 않은 데이터에 사용됩니다. 데이터는 버스에서 사용할 수 있는 사용되지 않는 대역폭이 있는 경우에만 전송됩니다. 따라서 버스가 다른 전송으로 사용 중인 경우 대량 데이터가 무기한 대기할 수 있습니다.

대량 엔드포인트는 단방향이며 한 번의 전송으로 데이터를 IN 또는 OUT 방향으로 전송할 수 있습니다. 대량 데이터 읽기 및 쓰기를 지원하려면 디바이스에서 대량 IN 및 대량 OUT 엔드포인트를 지원해야 합니다. Bulk IN 엔드포인트는 디바이스에서 호스트로 데이터를 읽는 데 사용되며 대량 OUT 엔드포인트는 호스트에서 디바이스로 데이터를 보내는 데 사용됩니다.

대량 전송 요청을 시작하려면 앱에 엔드포인트를 나타내는 파이프 에 대한 참조가 있어야 합니다. 파이프는 디바이스가 구성될 때 디바이스 드라이버가 여는 통신 채널입니다. 앱의 경우 파이프는 엔드포인트의 논리적 표현입니다. 엔드포인트에서 데이터를 읽기 위해 앱은 연결된 대량 IN 파이프에서 데이터를 가져옵니다. 엔드포인트에 데이터를 쓰기 위해 앱은 대량 OUT 파이프로 데이터를 보냅니다. 대량 읽기 및 쓰기 파이프의 경우 UsbBulkInPipeUsbBulkOutPipe 클래스를 사용합니다.

앱은 특정 정책 플래그를 설정하여 파이프의 동작을 수정할 수도 있습니다. 예를 들어 읽기 요청의 경우 파이프에서 중단 조건을 자동으로 지우는 플래그를 설정할 수 있습니다. 이러한 플래그에 대한 자세한 내용은 UsbReadOptionsUsbWriteOptions를 참조하세요.

시작하기 전에

1단계: 대량 파이프 개체 가져오기

전송 요청을 시작하려면 대량 파이프 개체(UsbBulkOutPipe 또는 UsbBulkInPipe )에 대한 참조 가져와야 합니다. 모든 인터페이스의 모든 설정을 열거하여 파이프를 가져올 수 있습니다. 그러나 데이터 전송의 경우 활성 설정의 파이프만 사용해야 합니다. 연결된 엔드포인트가 활성 설정에 없는 경우 파이프 개체가 null이면 입니다.

다음을 원하는 경우... 이 속성 값 사용
대량 파이프로 데이터를 보내고 UsbBulkOutPipe에 대한 참조를 가져옵니다. 디바이스 구성에서 하나의 USB 인터페이스를 노출하는 경우 UsbDevice.DefaultInterface.BulkOutPipes[n]

UsbDevice.Configuration.UsbInterfaces[m]. BulkOutPipes[n] 디바이스에서 지원하는 여러 인터페이스에서 대량 OUT 파이프를 열거합니다.

UsbInterface.InterfaceSettings[m]. BulkOutEndpoints[n]. 인터페이스의 설정에 의해 정의된 대량 OUT 파이프를 열거하기 위한 파이프입니다.

대량 OUT 엔드포인트에 대한 엔드포인트 설명자에서 파이프 개체를 가져오기 위한 UsbEndpointDescriptor.AsBulkOutEndpointDescriptor.Pipe입니다.
대량 파이프에서 데이터를 수신하면 UsbBulkInPipe 개체를 가져올 수 있습니다. 디바이스 구성이 하나의 USB 인터페이스를 노출하는 경우 UsbDevice.DefaultInterface.BulkInPipes[n]

UsbDevice.Configuration.UsbInterfaces[m]. BulkInPipes[n] 디바이스에서 지원하는 여러 인터페이스에서 대량 IN 파이프를 열거합니다.

UsbInterface.InterfaceSettings[m]. BulkInEndpoints[n]. 인터페이스의 설정에 의해 정의된 대량 IN 파이프를 열거하기 위한 파이프입니다.

대량 IN 엔드포인트에 대한 엔드포인트 설명자에서 파이프 개체를 가져오기 위한 UsbEndpointDescriptor.AsBulkInEndpointDescriptor.Pipe입니다.

참고

활성 설정에 있거나 null 검사 필요합니다.

2단계: 대량 파이프 구성(선택 사항)

검색된 대량 파이프에서 특정 플래그를 설정하여 읽기 또는 쓰기 작업의 동작을 수정할 수 있습니다.

디바이스에서 읽으려면 UsbBulkInPipe.ReadOptions 속성을 UsbReadOptions에 정의된 값 중 하나로 설정합니다. 쓰기의 경우 UsbBulkOutPipe.WriteOptions 속성을 UsbWriteOptions에 정의된 값 중 하나로 설정합니다.

다음을 원하는 경우... 이 플래그 설정
데이터 흐름을 중지하지 않고 엔드포인트에서 오류 조건 자동 지우기 AutoClearStall

자세한 내용은 중단 조건 지우기 를 참조하세요.

이 플래그는 읽기 및 쓰기 전송 모두에 적용됩니다.
최대 효율성으로 여러 읽기 요청을 보냅니다. 오류 검사를 바이패스하여 성능을 향상시킵니다. OverrideAutomaticBufferManagement

데이터 요청은 하나 이상의 전송으로 나눌 수 있으며, 각 전송에는 최대 전송 크기라고 하는 특정 바이트 수가 포함됩니다. 여러 전송의 경우 드라이버에서 수행한 오류 검사로 인해 두 전송을 큐에 대기하는 데 지연이 있을 수 있습니다. 이 플래그는 해당 오류 검사를 무시합니다. 최대 전송 크기를 얻으려면 UsbBulkInPipe.MaxTransferSizeBytes 속성을 사용합니다. 요청 크기가 UsbBulkInPipe.MaxTransferSizeBytes인 경우 이 플래그를 설정해야 합니다.

중요: 이 플래그를 설정하는 경우 파이프의 최대 패킷 크기의 배수로 데이터를 요청해야 합니다. 해당 정보는 엔드포인트 설명자에 저장됩니다. 크기는 디바이스의 버스 속도에 따라 달라집니다. 최고 속도, 고속 및 SuperSpeed; 최대 패킷 크기는 각각 64, 512 및 1024바이트입니다. 해당 값을 가져오려면 UsbBulkInPipe.EndpointDescriptor.MaxPacketSize 속성을 사용합니다.

이 플래그는 읽기 전송에만 적용됩니다.
길이가 0인 패킷으로 쓰기 요청 종료 ShortPacketTerminate

OUT 전송의 끝을 나타내기 위해 길이가 0인 패킷을 보냅니다.

이 플래그는 쓰기 전송에만 적용됩니다.
짧은 패킷 읽기 사용 안 함(엔드포인트에서 지원하는 최대 패킷 크기 미만) IgnoreShortPacket

기본적으로 디바이스가 최대 패킷 크기보다 작은 바이트를 보내면 앱에서 수신합니다. 짧은 패킷을 받지 않으려면 이 플래그를 설정합니다.

이 플래그는 읽기 전송에만 적용됩니다.

3단계: 데이터 스트림 설정

디바이스에서 대량 데이터를 보내면 대량 파이프의 입력 스트림에서와 같이 데이터가 수신됩니다. 입력 스트림을 가져오는 단계는 다음과 같습니다.

  1. UsbBulkInPipe.InputStream 속성을 가져와 입력 스트림에 대한 참조를 가져옵니다.
  2. DataReader 생성자에서 입력 스트림을 지정하여 DataReader 개체를 만듭니다.

디바이스에 데이터를 쓰려면 앱이 대량 파이프의 출력 스트림에 씁니다. 출력 스트림을 준비하는 단계는 다음과 같습니다.

  1. UsbBulkOutPipe.OutputStream 속성을 가져와 출력 스트림에 대한 참조를 가져옵니다.
  2. DataWriter 생성자에서 출력 스트림을 지정하여 DataWriter 개체를 만듭니다.
  3. 출력 스트림과 연결된 데이터 버퍼를 채웁다.
  4. 데이터 형식에 따라 WriteBytes와 같은 DataWriter 메서드를 호출하여 전송 데이터를 출력 스트림에 씁니다.

4단계: 비동기 전송 작업 시작

대량 전송은 비동기 작업을 통해 시작됩니다.

대량 데이터를 읽으려면 DataReader.LoadAsync를 호출하여 비동기 읽기 작업을 시작합니다.

대량 데이터를 작성하려면 DataWriter.StoreAsync를 호출하여 비동기 쓰기 작업을 시작합니다.

5단계: 읽기 전송 작업의 결과 가져오기

비동기 데이터 작업이 완료되면 작업 개체에서 읽거나 쓴 바이트 수를 가져올 수 있습니다. 읽기 작업의 경우 ReadBytes와 같은 DataReader 메서드를 호출하여 입력 스트림에서 데이터를 읽습니다.

중단 조건 지우기

때때로 앱에서 데이터 전송에 실패할 수 있습니다. 전송 실패는 엔드포인트의 중단 조건으로 인해 발생할 수 있습니다. 엔드포인트가 중단된 한 데이터를 기록하거나 읽을 수 없습니다. 데이터 전송을 진행하려면 앱이 연결된 파이프의 중단 조건을 지워야 합니다.

앱은 파이프가 발생할 때 중단 조건을 자동으로 지우도록 파이프를 구성할 수 있습니다. 이렇게 하려면 UsbBulkInPipe.ReadOptions 속성을 UsbReadOptions.AutoClearStall 또는 UsbBulkOutPipe.WriteOptions 속성으로 UsbWriteOptions.AutoClearStall로 설정합니다. 이 자동 구성을 사용하면 앱에서 전송에 실패하고 데이터 전송 환경이 원활하지 않습니다.

중단 조건을 수동으로 지우려면 대량 IN 파이프에 대해 UsbBulkInPipe.ClearStallAsync 를 호출합니다. Bulk OUT 파이프 에 대해 UsbBulkOutPipe.ClearStallAsync 를 호출합니다.

참고

중단 조건은 빈 엔드포인트를 나타내지 않습니다. 엔드포인트에 데이터가 없으면 전송이 완료되지만 길이는 0바이트입니다.

읽기 작업의 경우 새 전송 요청을 시작하기 전에 파이프에서 보류 중인 데이터를 지워야 할 수 있습니다. 이렇게 하려면 UsbBulkInPipe.FlushBuffer 메서드를 호출합니다.

USB 대량 전송 코드 예제

이 코드 예제에서는 대량 파이프에 쓰는 방법을 보여줍니다. 이 예제에서는 기본 인터페이스의 첫 번째 대량 OUT 파이프로 데이터를 보냅니다. 전송이 끝날 때 길이가 0인 패킷을 보내도록 파이프를 구성합니다. 전송이 완료되면 바이트 수가 표시됩니다.

    private async void BulkWrite()
    {
        String dataBuffer = "Hello World!";
        UInt32 bytesWritten = 0;

        UsbBulkOutPipe writePipe = usbDevice.DefaultInterface.BulkOutPipes[0];
        writePipe.WriteOptions |= UsbWriteOptions.ShortPacketTerminate;

        var stream = writePipe.OutputStream;

        DataWriter writer = new DataWriter(stream);

        writer.WriteString(dataBuffer);

        try
        {
            bytesWritten = await writer.StoreAsync();
        }
        catch (Exception exception)
        {
            ShowStatus(exception.Message.ToString());
        }
        finally
        {
            ShowStatus("Data written: " + bytesWritten + " bytes.");
        }
    }

이 코드 예제에서는 대량 파이프에서 읽는 방법을 보여줍니다. 이 예제에서는 기본 인터페이스의 첫 번째 대량 IN 파이프에서 데이터를 검색합니다. 최대 효율성을 위해 파이프를 에 구성하고 최대 패킷 크기의 청크로 데이터를 받습니다. 전송이 완료되면 바이트 수가 표시됩니다.

    private async void BulkRead()
    {
        UInt32 bytesRead = 0;

        UsbBulkInPipe readPipe = usbDevice.DefaultInterface.BulkInPipes[0];

        // Warning: Setting IgnoreShortPacket causes LoadAsync to block until you receive a number of packets >= readPipe.EndpointDescriptor.MaxPacketSize.
        // Remove the following line if you want to see messages that are less than the max transfer size, for example if you are communicating with a USBTMC device. 
        readPipe.ReadOptions |= UsbReadOptions.IgnoreShortPacket;

        var stream = readPipe.InputStream;
        DataReader reader = new DataReader(stream);

        try
        {
            bytesRead = await reader.LoadAsync(readPipe.EndpointDescriptor.MaxPacketSize);
        }
        catch (Exception exception)
        {
            ShowStatus(exception.Message.ToString());
        }
        finally
        {
            ShowStatus("Number of bytes: " + bytesRead);

            IBuffer buffer = reader.ReadBuffer(bytesRead);

            using (var dataReader = Windows.Storage.Streams.DataReader.FromBuffer(buffer))
            {
                dataReader.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8;
                ShowData(dataReader.ReadString(buffer.Length));
            }
        }
    }