Skip to content

Commit eb5e7cd

Browse files
committed
Improve decoding algorithm
1 parent 260f127 commit eb5e7cd

File tree

2 files changed

+34
-28
lines changed

2 files changed

+34
-28
lines changed

FirmataParser.cpp

Lines changed: 33 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,25 @@ bool FirmataParser::bufferDataAtPosition(const uint8_t data, const size_t pos)
400400
return bufferOverflow;
401401
}
402402

403+
/**
404+
* Transform 7-bit firmata message into 8-bit stream
405+
* @param bytec The encoded data byte length of the message (max: 16383).
406+
* @param bytev A pointer to the encoded array of data bytes.
407+
* @return The length of the decoded data.
408+
* @note The conversion will be done in place on the provided buffer.
409+
* @private
410+
*/
411+
size_t FirmataParser::decodeByteStream(size_t bytec, uint8_t * bytev) {
412+
size_t decoded_bytes, i;
413+
414+
for ( i = 0, decoded_bytes = 0 ; i < bytec ; ++decoded_bytes, ++i ) {
415+
bytev[decoded_bytes] = bytev[i];
416+
bytev[decoded_bytes] |= (uint8_t)(bytev[++i] << 7);
417+
}
418+
419+
return decoded_bytes;
420+
}
421+
403422
/**
404423
* Process incoming sysex messages. Handles REPORT_FIRMWARE and STRING_DATA internally.
405424
* Calls callback function for STRING_DATA and all other sysex messages.
@@ -410,39 +429,25 @@ void FirmataParser::processSysexMessage(void)
410429
switch (dataBuffer[0]) { //first byte in buffer is command
411430
case REPORT_FIRMWARE:
412431
if (currentReportFirmwareCallback) {
413-
size_t sv_major = dataBuffer[1], sv_minor = dataBuffer[2];
414-
size_t i = 0, j = 3;
415-
while (j < sysexBytesRead) {
416-
// The string length will only be at most half the size of the
417-
// stored input buffer so we can decode the string within the buffer.
418-
bufferDataAtPosition(dataBuffer[j], i);
419-
++i;
420-
++j;
432+
const size_t major_version_offset = 1;
433+
const size_t minor_version_offset = 2;
434+
const size_t string_offset = 3;
435+
// Test for malformed REPORT_FIRMWARE message (used to query firmware prior to Firmata v3.0.0)
436+
if ( 3 > sysexBytesRead ) {
437+
(*currentReportFirmwareCallback)(currentReportFirmwareCallbackContext, 0, 0, (const char *)NULL);
438+
} else {
439+
const size_t end_of_string = (string_offset + decodeByteStream((sysexBytesRead - string_offset), &dataBuffer[string_offset]));
440+
bufferDataAtPosition('\0', end_of_string); // NULL terminate the string
441+
(*currentReportFirmwareCallback)(currentReportFirmwareCallbackContext, (size_t)dataBuffer[major_version_offset], (size_t)dataBuffer[minor_version_offset], (const char *)&dataBuffer[string_offset]);
421442
}
422-
bufferDataAtPosition('\0', i); // Terminate the string
423-
(*currentReportFirmwareCallback)(currentReportFirmwareCallbackContext, sv_major, sv_minor, (const char *)&dataBuffer[0]);
424443
}
425444
break;
426445
case STRING_DATA:
427446
if (currentStringCallback) {
428-
size_t bufferLength = (sysexBytesRead - 1) / 2;
429-
size_t i = 1, j = 0;
430-
while (j < bufferLength) {
431-
// The string length will only be at most half the size of the
432-
// stored input buffer so we can decode the string within the buffer.
433-
bufferDataAtPosition(dataBuffer[i], j);
434-
++i;
435-
bufferDataAtPosition((dataBuffer[j] + (dataBuffer[i] << 7)), j);
436-
++i;
437-
++j;
438-
}
439-
// Make sure string is null terminated. This may be the case for data
440-
// coming from client libraries in languages that don't null terminate
441-
// strings.
442-
if (dataBuffer[j - 1] != '\0') {
443-
bufferDataAtPosition('\0', j);
444-
}
445-
(*currentStringCallback)(currentStringCallbackContext, (const char *)&dataBuffer[0]);
447+
const size_t string_offset = 1;
448+
const size_t end_of_string = (string_offset + decodeByteStream((sysexBytesRead - string_offset), &dataBuffer[string_offset]));
449+
bufferDataAtPosition('\0', end_of_string); // NULL terminate the string
450+
(*currentStringCallback)(currentStringCallbackContext, (const char *)&dataBuffer[string_offset]);
446451
}
447452
break;
448453
default:

FirmataParser.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ class FirmataParser
9595

9696
/* private methods ------------------------------ */
9797
bool bufferDataAtPosition(const uint8_t data, const size_t pos);
98+
size_t decodeByteStream(size_t bytec, uint8_t * bytev);
9899
void processSysexMessage(void);
99100
void systemReset(void);
100101
};

0 commit comments

Comments
 (0)