Search code examples
javausbasciiinputstreamcorruption

Java reading from continuous USB stream showing corruption


I've got an application which records data from a USB device to a local file, however the data being received is corrupted. The data is encoded as ASCII and has 4 columns of information separated by spaces. There are 2 sensors attached to the device, with the first column indicating the sensor. The data is sent at a frequency of 60Hz, with both sensor data being transmitted at the same time. The ideal output should be in the form

01 value1  value2  value3
02 value1  value2  value3
01 value1  value2  value3 

etc...

However the first 2 lines are correct, but subsequent alternate lines have a lot of blank spaces (in Windows, in gEdit in Ubuntu it's shown as \00s and Vim shows it as sequences of ^@). Here's how it looks in gEdit (note there are sensor values after all the \00s)

01     0.109    5.933    1.803 
02     5.550    6.027    1.714 
\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00    \00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\0001     0.109    5.933    1.803 
02     5.553    6.027    1.713 
\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00    \00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\0001     0.108    5.933    1.803 

I'm testing recording for 5 seconds and by the end the written lines have less data and more \00s.

The data is sent as ASCII streams with carriage return followed by line feed separating sensor values. The reading is is done in the run() method of a thread class. The constructor instantiates a PrintWriter to the destination output file, saved as variable writer. The run method is shown below. I imagine the problem is in the handling of the end of messages but can't get it working.

    public void run() {
        long startTime = System.currentTimeMillis();
        error = true;
        have1 = false;
        int data;

        try {
            // Send output commands to device
            out = new FileOutputStream(portName);
            out.write(0x0d);
            out.close();

            // Open stream to read from device
            FileReader fr = new FileReader(portName);
            BufferedReader br = new BufferedReader(fr);

            while(System.currentTimeMillis() < startTime+ltime) {

                data = br.read();

                if (data == -1)
                    break;

                else if (data == 0x0d) {
                    if (br.read() == 0x0a) {
                        //System.out.println(line);
                        writer.println(line+"     "+System.currentTimeMillis());
                        line = "";
                    }
                }

                else { // Have data
                    line += (char) data;
                }       

            }

          br.close();   

          // Command to stop recording
          out = new FileOutputStream(portName);
          out.write('x');
          out.close();

          writer.flush();
          writer.close();
        }
        catch (IOException e) { // generated by the device
            e.printStackTrace();
            readError = true;
            System.out.println("RECORDING ERROR");
        }  
    }

Solution

  • I think it may be that your USB device and your program are not sync, and I think of this causes:

    • No initial sync, you're assuming you are in sync.
    • I/O operations take much time (relative to miliseconds).

    Solutions:

    • Do not write any file until you've ended the process, this will save you time, and as I see, time is an issue.
    • Parse the data to completely delete all corrupted data, or assume it is the arithmetic mean between the last and next valid data (all of this should run after the data gathering).

    I don't know how you could sync the device, try making it wait until some data is recived.