Skip to content

Core #345

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 22, 2017
Merged

Core #345

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 73 additions & 16 deletions Firmata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,16 @@ extern "C" {
// make one instance for the user to use
FirmataClass Firmata;

void printVersion (void) {
Firmata.printVersion();
}

void printFirmwareVersion (void) {
Firmata.printFirmwareVersion();
}
/* callback functions */
callbackFunction FirmataClass::currentAnalogCallback = (callbackFunction)NULL;
callbackFunction FirmataClass::currentDigitalCallback = (callbackFunction)NULL;
callbackFunction FirmataClass::currentPinModeCallback = (callbackFunction)NULL;
callbackFunction FirmataClass::currentPinValueCallback = (callbackFunction)NULL;
callbackFunction FirmataClass::currentReportAnalogCallback = (callbackFunction)NULL;
callbackFunction FirmataClass::currentReportDigitalCallback = (callbackFunction)NULL;
stringCallbackFunction FirmataClass::currentStringCallback = (stringCallbackFunction)NULL;
sysexCallbackFunction FirmataClass::currentSysexCallback = (sysexCallbackFunction)NULL;
systemCallbackFunction FirmataClass::currentSystemResetCallback = (systemCallbackFunction)NULL;

//******************************************************************************
//* Support Functions
Expand Down Expand Up @@ -81,8 +84,19 @@ FirmataClass::FirmataClass()
firmwareVersionCount = 0;
firmwareVersionVector = 0;
blinkVersionDisabled = false;
parser.attach(REPORT_FIRMWARE, ::printFirmwareVersion);
parser.attach(REPORT_VERSION, ::printVersion);

// Establish callback translation to parser callbacks
parser.attach(ANALOG_MESSAGE, (FirmataParser::callbackFunction)staticAnalogCallback, (void *)NULL);
parser.attach(DIGITAL_MESSAGE, (FirmataParser::callbackFunction)staticDigitalCallback, (void *)NULL);
parser.attach(REPORT_ANALOG, (FirmataParser::callbackFunction)staticReportAnalogCallback, (void *)NULL);
parser.attach(REPORT_DIGITAL, (FirmataParser::callbackFunction)staticReportDigitalCallback, (void *)NULL);
parser.attach(SET_PIN_MODE, (FirmataParser::callbackFunction)staticPinModeCallback, (void *)NULL);
parser.attach(SET_DIGITAL_PIN_VALUE, (FirmataParser::callbackFunction)staticPinValueCallback, (void *)NULL);
parser.attach(STRING_DATA, (FirmataParser::stringCallbackFunction)staticStringCallback, (void *)NULL);
parser.attach(START_SYSEX, (FirmataParser::sysexCallbackFunction)staticSysexCallback, (void *)NULL);
parser.attach(REPORT_FIRMWARE, (FirmataParser::systemCallbackFunction)staticReportFirmwareCallback, this);
parser.attach(REPORT_VERSION, (FirmataParser::systemCallbackFunction)staticReportVersionCallback, this);
parser.attach(SYSTEM_RESET, (FirmataParser::systemCallbackFunction)staticSystemResetCallback, (void *)NULL);
}

//******************************************************************************
Expand Down Expand Up @@ -296,6 +310,8 @@ void FirmataClass::sendAnalog(byte pin, int value)
*/
void FirmataClass::sendDigital(byte pin, int value)
{
(void)pin;
(void)value;
/* TODO add single pin digital messages to the protocol, this needs to
* track the last digital data sent so that it can be sure to change just
* one bit in the packet. This is complicated by the fact that the
Expand Down Expand Up @@ -376,9 +392,28 @@ void FirmataClass::write(byte c)
* @param command The ID of the command to attach a callback function to.
* @param newFunction A reference to the callback function to attach.
*/
void FirmataClass::attach(uint8_t command, callbackFunction newFunction)
{
parser.attach(command, (callbackFunction)newFunction);
void FirmataClass::attach(uint8_t command, ::callbackFunction newFunction)
{
switch (command) {
case ANALOG_MESSAGE:
currentAnalogCallback = newFunction;
break;
case DIGITAL_MESSAGE:
currentDigitalCallback = newFunction;
break;
case REPORT_ANALOG:
currentReportAnalogCallback = newFunction;
break;
case REPORT_DIGITAL:
currentReportDigitalCallback = newFunction;
break;
case SET_PIN_MODE:
currentPinModeCallback = newFunction;
break;
case SET_DIGITAL_PIN_VALUE:
currentPinValueCallback = newFunction;
break;
}
}

/**
Expand All @@ -388,7 +423,11 @@ void FirmataClass::attach(uint8_t command, callbackFunction newFunction)
*/
void FirmataClass::attach(uint8_t command, systemCallbackFunction newFunction)
{
parser.attach(command, (systemCallbackFunction)newFunction);
switch (command) {
case SYSTEM_RESET:
currentSystemResetCallback = newFunction;
break;
}
}

/**
Expand All @@ -398,7 +437,11 @@ void FirmataClass::attach(uint8_t command, systemCallbackFunction newFunction)
*/
void FirmataClass::attach(uint8_t command, stringCallbackFunction newFunction)
{
parser.attach(command, (stringCallbackFunction)newFunction);
switch (command) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this need to be a switch statement? Would an if statement be more performant (I'm not sure if an if or switch statement is better performance wise when there is only a single condition)? I don't foresee having other types of string callback functions.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't imagine a more performant branch than an if, but I was assuming they would distill down into the same assembly; I will check into it and get back. I just wanted to keep the same semantics, but I wouldn't sacrifice performance for it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just confirmed the binary is the same exact size, when using the single case switch or an if statement.

case STRING_DATA:
currentStringCallback = newFunction;
break;
}
}

/**
Expand All @@ -408,7 +451,8 @@ void FirmataClass::attach(uint8_t command, stringCallbackFunction newFunction)
*/
void FirmataClass::attach(uint8_t command, sysexCallbackFunction newFunction)
{
parser.attach(command, (sysexCallbackFunction)newFunction);
(void)command;
currentSysexCallback = newFunction;
}

/**
Expand All @@ -418,7 +462,20 @@ void FirmataClass::attach(uint8_t command, sysexCallbackFunction newFunction)
*/
void FirmataClass::detach(uint8_t command)
{
parser.detach(command);
switch (command) {
case SYSTEM_RESET:
attach(command, (systemCallbackFunction)NULL);
break;
case STRING_DATA:
attach(command, (stringCallbackFunction)NULL);
break;
case START_SYSEX:
attach(command, (sysexCallbackFunction)NULL);
break;
default:
attach(command, (callbackFunction)NULL);
break;
}
}

/**
Expand Down
49 changes: 45 additions & 4 deletions Firmata.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,27 +48,40 @@
#define ENCODER 0x09 // same as PIN_MODE_ENCODER
#define IGNORE 0x7F // same as PIN_MODE_IGNORE

extern "C" {
// callback function types
typedef void (*callbackFunction)(uint8_t, int);
typedef void (*systemCallbackFunction)(void);
typedef void (*stringCallbackFunction)(char *);
typedef void (*sysexCallbackFunction)(uint8_t command, uint8_t argc, uint8_t *argv);
}

// TODO make it a subclass of a generic Serial/Stream base class
class FirmataClass
{
public:
FirmataClass();

/* Arduino constructors */
void begin();
void begin(long);
void begin(Stream &s);

/* querying functions */
void printVersion(void);
void blinkVersion(void);
void printFirmwareVersion(void);

//void setFirmwareVersion(byte major, byte minor); // see macro below
void setFirmwareNameAndVersion(const char *name, byte major, byte minor);
void disableBlinkVersion();

/* serial receive handling */
int available(void);
void processInput(void);
void parse(unsigned char value);
boolean isParsingMessage(void);

/* serial send handling */
void sendAnalog(byte pin, int value);
void sendDigital(byte pin, int value); // TODO implement this
Expand All @@ -77,16 +90,18 @@ class FirmataClass
void sendString(byte command, const char *string);
void sendSysex(byte command, byte bytec, byte *bytev);
void write(byte c);

/* attach & detach callback functions to messages */
void attach(uint8_t command, callbackFunction newFunction);
void attach(uint8_t command, systemCallbackFunction newFunction);
void attach(uint8_t command, stringCallbackFunction newFunction);
void attach(uint8_t command, sysexCallbackFunction newFunction);
void attach(uint8_t command, ::callbackFunction newFunction);
void attach(uint8_t command, ::systemCallbackFunction newFunction);
void attach(uint8_t command, ::stringCallbackFunction newFunction);
void attach(uint8_t command, ::sysexCallbackFunction newFunction);
void detach(uint8_t command);

/* access pin state and config */
byte getPinMode(byte pin);
void setPinMode(byte pin, byte config);

/* access pin state */
int getPinState(byte pin);
void setPinState(byte pin, int state);
Expand All @@ -101,9 +116,11 @@ class FirmataClass
FirmataMarshaller marshaller;
FirmataParser parser;
Stream *FirmataStream;

/* firmware name and version */
byte firmwareVersionCount;
byte *firmwareVersionVector;

/* pin configuration */
byte pinConfig[TOTAL_PINS];
int pinState[TOTAL_PINS];
Expand All @@ -113,6 +130,30 @@ class FirmataClass
/* private methods ------------------------------ */
void strobeBlinkPin(byte pin, int count, int onInterval, int offInterval);
friend void FirmataMarshaller::sendValueAsTwo7bitBytes(uint16_t value) const;

/* callback functions */
static callbackFunction currentAnalogCallback;
static callbackFunction currentDigitalCallback;
static callbackFunction currentPinModeCallback;
static callbackFunction currentPinValueCallback;
static callbackFunction currentReportAnalogCallback;
static callbackFunction currentReportDigitalCallback;
static stringCallbackFunction currentStringCallback;
static sysexCallbackFunction currentSysexCallback;
static systemCallbackFunction currentSystemResetCallback;

/* static callbacks */
inline static void staticAnalogCallback (void *, uint8_t command, uint16_t value) { if ( currentAnalogCallback ) { currentAnalogCallback(command,(int)value); } }
inline static void staticDigitalCallback (void *, uint8_t command, uint16_t value) { if ( currentDigitalCallback ) { currentDigitalCallback(command, (int)value); } }
inline static void staticPinModeCallback (void *, uint8_t command, uint16_t value) { if ( currentPinModeCallback ) { currentPinModeCallback(command, (int)value); } }
inline static void staticPinValueCallback (void *, uint8_t command, uint16_t value) { if ( currentPinValueCallback ) { currentPinValueCallback(command, (int)value); } }
inline static void staticReportAnalogCallback (void *, uint8_t command, uint16_t value) { if ( currentReportAnalogCallback ) { currentReportAnalogCallback(command, (int)value); } }
inline static void staticReportDigitalCallback (void *, uint8_t command, uint16_t value) { if ( currentReportDigitalCallback ) { currentReportDigitalCallback(command, (int)value); } }
inline static void staticStringCallback (void *, char * c_str) { if ( currentStringCallback ) { currentStringCallback(c_str); } }
inline static void staticSysexCallback (void *, uint8_t command, size_t argc, uint8_t *argv) { if ( currentSysexCallback ) { currentSysexCallback(command, (uint8_t)argc, argv); } }
inline static void staticReportFirmwareCallback (void * context) { if ( context ) { ((FirmataClass *)context)->printFirmwareVersion(); } }
inline static void staticReportVersionCallback (void * context) { if ( context ) { ((FirmataClass *)context)->printVersion(); } }
inline static void staticSystemResetCallback (void *) { if ( currentSystemResetCallback ) { currentSystemResetCallback(); } }
};

extern FirmataClass Firmata;
Expand Down
Loading