Skip to content

Commit f18eb75

Browse files
Merge pull request firmata#364 from zfields/bug
codec bug
2 parents 260f127 + 8f83459 commit f18eb75

File tree

6 files changed

+43
-37
lines changed

6 files changed

+43
-37
lines changed

Firmata.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ systemCallbackFunction FirmataClass::currentSystemResetCallback = (systemCallbac
5050
*/
5151
void FirmataClass::sendValueAsTwo7bitBytes(int value)
5252
{
53-
marshaller.transformByteStreamToMessageBytes(sizeof(value), reinterpret_cast<uint8_t *>(&value), sizeof(value));
53+
marshaller.encodeByteStream(sizeof(value), reinterpret_cast<uint8_t *>(&value), sizeof(value));
5454
}
5555

5656
/**

Firmata.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ class FirmataClass
128128

129129
/* private methods ------------------------------ */
130130
void strobeBlinkPin(byte pin, int count, int onInterval, int offInterval);
131-
friend void FirmataMarshaller::transformByteStreamToMessageBytes (size_t bytec, uint8_t * bytev, size_t max_bytes = 0) const;
131+
friend void FirmataMarshaller::encodeByteStream (size_t bytec, uint8_t * bytev, size_t max_bytes = 0) const;
132132

133133
/* callback functions */
134134
static callbackFunction currentAnalogCallback;

FirmataMarshaller.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ const
7979
FirmataStream->write(START_SYSEX);
8080
FirmataStream->write(EXTENDED_ANALOG);
8181
FirmataStream->write(pin);
82-
transformByteStreamToMessageBytes(bytec, bytev, bytec);
82+
encodeByteStream(bytec, bytev, bytec);
8383
FirmataStream->write(END_SYSEX);
8484
}
8585

@@ -89,7 +89,7 @@ const
8989
* @param bytev A pointer to the array of data bytes to send in the message.
9090
* @param max_bytes Force message to be n bytes, regardless of data bits.
9191
*/
92-
void FirmataMarshaller::transformByteStreamToMessageBytes (size_t bytec, uint8_t * bytev, size_t max_bytes)
92+
void FirmataMarshaller::encodeByteStream (size_t bytec, uint8_t * bytev, size_t max_bytes)
9393
const
9494
{
9595
static const size_t transmit_bits = 7;
@@ -248,7 +248,7 @@ const
248248
if ( (Stream *)NULL == FirmataStream ) { return; }
249249
if ( (0xF >= pin) && (0x3FFF >= value) ) {
250250
FirmataStream->write(ANALOG_MESSAGE|pin);
251-
transformByteStreamToMessageBytes(sizeof(value), reinterpret_cast<uint8_t *>(&value), sizeof(value));
251+
encodeByteStream(sizeof(value), reinterpret_cast<uint8_t *>(&value), sizeof(value));
252252
} else {
253253
sendExtendedAnalog(pin, sizeof(value), reinterpret_cast<uint8_t *>(&value));
254254
}
@@ -306,7 +306,7 @@ const
306306
FirmataStream->write(DIGITAL_MESSAGE | (portNumber & 0xF));
307307
// Tx bits 0-6 (protocol v1 and higher)
308308
// Tx bits 7-13 (bit 7 only for protocol v2 and higher)
309-
transformByteStreamToMessageBytes(sizeof(portData), reinterpret_cast<uint8_t *>(&portData), sizeof(portData));
309+
encodeByteStream(sizeof(portData), reinterpret_cast<uint8_t *>(&portData), sizeof(portData));
310310
}
311311

312312
/**
@@ -326,7 +326,7 @@ const
326326
FirmataStream->write(major);
327327
FirmataStream->write(minor);
328328
for (i = 0; i < bytec; ++i) {
329-
transformByteStreamToMessageBytes(sizeof(bytev[i]), reinterpret_cast<uint8_t *>(&bytev[i]), sizeof(bytev[i]));
329+
encodeByteStream(sizeof(bytev[i]), reinterpret_cast<uint8_t *>(&bytev[i]));
330330
}
331331
FirmataStream->write(END_SYSEX);
332332
}
@@ -393,7 +393,7 @@ const
393393
FirmataStream->write(START_SYSEX);
394394
FirmataStream->write(command);
395395
for (i = 0; i < bytec; ++i) {
396-
transformByteStreamToMessageBytes(sizeof(bytev[i]), reinterpret_cast<uint8_t *>(&bytev[i]), sizeof(bytev[i]));
396+
encodeByteStream(sizeof(bytev[i]), reinterpret_cast<uint8_t *>(&bytev[i]));
397397
}
398398
FirmataStream->write(END_SYSEX);
399399
}

FirmataMarshaller.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ class FirmataMarshaller
6464
void reportAnalog(uint8_t pin, bool stream_enable) const;
6565
void reportDigitalPort(uint8_t portNumber, bool stream_enable) const;
6666
void sendExtendedAnalog(uint8_t pin, size_t bytec, uint8_t * bytev) const;
67-
void transformByteStreamToMessageBytes (size_t bytec, uint8_t * bytev, size_t max_bytes = 0) const;
67+
void encodeByteStream (size_t bytec, uint8_t * bytev, size_t max_bytes = 0) const;
6868

6969
Stream * FirmataStream;
7070
};

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)