Skip to content

Commit 854b877

Browse files
Merge pull request #313 from zfields/parser
Split parsing functionality into new class
2 parents 39c8e70 + 8359209 commit 854b877

File tree

4 files changed

+494
-246
lines changed

4 files changed

+494
-246
lines changed

Firmata.cpp

Lines changed: 29 additions & 180 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,20 @@ extern "C" {
2323
#include <stdlib.h>
2424
}
2525

26+
//******************************************************************************
27+
//* Static Members
28+
//******************************************************************************
29+
// make one instance for the user to use
30+
FirmataClass Firmata;
31+
32+
void printVersion (void) {
33+
Firmata.printVersion();
34+
}
35+
36+
void printFirmwareVersion (void) {
37+
Firmata.printFirmwareVersion();
38+
}
39+
2640
//******************************************************************************
2741
//* Support Functions
2842
//******************************************************************************
@@ -66,7 +80,8 @@ FirmataClass::FirmataClass()
6680
firmwareVersionCount = 0;
6781
firmwareVersionVector = 0;
6882
blinkVersionDisabled = false;
69-
systemReset();
83+
parser.attach(REPORT_FIRMWARE, ::printFirmwareVersion);
84+
parser.attach(REPORT_VERSION, ::printVersion);
7085
}
7186

7287
//******************************************************************************
@@ -228,54 +243,14 @@ int FirmataClass::available(void)
228243
return FirmataStream->available();
229244
}
230245

231-
/**
232-
* Process incoming sysex messages. Handles REPORT_FIRMWARE and STRING_DATA internally.
233-
* Calls callback function for STRING_DATA and all other sysex messages.
234-
* @private
235-
*/
236-
void FirmataClass::processSysexMessage(void)
237-
{
238-
switch (storedInputData[0]) { //first byte in buffer is command
239-
case REPORT_FIRMWARE:
240-
printFirmwareVersion();
241-
break;
242-
case STRING_DATA:
243-
if (currentStringCallback) {
244-
byte bufferLength = (sysexBytesRead - 1) / 2;
245-
byte i = 1;
246-
byte j = 0;
247-
while (j < bufferLength) {
248-
// The string length will only be at most half the size of the
249-
// stored input buffer so we can decode the string within the buffer.
250-
storedInputData[j] = storedInputData[i];
251-
i++;
252-
storedInputData[j] += (storedInputData[i] << 7);
253-
i++;
254-
j++;
255-
}
256-
// Make sure string is null terminated. This may be the case for data
257-
// coming from client libraries in languages that don't null terminate
258-
// strings.
259-
if (storedInputData[j - 1] != '\0') {
260-
storedInputData[j] = '\0';
261-
}
262-
(*currentStringCallback)((char *)&storedInputData[0]);
263-
}
264-
break;
265-
default:
266-
if (currentSysexCallback)
267-
(*currentSysexCallback)(storedInputData[0], sysexBytesRead - 1, storedInputData + 1);
268-
}
269-
}
270-
271246
/**
272247
* Read a single int from the input stream. If the value is not = -1, pass it on to parse(byte)
273248
*/
274249
void FirmataClass::processInput(void)
275250
{
276251
int inputData = FirmataStream->read(); // this is 'int' to handle -1 when no data
277252
if (inputData != -1) {
278-
parse(inputData);
253+
parser.parse(inputData);
279254
}
280255
}
281256

@@ -285,99 +260,15 @@ void FirmataClass::processInput(void)
285260
*/
286261
void FirmataClass::parse(byte inputData)
287262
{
288-
int command;
289-
290-
if (parsingSysex) {
291-
if (inputData == END_SYSEX) {
292-
//stop sysex byte
293-
parsingSysex = false;
294-
//fire off handler function
295-
processSysexMessage();
296-
} else {
297-
//normal data byte - add to buffer
298-
storedInputData[sysexBytesRead] = inputData;
299-
sysexBytesRead++;
300-
}
301-
} else if ( (waitForData > 0) && (inputData < 128) ) {
302-
waitForData--;
303-
storedInputData[waitForData] = inputData;
304-
if ( (waitForData == 0) && executeMultiByteCommand ) { // got the whole message
305-
switch (executeMultiByteCommand) {
306-
case ANALOG_MESSAGE:
307-
if (currentAnalogCallback) {
308-
(*currentAnalogCallback)(multiByteChannel,
309-
(storedInputData[0] << 7)
310-
+ storedInputData[1]);
311-
}
312-
break;
313-
case DIGITAL_MESSAGE:
314-
if (currentDigitalCallback) {
315-
(*currentDigitalCallback)(multiByteChannel,
316-
(storedInputData[0] << 7)
317-
+ storedInputData[1]);
318-
}
319-
break;
320-
case SET_PIN_MODE:
321-
if (currentPinModeCallback)
322-
(*currentPinModeCallback)(storedInputData[1], storedInputData[0]);
323-
break;
324-
case SET_DIGITAL_PIN_VALUE:
325-
if (currentPinValueCallback)
326-
(*currentPinValueCallback)(storedInputData[1], storedInputData[0]);
327-
break;
328-
case REPORT_ANALOG:
329-
if (currentReportAnalogCallback)
330-
(*currentReportAnalogCallback)(multiByteChannel, storedInputData[0]);
331-
break;
332-
case REPORT_DIGITAL:
333-
if (currentReportDigitalCallback)
334-
(*currentReportDigitalCallback)(multiByteChannel, storedInputData[0]);
335-
break;
336-
}
337-
executeMultiByteCommand = 0;
338-
}
339-
} else {
340-
// remove channel info from command byte if less than 0xF0
341-
if (inputData < 0xF0) {
342-
command = inputData & 0xF0;
343-
multiByteChannel = inputData & 0x0F;
344-
} else {
345-
command = inputData;
346-
// commands in the 0xF* range don't use channel data
347-
}
348-
switch (command) {
349-
case ANALOG_MESSAGE:
350-
case DIGITAL_MESSAGE:
351-
case SET_PIN_MODE:
352-
case SET_DIGITAL_PIN_VALUE:
353-
waitForData = 2; // two data bytes needed
354-
executeMultiByteCommand = command;
355-
break;
356-
case REPORT_ANALOG:
357-
case REPORT_DIGITAL:
358-
waitForData = 1; // one data byte needed
359-
executeMultiByteCommand = command;
360-
break;
361-
case START_SYSEX:
362-
parsingSysex = true;
363-
sysexBytesRead = 0;
364-
break;
365-
case SYSTEM_RESET:
366-
systemReset();
367-
break;
368-
case REPORT_VERSION:
369-
Firmata.printVersion();
370-
break;
371-
}
372-
}
263+
parser.parse(inputData);
373264
}
374265

375266
/**
376267
* @return Returns true if the parser is actively parsing data.
377268
*/
378269
boolean FirmataClass::isParsingMessage(void)
379270
{
380-
return (waitForData > 0 || parsingSysex);
271+
return parser.isParsingMessage();
381272
}
382273

383274
//------------------------------------------------------------------------------
@@ -495,66 +386,49 @@ void FirmataClass::write(byte c)
495386
* @param command The ID of the command to attach a callback function to.
496387
* @param newFunction A reference to the callback function to attach.
497388
*/
498-
void FirmataClass::attach(byte command, callbackFunction newFunction)
389+
void FirmataClass::attach(uint8_t command, callbackFunction newFunction)
499390
{
500-
switch (command) {
501-
case ANALOG_MESSAGE: currentAnalogCallback = newFunction; break;
502-
case DIGITAL_MESSAGE: currentDigitalCallback = newFunction; break;
503-
case REPORT_ANALOG: currentReportAnalogCallback = newFunction; break;
504-
case REPORT_DIGITAL: currentReportDigitalCallback = newFunction; break;
505-
case SET_PIN_MODE: currentPinModeCallback = newFunction; break;
506-
case SET_DIGITAL_PIN_VALUE: currentPinValueCallback = newFunction; break;
507-
}
391+
parser.attach(command, (callbackFunction)newFunction);
508392
}
509393

510394
/**
511395
* Attach a callback function for the SYSTEM_RESET command.
512396
* @param command Must be set to SYSTEM_RESET or it will be ignored.
513397
* @param newFunction A reference to the system reset callback function to attach.
514398
*/
515-
void FirmataClass::attach(byte command, systemResetCallbackFunction newFunction)
399+
void FirmataClass::attach(uint8_t command, systemCallbackFunction newFunction)
516400
{
517-
switch (command) {
518-
case SYSTEM_RESET: currentSystemResetCallback = newFunction; break;
519-
}
401+
parser.attach(command, (systemCallbackFunction)newFunction);
520402
}
521403

522404
/**
523405
* Attach a callback function for the STRING_DATA command.
524406
* @param command Must be set to STRING_DATA or it will be ignored.
525407
* @param newFunction A reference to the string callback function to attach.
526408
*/
527-
void FirmataClass::attach(byte command, stringCallbackFunction newFunction)
409+
void FirmataClass::attach(uint8_t command, stringCallbackFunction newFunction)
528410
{
529-
switch (command) {
530-
case STRING_DATA: currentStringCallback = newFunction; break;
531-
}
411+
parser.attach(command, (stringCallbackFunction)newFunction);
532412
}
533413

534414
/**
535415
* Attach a generic sysex callback function to sysex command.
536416
* @param command The ID of the command to attach a callback function to.
537417
* @param newFunction A reference to the sysex callback function to attach.
538418
*/
539-
void FirmataClass::attach(byte command, sysexCallbackFunction newFunction)
419+
void FirmataClass::attach(uint8_t command, sysexCallbackFunction newFunction)
540420
{
541-
currentSysexCallback = newFunction;
421+
parser.attach(command, (sysexCallbackFunction)newFunction);
542422
}
543423

544424
/**
545425
* Detach a callback function for a specified command (such as SYSTEM_RESET, STRING_DATA,
546426
* ANALOG_MESSAGE, DIGITAL_MESSAGE, etc).
547427
* @param command The ID of the command to detatch the callback function from.
548428
*/
549-
void FirmataClass::detach(byte command)
429+
void FirmataClass::detach(uint8_t command)
550430
{
551-
switch (command) {
552-
case SYSTEM_RESET: currentSystemResetCallback = NULL; break;
553-
case STRING_DATA: currentStringCallback = NULL; break;
554-
case START_SYSEX: currentSysexCallback = NULL; break;
555-
default:
556-
attach(command, (callbackFunction)NULL);
557-
}
431+
parser.detach(command);
558432
}
559433

560434
/**
@@ -623,29 +497,6 @@ void FirmataClass::setPinState(byte pin, int state)
623497
//* Private Methods
624498
//******************************************************************************
625499

626-
/**
627-
* Resets the system state upon a SYSTEM_RESET message from the host software.
628-
* @private
629-
*/
630-
void FirmataClass::systemReset(void)
631-
{
632-
byte i;
633-
634-
waitForData = 0; // this flag says the next serial input will be data
635-
executeMultiByteCommand = 0; // execute this after getting multi-byte data
636-
multiByteChannel = 0; // channel data for multiByteCommands
637-
638-
for (i = 0; i < MAX_DATA_BYTES; i++) {
639-
storedInputData[i] = 0;
640-
}
641-
642-
parsingSysex = false;
643-
sysexBytesRead = 0;
644-
645-
if (currentSystemResetCallback)
646-
(*currentSystemResetCallback)();
647-
}
648-
649500
/**
650501
* Flashing the pin for the version number
651502
* @private
@@ -665,5 +516,3 @@ void FirmataClass::strobeBlinkPin(byte pin, int count, int onInterval, int offIn
665516
}
666517
}
667518

668-
// make one instance for the user to use
669-
FirmataClass Firmata;

0 commit comments

Comments
 (0)