1

I'm getting some weird results when converting an array buffer to a string then displaying the output in a div.

I'm getting some GPS data from the USB port in a chrome packaged app. It converts the array buffer received from the port into a string and outputs. The functions are:

var onReceiveCallback = function(info) {    
    if (info.connectionId == connectionId && info.data) {
        $(".output").append(ab2str(info.data));
    }   
};

/* Interprets an ArrayBuffer as UTF-8 encoded string data. */
var ab2str = function(buf) {
    var bufView = new Uint8Array(buf);
    var encodedString = String.fromCharCode.apply(null, bufView);
    return decodeURIComponent(escape(encodedString));
};

I have a start and stop button to obviously start and stop the reading of data from the gps device. When I start it the first time it works and outputs as expected, something like:

$GPGGA,214948.209,,,,,0,0,,,M,,M,,*41 $GPGSA,A,1,,,,,,,,,,,,,,,*1E $GPGSV,1,1,01,07,,,33*7F $GPRMC,214948.209,V,,,,,0.00,0.00,270814,,,N*4C $GPGGA,214949.209,,,,,0,0,,,M,,M,,*40 $GPGSA,A,1,,,,,,,,,,,,,,,*1E $GPGSV,1,1,01,07,,,34*78 $GPRMC,214949.209,V,,,,,0.00,0.00,270814,,,N*4D

but then when I stop it, and restart it, although I clear the output div, the output data seems to be mixing in with the previous result. Like:

$$GPGPGGGGAA,,221155115544..202099,,,,,,,,,0,0,0,0,,,,,,MM,,,,MM,,,,**4455 $$GGPPGGSSAA,,AA,,11,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,**11EE $$GGPGPGSSVV,,11,,11,,0022,,0077,,,,,,3344,1,177,,,,,,3311**77FF $$GGPPRRMMCC,,212155115544..220099,,VV,,,,,,,,,,00..0000,,00..0000,,227700881144,,,,,,NN*4*488 $$GPGGPGGGAA,,221155115555..220099,,,,,,,,,,00,,00,,,,,,MM,,,,MM,,,,**4444 $$GGPPGGSSAA,,AA,,11,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,**11EE $G$GPPGGSSVV,,11,,11,,0022,,0077,,,,,,331,1,1177,,,,,,2255**77FF $$GGPPRRMMCC,2,21155115555..220099,,VV,,,,,,,,,,00..0000,,00..0000,,227700881144,,,,,,N*N*4499

Its like a buffer or variable isnt being emptied, or something else crazy that I cant figure out. Any pointers appreciated.

edit:

this is the 'start' function which clears the output div and reconnects:

// when the start button is clicked
$( "#start" ).click(function() {
    if ( deviceId == 0 ) {
        console.log("Please select a device");
        return;
    }
    else {
        $(".output").empty();
        serial.connect(deviceId, {bitrate: 9600}, onConnect);
    }
});
6
  • 1
    See what's in info.data when you restart. It may be that the data is getting appended to there. If so, the problem is related to the source of that data, not to the conversion of the array buffer. Commented Aug 27, 2014 at 23:46
  • You said you are clearing the output div. Yet the code you included in your question does not clear divs. Given that your question is related to the fact that the div isn't being cleared, it might make sense for your question to include the code that isn't working. Commented Aug 29, 2014 at 1:18
  • updated question to show this Commented Aug 29, 2014 at 13:19
  • @MarcRochkind I can only check the info.data in the onReceive function and I need to convert it from an array buffer to see it as a string, so I'm only seeing the end result each time, if that makes sense. Commented Aug 29, 2014 at 13:22
  • Perhaps you can dump out the individual bytes in the array buffer with console.log to see what they are. All you need to know is whether the buffer is being cleared. It make take some detective work to interpret the bytes, but this should be doable. Commented Aug 29, 2014 at 14:18

1 Answer 1

1

I have found this technique unreliable in my own code, although I don't remember if the problem was similar to one you report:

var ab2str = function(buf) { // not reliable
    var bufView = new Uint8Array(buf);
    var encodedString = String.fromCharCode.apply(null, bufView);
    return decodeURIComponent(escape(encodedString));
};

So, I have done it this way, with code taken from one of the Google Chrome App examples (tcpserver):

function ab2str(buf, callback) {
    var bb = new Blob([new Uint8Array(buf)]);
    var f = new FileReader();
    f.onload = function(e) {
        callback(e.target.result);
    };
    f.readAsText(bb);
}

Note that this version isn't an exact replacement, since it's asynchronous.

Now, starting with Chrome Version 38 (now in beta), you can do it this way:

function ab2str(buf) {
    var dataView = new DataView(buf);
    var decoder = new TextDecoder('utf-8');
    return decoder.decode(dataView);
}

As I always run the beta and am preparing examples for a forthcoming book, I am now doing it the newest way. Give that a try and see if your problem goes away. If not, my suggestion to examine info.data is still a good one, I think.

UPDATE: I've just checked out this reverse function, which you may also find handy at some point:

function str2ab(buf) {
    var encoder = new TextEncoder('utf-8');
    return encoder.encode(buf).buffer;
}
Sign up to request clarification or add additional context in comments.

5 Comments

Marc, awesome, thanks for the code. Will check these out tonight and have a play around with it. Its bound to be something simple, but I like the structure of your code better as it is. cheers/
OK... please post the results here. Also, see the update I just added.
Marc, found your code really interesting and i've downloaded chrome beta to play around with that also. turns out it was something stupid my end, as with most these things. i was "calling" the onreceive listener function when successfully connecting, not realising I should have set up the listener (asynchronously) and then connected to the device. Problem seemingly solved.
So I was setting up multiple listeners each time I restarted I was adding another listener. Very much a "d'oh" moment
Ouch! I did that once. ;-)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.