USB communications using StreamReader and StreamWriter

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • stumorgan@gmail.com

    USB communications using StreamReader and StreamWriter

    I'm doing some USB communications in C# and am running into a minor
    annoyance. I'm using the Windows API CreateFile function to get a
    SafeFileHandle, which I then stuff into a FileStream and from there
    into StreamReader and StreamWriter objects. The StreamReader is
    working beautifully, but the StreamWriter isn't. If I convert the
    StreamWriter.Ba seStream back to a FileStream and use its
    SafeFileHandle in the Windows API WriteFile function to write the data
    then everything works perfectly, but that defeats the purpose of
    having the StreamWriter in the first place. I want to just use the
    StreamWriter.Wr ite() function. Is there something I'm doing
    incorrectly? Here's some random excerpts from my code so you can sort
    of see what I'm doing. The WnAPIWrapper is just my wrapper for
    getting C# friendly objects from the Windows API:

    // Get the input and output streams to the USB device from the Windows
    API
    // Basically just gets a SafeFileHandle to the USB device and puts it
    into a FileStream
    StreamReader fPipeIn = new
    StreamReader(Wi nAPIWrapper.Get FileStreamFromG uid(DeviceGuid,
    @"\PIPE00")) ;
    StreamWriter fPipeOut = new
    StreamWriter(Wi nAPIWrapper.Get FileStreamFromG uid(DeviceGuid,
    @"\PIPE01")) ;

    // At this point I can do fPipeIn.ReadLin e() and it works very well

    // Create the data to send to the device
    int command = 11;
    byte[] data = new byte[1]{(byte)command} ;

    // This method does NOT work. Why? fPipeOut is set to AutoFlush by
    the way
    fPipeOut.Write( data);

    // This method, accessing the Windows API WriteFile function directly
    with the FileStream.Safe FileHandle, works just fine
    WinAPIWrapper.W riteToStream((F ileStream)fPipe Out.BaseStream, data);

    Any help is much appreciated. I don't NEED to use the StreamWriter
    since I have a method that works, but it would be cleaner and nicer if
    I could.

    Thanks!
    Stu
  • Jeroen Mostert

    #2
    Re: USB communications using StreamReader and StreamWriter

    stumorgan@gmail .com wrote:
    <snip>
    // Create the data to send to the device
    int command = 11;
    byte[] data = new byte[1]{(byte)command} ;
    >
    // This method does NOT work. Why? fPipeOut is set to AutoFlush by
    the way
    fPipeOut.Write( data);
    >
    You're actually calling the StreamWriter.Wr ite(object) overload, because
    StreamWriter has no method for writing a byte[] (it's character-oriented,
    not byte-oriented).

    This ends up calling .ToString() on "data", which yields "System.Byt e[]"...
    This is one reason not to like overloads. (The moral here is actually not to
    declare an overload that takes an "object" along with more specific
    overloads. Unfortunately, it's too late now.)

    You'll want to call it like this instead:

    fPipeOut.Write( (char) 11);

    or use a char[], but not a byte[].

    Beware that this method simply *does not work* for bytes 127, because
    these will end up encoded in UTF-8. If you want to write arbitrary bytes,
    you shouldn't use StreamWriter but instead operate directly on the Stream.
    You can convert (portions of) byte arrays with the Encoder classes. The same
    caveat applies to using StreamReader.

    --
    J.

    Comment

    • stumorgan@gmail.com

      #3
      Re: USB communications using StreamReader and StreamWriter

      Thanks, that worked perfectly. Now I'm having some issues with the
      StreamReader. When I send a command to the device to stop streaming,
      the StreamReader hangs. I've tried ReadLine, ReadToEnd,
      DiscardBuffered Data. They all hang when the device stops streaming.
      Anything I'm doing wrong? I would think if there is nothing to read
      then ReadLine would just return a blank string... I suppose the
      device could be closing its outbound USB port thus severing the
      connection, would that cause the StreamReader to hang? I was hoping
      it might more gracefully wait for the stream to open again.

      Comment

      • Peter Duniho

        #4
        Re: USB communications using StreamReader and StreamWriter

        On Wed, 16 Jul 2008 09:53:29 -0700, <stumorgan@gmai l.comwrote:
        Thanks, that worked perfectly. Now I'm having some issues with the
        StreamReader. When I send a command to the device to stop streaming,
        the StreamReader hangs. I've tried ReadLine, ReadToEnd,
        DiscardBuffered Data. They all hang when the device stops streaming.
        Anything I'm doing wrong?
        That depends. But it sounds like your USB source doesn't provide an "end
        of stream" indication when it's done. That's not actually all that
        surprising to me. I don't know much about USB i/o, but assuming it's like
        regular serial interfaces, it just doesn't have the idea of an "end of
        stream".

        DiscardBuffered Data() is irrelevant (has nothing at all to do with the
        question). ReadToEnd() won't return until the stream ends. Even
        ReadLine() won't return until a full line has been received. If no more
        data is sent, there's no way for a full line to be received. So either of
        those read methods will simply block indefinitely.

        Ideally, the _data_ in the stream would include some kind of termination
        indication. If so, then you simply need to watch for that data, and close
        the stream yourself when you see it.

        Otherwise, you are probably going to have to make some assumptions about
        the definition of "end of stream". Most likely in the form of a timeout.
        You can use a timer, restarting it each time you successfully read some
        data. Once the timer finally expires (i.e. you have not received any data
        after the specified amount of time), you can then assume that the device
        is done sending and close the stream at that point.

        Again, I'm unfamiliar with USB i/o, but I suspect that if you've got one
        thread blocked on a call to ReadLine() or similar, closing the stream will
        cause that call to complete with an exception, allowing you to catch the
        exception and correctly detect the pseudo-"end of stream" you've created.

        Finally, I'd like to suggest that you seriously consider taking Jeroen's
        advice to switch to using a regular Stream. My understanding is that your
        stream is not just character input, but rather also includes binary data.
        If this is the case, I think you will have more reliable, more
        maintainable code by handling the character data yourself with a regular
        Stream than by trying to shoe-horn binary data into the character-based
        StreamWriter/StreamReader classes. (Though, the "end of stream" issue as
        described above will be basically the same).

        Pete

        Comment

        Working...