diff options
10 files changed, 687 insertions, 373 deletions
diff --git a/libraries/Firmata/Firmata.cpp b/libraries/Firmata/Firmata.cpp index 4e59d27..9a18615 100644 --- a/libraries/Firmata/Firmata.cpp +++ b/libraries/Firmata/Firmata.cpp @@ -29,18 +29,18 @@ extern "C" { void sendValueAsTwo7bitBytes(int value) { - Serial.print(value & B01111111, BYTE); // LSB - Serial.print(value >> 7 & B01111111, BYTE); // MSB + Serial.print(value & B01111111, BYTE); // LSB + Serial.print(value >> 7 & B01111111, BYTE); // MSB } void startSysex(void) { - Serial.print(START_SYSEX, BYTE); + Serial.print(START_SYSEX, BYTE); } void endSysex(void) { - Serial.print(END_SYSEX, BYTE); + Serial.print(END_SYSEX, BYTE); } //****************************************************************************** @@ -49,8 +49,8 @@ void endSysex(void) FirmataClass::FirmataClass(void) { - firmwareVersionCount = 0; - systemReset(); + firmwareVersionCount = 0; + systemReset(); } //****************************************************************************** @@ -60,83 +60,83 @@ FirmataClass::FirmataClass(void) /* begin method for overriding default serial bitrate */ void FirmataClass::begin(void) { - Serial.begin(115200); - blinkVersion(); - delay(300); - printVersion(); + Serial.begin(57600); + blinkVersion(); + delay(300); + printVersion(); } /* begin method for overriding default serial bitrate */ void FirmataClass::begin(long speed) { - blinkVersion(); + blinkVersion(); #if defined(__AVR_ATmega128__) // Wiring - Serial.begin((uint32_t)speed); + Serial.begin((uint32_t)speed); #else - Serial.begin(speed); + Serial.begin(speed); #endif - delay(300); - printVersion(); - printFirmwareVersion(); + delay(300); + printVersion(); + printFirmwareVersion(); } // output the protocol version message to the serial port void FirmataClass::printVersion(void) { - Serial.print(REPORT_VERSION, BYTE); - Serial.print(FIRMATA_MAJOR_VERSION, BYTE); - Serial.print(FIRMATA_MINOR_VERSION, BYTE); + Serial.print(REPORT_VERSION, BYTE); + Serial.print(FIRMATA_MAJOR_VERSION, BYTE); + Serial.print(FIRMATA_MINOR_VERSION, BYTE); } void FirmataClass::blinkVersion(void) { - // flash the pin with the protocol version - pinMode(VERSION_BLINK_PIN,OUTPUT); - pin13strobe(FIRMATA_MAJOR_VERSION, 200, 400); - delay(300); - pin13strobe(2,1,4); // separator, a quick burst - delay(300); - pin13strobe(FIRMATA_MINOR_VERSION, 200, 400); + // flash the pin with the protocol version + pinMode(VERSION_BLINK_PIN,OUTPUT); + pin13strobe(FIRMATA_MAJOR_VERSION, 200, 400); + delay(300); + pin13strobe(2,1,4); // separator, a quick burst + delay(300); + pin13strobe(FIRMATA_MINOR_VERSION, 200, 400); } void FirmataClass::printFirmwareVersion(void) { - byte i; - - if(firmwareVersionCount) { // make sure that the name has been set before reporting - startSysex(); - Serial.print(REPORT_FIRMWARE, BYTE); - Serial.print(firmwareVersionVector[0]); // major version number - Serial.print(firmwareVersionVector[1]); // minor version number - for(i=2; i<firmwareVersionCount; ++i) { - sendValueAsTwo7bitBytes(firmwareVersionVector[i]); - } - endSysex(); + byte i; + + if(firmwareVersionCount) { // make sure that the name has been set before reporting + startSysex(); + Serial.print(REPORT_FIRMWARE, BYTE); + Serial.print(firmwareVersionVector[0]); // major version number + Serial.print(firmwareVersionVector[1]); // minor version number + for(i=2; i<firmwareVersionCount; ++i) { + sendValueAsTwo7bitBytes(firmwareVersionVector[i]); } + endSysex(); + } } void FirmataClass::setFirmwareNameAndVersion(const char *name, byte major, byte minor) { - const char *filename; - char *extension; - -// parse out ".cpp" and "applet/" that comes from using __FILE__ - extension = strstr(name, ".cpp"); - filename = strrchr(name, '/') + 1; //points to slash, +1 gets to start of filename - // add two bytes for version numbers - if(extension && filename) { - firmwareVersionCount = extension - filename + 2; - } else { - firmwareVersionCount = strlen(name) + 2; - filename = name; - } - firmwareVersionVector = (byte *) malloc(firmwareVersionCount); - firmwareVersionVector[firmwareVersionCount] = 0; - firmwareVersionVector[0] = major; - firmwareVersionVector[1] = minor; - strncpy((char*)firmwareVersionVector + 2, filename, firmwareVersionCount - 2); -// alas, no snprintf on Arduino -// snprintf(firmwareVersionVector, MAX_DATA_BYTES, "%c%c%s", -// (char)major, (char)minor, firmwareVersionVector); + const char *filename; + char *extension; + + // parse out ".cpp" and "applet/" that comes from using __FILE__ + extension = strstr(name, ".cpp"); + filename = strrchr(name, '/') + 1; //points to slash, +1 gets to start of filename + // add two bytes for version numbers + if(extension && filename) { + firmwareVersionCount = extension - filename + 2; + } else { + firmwareVersionCount = strlen(name) + 2; + filename = name; + } + firmwareVersionVector = (byte *) malloc(firmwareVersionCount); + firmwareVersionVector[firmwareVersionCount] = 0; + firmwareVersionVector[0] = major; + firmwareVersionVector[1] = minor; + strncpy((char*)firmwareVersionVector + 2, filename, firmwareVersionCount - 2); + // alas, no snprintf on Arduino + // snprintf(firmwareVersionVector, MAX_DATA_BYTES, "%c%c%s", + // (char)major, (char)minor, firmwareVersionVector); } //------------------------------------------------------------------------------ @@ -144,123 +144,123 @@ void FirmataClass::setFirmwareNameAndVersion(const char *name, byte major, byte int FirmataClass::available(void) { - return Serial.available(); + return Serial.available(); } void FirmataClass::processSysexMessage(void) { - switch(storedInputData[0]) { //first byte in buffer is command - case REPORT_FIRMWARE: - printFirmwareVersion(); - break; - case FIRMATA_STRING: - if(currentStringCallback) { - byte bufferLength = (sysexBytesRead - 1) / 2; - char *buffer = (char*)malloc(bufferLength * sizeof(char)); - byte i = 1; - byte j = 0; - while(j < bufferLength) { - buffer[j] = (char)storedInputData[i]; - i++; - buffer[j] += (char)(storedInputData[i] << 7); - i++; - j++; - } - (*currentStringCallback)(buffer); - } - break; - default: - if(currentSysexCallback) - (*currentSysexCallback)(storedInputData[0], sysexBytesRead - 1, storedInputData + 1); + switch(storedInputData[0]) { //first byte in buffer is command + case REPORT_FIRMWARE: + printFirmwareVersion(); + break; + case STRING_DATA: + if(currentStringCallback) { + byte bufferLength = (sysexBytesRead - 1) / 2; + char *buffer = (char*)malloc(bufferLength * sizeof(char)); + byte i = 1; + byte j = 0; + while(j < bufferLength) { + buffer[j] = (char)storedInputData[i]; + i++; + buffer[j] += (char)(storedInputData[i] << 7); + i++; + j++; + } + (*currentStringCallback)(buffer); } + break; + default: + if(currentSysexCallback) + (*currentSysexCallback)(storedInputData[0], sysexBytesRead - 1, storedInputData + 1); + } } void FirmataClass::processInput(void) { - int inputData = Serial.read(); // this is 'int' to handle -1 when no data - int command; + int inputData = Serial.read(); // this is 'int' to handle -1 when no data + int command; - // TODO make sure it handles -1 properly - - if (parsingSysex) { - if(inputData == END_SYSEX) { - //stop sysex byte - parsingSysex = false; - //fire off handler function - processSysexMessage(); - } else { - //normal data byte - add to buffer - storedInputData[sysexBytesRead] = inputData; - sysexBytesRead++; - } - } else if( (waitForData > 0) && (inputData < 128) ) { - waitForData--; - storedInputData[waitForData] = inputData; - if( (waitForData==0) && executeMultiByteCommand ) { // got the whole message - switch(executeMultiByteCommand) { - case ANALOG_MESSAGE: - if(currentAnalogCallback) { - (*currentAnalogCallback)(multiByteChannel, - (storedInputData[0] << 7) - + storedInputData[1]); - } - break; - case DIGITAL_MESSAGE: - if(currentDigitalCallback) { - (*currentDigitalCallback)(multiByteChannel, - (storedInputData[0] << 7) - + storedInputData[1]); - } - break; - case SET_PIN_MODE: - if(currentPinModeCallback) - (*currentPinModeCallback)(storedInputData[1], storedInputData[0]); - break; - case REPORT_ANALOG: - if(currentReportAnalogCallback) - (*currentReportAnalogCallback)(multiByteChannel,storedInputData[0]); - break; - case REPORT_DIGITAL: - if(currentReportDigitalCallback) - (*currentReportDigitalCallback)(multiByteChannel,storedInputData[0]); - break; - } - executeMultiByteCommand = 0; - } + // TODO make sure it handles -1 properly + + if (parsingSysex) { + if(inputData == END_SYSEX) { + //stop sysex byte + parsingSysex = false; + //fire off handler function + processSysexMessage(); } else { - // remove channel info from command byte if less than 0xF0 - if(inputData < 0xF0) { - command = inputData & 0xF0; - multiByteChannel = inputData & 0x0F; - } else { - command = inputData; - // commands in the 0xF* range don't use channel data + //normal data byte - add to buffer + storedInputData[sysexBytesRead] = inputData; + sysexBytesRead++; + } + } else if( (waitForData > 0) && (inputData < 128) ) { + waitForData--; + storedInputData[waitForData] = inputData; + if( (waitForData==0) && executeMultiByteCommand ) { // got the whole message + switch(executeMultiByteCommand) { + case ANALOG_MESSAGE: + if(currentAnalogCallback) { + (*currentAnalogCallback)(multiByteChannel, + (storedInputData[0] << 7) + + storedInputData[1]); } - switch (command) { - case ANALOG_MESSAGE: - case DIGITAL_MESSAGE: - case SET_PIN_MODE: - waitForData = 2; // two data bytes needed - executeMultiByteCommand = command; - break; - case REPORT_ANALOG: - case REPORT_DIGITAL: - waitForData = 1; // two data bytes needed - executeMultiByteCommand = command; - break; - case START_SYSEX: - parsingSysex = true; - sysexBytesRead = 0; - break; - case SYSTEM_RESET: - systemReset(); - break; - case REPORT_VERSION: - Firmata.printVersion(); - break; + break; + case DIGITAL_MESSAGE: + if(currentDigitalCallback) { + (*currentDigitalCallback)(multiByteChannel, + (storedInputData[0] << 7) + + storedInputData[1]); } + break; + case SET_PIN_MODE: + if(currentPinModeCallback) + (*currentPinModeCallback)(storedInputData[1], storedInputData[0]); + break; + case REPORT_ANALOG: + if(currentReportAnalogCallback) + (*currentReportAnalogCallback)(multiByteChannel,storedInputData[0]); + break; + case REPORT_DIGITAL: + if(currentReportDigitalCallback) + (*currentReportDigitalCallback)(multiByteChannel,storedInputData[0]); + break; + } + executeMultiByteCommand = 0; + } + } else { + // remove channel info from command byte if less than 0xF0 + if(inputData < 0xF0) { + command = inputData & 0xF0; + multiByteChannel = inputData & 0x0F; + } else { + command = inputData; + // commands in the 0xF* range don't use channel data } + switch (command) { + case ANALOG_MESSAGE: + case DIGITAL_MESSAGE: + case SET_PIN_MODE: + waitForData = 2; // two data bytes needed + executeMultiByteCommand = command; + break; + case REPORT_ANALOG: + case REPORT_DIGITAL: + waitForData = 1; // two data bytes needed + executeMultiByteCommand = command; + break; + case START_SYSEX: + parsingSysex = true; + sysexBytesRead = 0; + break; + case SYSTEM_RESET: + systemReset(); + break; + case REPORT_VERSION: + Firmata.printVersion(); + break; + } + } } //------------------------------------------------------------------------------ @@ -269,31 +269,31 @@ void FirmataClass::processInput(void) // send an analog message void FirmataClass::sendAnalog(byte pin, int value) { - // pin can only be 0-15, so chop higher bits - Serial.print(ANALOG_MESSAGE | (pin & 0xF), BYTE); - sendValueAsTwo7bitBytes(value); + // pin can only be 0-15, so chop higher bits + Serial.print(ANALOG_MESSAGE | (pin & 0xF), BYTE); + sendValueAsTwo7bitBytes(value); } // send a single digital pin in a digital message void FirmataClass::sendDigital(byte pin, int 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 - * numbering of the pins will probably differ on Arduino, Wiring, and - * other boards. The DIGITAL_MESSAGE sends 14 bits at a time, but it is - * probably easier to send 8 bit ports for any board with more than 14 - * digital pins. - */ - - // TODO: the digital message should not be sent on the serial port every - // time sendDigital() is called. Instead, it should add it to an int - // which will be sent on a schedule. If a pin changes more than once - // before the digital message is sent on the serial port, it should send a - // digital message for each change. - -// if(value == 0) -// sendDigitalPortPair(); + /* 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 + * numbering of the pins will probably differ on Arduino, Wiring, and + * other boards. The DIGITAL_MESSAGE sends 14 bits at a time, but it is + * probably easier to send 8 bit ports for any board with more than 14 + * digital pins. + */ + + // TODO: the digital message should not be sent on the serial port every + // time sendDigital() is called. Instead, it should add it to an int + // which will be sent on a schedule. If a pin changes more than once + // before the digital message is sent on the serial port, it should send a + // digital message for each change. + + // if(value == 0) + // sendDigitalPortPair(); } @@ -301,33 +301,33 @@ void FirmataClass::sendDigital(byte pin, int value) // send an 8-bit port in a single digital message (protocol v2) void FirmataClass::sendDigitalPort(byte portNumber, int portData) { - Serial.print(DIGITAL_MESSAGE | (portNumber & 0xF),BYTE); - Serial.print(portData % 128, BYTE); // Tx bits 0-6 - Serial.print(portData >> 7, BYTE); // Tx bits 7-13 + Serial.print(DIGITAL_MESSAGE | (portNumber & 0xF),BYTE); + Serial.print(portData % 128, BYTE); // Tx bits 0-6 + Serial.print(portData >> 7, BYTE); // Tx bits 7-13 } void FirmataClass::sendSysex(byte command, byte bytec, byte* bytev) { - byte i; - startSysex(); - Serial.print(command, BYTE); - for(i=0; i<bytec; i++) { - sendValueAsTwo7bitBytes(bytev[i]); - } - endSysex(); + byte i; + startSysex(); + Serial.print(command, BYTE); + for(i=0; i<bytec; i++) { + sendValueAsTwo7bitBytes(bytev[i]); + } + endSysex(); } void FirmataClass::sendString(byte command, const char* string) { - sendSysex(command, strlen(string), (byte *)string); + sendSysex(command, strlen(string), (byte *)string); } // send a string as the protocol string type void FirmataClass::sendString(const char* string) { - sendString(FIRMATA_STRING, string); + sendString(STRING_DATA, string); } @@ -336,43 +336,43 @@ void FirmataClass::sendString(const char* string) // generic callbacks void FirmataClass::attach(byte 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; - } + 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; + } } void FirmataClass::attach(byte command, systemResetCallbackFunction newFunction) { - switch(command) { - case SYSTEM_RESET: currentSystemResetCallback = newFunction; break; - } + switch(command) { + case SYSTEM_RESET: currentSystemResetCallback = newFunction; break; + } } void FirmataClass::attach(byte command, stringCallbackFunction newFunction) { - switch(command) { - case FIRMATA_STRING: currentStringCallback = newFunction; break; - } + switch(command) { + case STRING_DATA: currentStringCallback = newFunction; break; + } } void FirmataClass::attach(byte command, sysexCallbackFunction newFunction) { - currentSysexCallback = newFunction; + currentSysexCallback = newFunction; } void FirmataClass::detach(byte command) { - switch(command) { - case SYSTEM_RESET: currentSystemResetCallback = NULL; break; - case FIRMATA_STRING: currentStringCallback = NULL; break; - case START_SYSEX: currentSysexCallback = NULL; break; - default: - attach(command, (callbackFunction)NULL); - } + switch(command) { + case SYSTEM_RESET: currentSystemResetCallback = NULL; break; + case STRING_DATA: currentStringCallback = NULL; break; + case START_SYSEX: currentSysexCallback = NULL; break; + default: + attach(command, (callbackFunction)NULL); + } } // sysex callbacks @@ -402,24 +402,24 @@ void FirmataClass::detach(byte command) // resets the system state upon a SYSTEM_RESET message from the host software void FirmataClass::systemReset(void) { - byte i; + byte i; - waitForData = 0; // this flag says the next serial input will be data - executeMultiByteCommand = 0; // execute this after getting multi-byte data - multiByteChannel = 0; // channel data for multiByteCommands + waitForData = 0; // this flag says the next serial input will be data + executeMultiByteCommand = 0; // execute this after getting multi-byte data + multiByteChannel = 0; // channel data for multiByteCommands - for(i=0; i<MAX_DATA_BYTES; i++) { - storedInputData[i] = 0; - } + for(i=0; i<MAX_DATA_BYTES; i++) { + storedInputData[i] = 0; + } - parsingSysex = false; - sysexBytesRead = 0; + parsingSysex = false; + sysexBytesRead = 0; - if(currentSystemResetCallback) - (*currentSystemResetCallback)(); + if(currentSystemResetCallback) + (*currentSystemResetCallback)(); - //flush(); //TODO uncomment when Firmata is a subclass of HardwareSerial + //flush(); //TODO uncomment when Firmata is a subclass of HardwareSerial } @@ -428,14 +428,14 @@ void FirmataClass::systemReset(void) // used for flashing the pin for the version number void FirmataClass::pin13strobe(int count, int onInterval, int offInterval) { - byte i; - pinMode(VERSION_BLINK_PIN, OUTPUT); - for(i=0; i<count; i++) { - delay(offInterval); - digitalWrite(VERSION_BLINK_PIN, HIGH); - delay(onInterval); - digitalWrite(VERSION_BLINK_PIN, LOW); - } + byte i; + pinMode(VERSION_BLINK_PIN, OUTPUT); + for(i=0; i<count; i++) { + delay(offInterval); + digitalWrite(VERSION_BLINK_PIN, HIGH); + delay(onInterval); + digitalWrite(VERSION_BLINK_PIN, LOW); + } } diff --git a/libraries/Firmata/Firmata.h b/libraries/Firmata/Firmata.h index a926462..65c537f 100644 --- a/libraries/Firmata/Firmata.h +++ b/libraries/Firmata/Firmata.h @@ -22,7 +22,7 @@ * software can test whether it will be compatible with the currently * installed firmware. */ #define FIRMATA_MAJOR_VERSION 2 // for non-compatible changes -#define FIRMATA_MINOR_VERSION 0 // for backwards compatible changes +#define FIRMATA_MINOR_VERSION 1 // for backwards compatible changes #define VERSION_BLINK_PIN 13 // digital pin to blink version on #define MAX_DATA_BYTES 32 // max number of data bytes in non-Sysex messages @@ -42,12 +42,22 @@ #define END_SYSEX 0xF7 // end a MIDI Sysex message // extended command set using sysex (0-127/0x00-0x7F) -/* 0x00-0x0F reserved for custom commands */ +/* 0x00-0x0F reserved for user-defined commands */ #define SERVO_CONFIG 0x70 // set max angle, minPulse, maxPulse, freq -#define FIRMATA_STRING 0x71 // a string message with 14-bits per char +#define STRING_DATA 0x71 // a string message with 14-bits per char +#define SHIFT_DATA 0x75 // a bitstream to/from a shift register +#define I2C_REQUEST 0x76 // send an I2C read/write request +#define I2C_REPLY 0x77 // a reply to an I2C read request +#define I2C_CONFIG 0x78 // config I2C settings such as delay times and power pins #define REPORT_FIRMWARE 0x79 // report name and version of the firmware +#define SAMPLING_INTERVAL 0x7A // set the poll rate of the main loop #define SYSEX_NON_REALTIME 0x7E // MIDI Reserved for non-realtime messages #define SYSEX_REALTIME 0x7F // MIDI Reserved for realtime messages +// these are DEPRECATED to make the naming more consistent +#define FIRMATA_STRING 0x71 // same as STRING_DATA +#define SYSEX_I2C_REQUEST 0x76 // same as I2C_REQUEST +#define SYSEX_I2C_REPLY 0x77 // same as I2C_REPLY +#define SYSEX_SAMPLING_INTERVAL 0x7A // same as SAMPLING_INTERVAL // pin modes //#define INPUT 0x00 // defined in wiring.h @@ -55,7 +65,8 @@ #define ANALOG 0x02 // analog pin in analogInput mode #define PWM 0x03 // digital pin in PWM output mode #define SERVO 0x04 // digital pin in Servo output mode - +#define SHIFT 0x05 // shiftIn/shiftOut mode +#define I2C 0x06 // pin included in I2C setup extern "C" { // callback function types @@ -151,6 +162,11 @@ extern FirmataClass Firmata; #define TOTAL_DIGITAL_PINS 20 // 14 digital + 6 analog #define TOTAL_PORTS 3 // total number of ports for the board #define ANALOG_PORT 2 // port# of analog used as digital +#elif defined(__AVR_ATmega1280__)// Arduino Mega +#define TOTAL_ANALOG_PINS 16 +#define TOTAL_DIGITAL_PINS 54 +#define TOTAL_PORTS 8 // total number of ports for the board +#define ANALOG_PORT 2 // port# of analog used as digital #elif defined(__AVR_ATmega128__)// Wiring #define TOTAL_ANALOG_PINS 8 #define TOTAL_DIGITAL_PINS 51 diff --git a/libraries/Firmata/examples/AnalogFirmata/AnalogFirmata.pde b/libraries/Firmata/examples/AnalogFirmata/AnalogFirmata.pde index fcd8e5e..ab83726 100644 --- a/libraries/Firmata/examples/AnalogFirmata/AnalogFirmata.pde +++ b/libraries/Firmata/examples/AnalogFirmata/AnalogFirmata.pde @@ -61,7 +61,7 @@ void setup() servo9.attach(9); servo10.attach(10); - Firmata.begin(); + Firmata.begin(57600); } /*============================================================================== diff --git a/libraries/Firmata/examples/EchoString/EchoString.pde b/libraries/Firmata/examples/EchoString/EchoString.pde index ed13ad8..6559ae1 100644 --- a/libraries/Firmata/examples/EchoString/EchoString.pde +++ b/libraries/Firmata/examples/EchoString/EchoString.pde @@ -25,9 +25,9 @@ void sysexCallback(byte command, byte argc, byte*argv) void setup() { Firmata.setFirmwareVersion(0, 1); - Firmata.attach(FIRMATA_STRING, stringCallback); + Firmata.attach(STRING_DATA, stringCallback); Firmata.attach(START_SYSEX, sysexCallback); - Firmata.begin(); + Firmata.begin(57600); } void loop() diff --git a/libraries/Firmata/examples/I2CFirmata/I2CFirmata.pde b/libraries/Firmata/examples/I2CFirmata/I2CFirmata.pde new file mode 100644 index 0000000..ffcb589 --- /dev/null +++ b/libraries/Firmata/examples/I2CFirmata/I2CFirmata.pde @@ -0,0 +1,220 @@ +/* + Copyright (C) 2009 Jeff Hoefs. All rights reserved. + Copyright (C) 2009 Shigeru Kobayashi. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + See file LICENSE.txt for further informations on licensing terms. + */ + +#include <Wire.h> +#include <Firmata.h> + + +#define I2C_WRITE B00000000 +#define I2C_READ B00001000 +#define I2C_READ_CONTINUOUSLY B00010000 +#define I2C_STOP_READING B00011000 +#define I2C_READ_WRITE_MODE_MASK B00011000 + +#define MAX_QUERIES 8 + +unsigned long currentMillis; // store the current value from millis() +unsigned long nextExecuteMillis; // for comparison with currentMillis +unsigned int samplingInterval = 32; // default sampling interval is 33ms +unsigned int i2cReadDelayTime = 0; // default delay time between i2c read request and Wire.requestFrom() +unsigned int powerPinsEnabled = 0; // use as boolean to prevent enablePowerPins from being called more than once + +#define MINIMUM_SAMPLING_INTERVAL 10 + +#define REGISTER_NOT_SPECIFIED -1 + +struct i2c_device_info { + byte addr; + byte reg; + byte bytes; +}; + +i2c_device_info query[MAX_QUERIES]; + +byte i2cRxData[32]; +boolean readingContinuously = false; +byte queryIndex = 0; + +void readAndReportData(byte address, int theRegister, byte numBytes) +{ + if (theRegister != REGISTER_NOT_SPECIFIED) { + Wire.beginTransmission(address); + Wire.send((byte)theRegister); + Wire.endTransmission(); + delayMicroseconds(i2cReadDelayTime); // delay is necessary for some devices such as WiiNunchuck + } + else { + theRegister = 0; // fill the register with a dummy value + } + + Wire.requestFrom(address, numBytes); + + // check to be sure correct number of bytes were returned by slave + if(numBytes == Wire.available()) { + i2cRxData[0] = address; + i2cRxData[1] = theRegister; + for (int i = 0; i < numBytes; i++) { + i2cRxData[2 + i] = Wire.receive(); + } + // send slave address, register and received bytes + Firmata.sendSysex(I2C_REPLY, numBytes + 2, i2cRxData); + } + else { + if(numBytes > Wire.available()) { + Firmata.sendString("I2C Read Error: Too many bytes received"); + } else { + Firmata.sendString("I2C Read Error: Too few bytes received"); + } + } + +} + +void sysexCallback(byte command, byte argc, byte *argv) +{ + byte mode; + byte slaveAddress; + byte slaveRegister; + byte data; + int delayTime; + + if (command == I2C_REQUEST) { + mode = argv[1] & I2C_READ_WRITE_MODE_MASK; + slaveAddress = argv[0]; + + switch(mode) { + case I2C_WRITE: + Wire.beginTransmission(slaveAddress); + for (byte i = 2; i < argc; i += 2) { + data = argv[i] + (argv[i + 1] << 7); + Wire.send(data); + } + Wire.endTransmission(); + delayMicroseconds(70); // TODO is this needed? + break; + case I2C_READ: + if (argc == 6) { + // a slave register is specified + slaveRegister = argv[2] + (argv[3] << 7); + data = argv[4] + (argv[5] << 7); // bytes to read + readAndReportData(slaveAddress, (int)slaveRegister, data); + } + else { + // a slave register is NOT specified + data = argv[2] + (argv[3] << 7); // bytes to read + readAndReportData(slaveAddress, (int)REGISTER_NOT_SPECIFIED, data); + } + break; + case I2C_READ_CONTINUOUSLY: + if ((queryIndex + 1) >= MAX_QUERIES) { + // too many queries, just ignore + Firmata.sendString("too many queries"); + break; + } + query[queryIndex].addr = slaveAddress; + query[queryIndex].reg = argv[2] + (argv[3] << 7); + query[queryIndex].bytes = argv[4] + (argv[5] << 7); + readingContinuously = true; + queryIndex++; + break; + case I2C_STOP_READING: + readingContinuously = false; + queryIndex = 0; + break; + default: + break; + } + } + else if (command == SAMPLING_INTERVAL) { + samplingInterval = argv[0] + (argv[1] << 7); + + if (samplingInterval < MINIMUM_SAMPLING_INTERVAL) { + samplingInterval = MINIMUM_SAMPLING_INTERVAL; + } + + samplingInterval -= 1; + Firmata.sendString("sampling interval"); + } + + else if (command == I2C_CONFIG) { + delayTime = (argv[4] + (argv[5] << 7)); // MSB + delayTime = (delayTime << 8) + (argv[2] + (argv[3] << 7)); // add LSB + + if((argv[0] + (argv[1] << 7)) > 0) { + enablePowerPins(PC3, PC2); + } + + if(delayTime > 0) { + i2cReadDelayTime = delayTime; + } + + if(argc > 6) { + // If you extend I2C_Config, handle your data here + } + + } +} + +void systemResetCallback() +{ + readingContinuously = false; + queryIndex = 0; +} + +/* reference: BlinkM_funcs.h by Tod E. Kurt, ThingM, http://thingm.com/ */ +// Enables Pins A2 and A3 to be used as GND and Power +// so that I2C devices can be plugged directly +// into Arduino header (pins A2 - A5) +static void enablePowerPins(byte pwrpin, byte gndpin) +{ + if(powerPinsEnabled == 0) { + DDRC |= _BV(pwrpin) | _BV(gndpin); + PORTC &=~ _BV(gndpin); + PORTC |= _BV(pwrpin); + powerPinsEnabled = 1; + Firmata.sendString("Power pins enabled"); + delay(100); + } +} + +void setup() +{ + Firmata.setFirmwareVersion(2, 0); + + Firmata.attach(START_SYSEX, sysexCallback); + Firmata.attach(SYSTEM_RESET, systemResetCallback); + + for (int i = 0; i < TOTAL_DIGITAL_PINS; ++i) { + pinMode(i, OUTPUT); + } + + /* I2C data is not reliable at higher baud rates, you'll need to change the + baud rate on the host computer as well. To get a firmware running with + minimal effort, you can try using the default baud rate (115200) */ + Firmata.begin(38400); + Wire.begin(); +} + +void loop() +{ + while (Firmata.available()) { + Firmata.processInput(); + } + + currentMillis = millis(); + if (currentMillis > nextExecuteMillis) { + nextExecuteMillis = currentMillis + samplingInterval; + + for (byte i = 0; i < queryIndex; i++) { + readAndReportData(query[i].addr, query[i].reg, query[i].bytes); + } + } +} diff --git a/libraries/Firmata/examples/ServoFirmata/ServoFirmata.pde b/libraries/Firmata/examples/ServoFirmata/ServoFirmata.pde index a3c609c..fa48e2b 100644 --- a/libraries/Firmata/examples/ServoFirmata/ServoFirmata.pde +++ b/libraries/Firmata/examples/ServoFirmata/ServoFirmata.pde @@ -28,7 +28,7 @@ void setup() servo9.attach(9); servo10.attach(10); - Firmata.begin(); + Firmata.begin(57600); } void loop() diff --git a/libraries/Firmata/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.pde b/libraries/Firmata/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.pde index 2950c01..430d0d0 100644 --- a/libraries/Firmata/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.pde +++ b/libraries/Firmata/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.pde @@ -16,7 +16,7 @@ void setup() { Firmata.setFirmwareVersion(0, 1); Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); - Firmata.begin(); + Firmata.begin(57600); } void loop() diff --git a/libraries/Firmata/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.pde b/libraries/Firmata/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.pde index 1104a92..9c4e05d 100644 --- a/libraries/Firmata/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.pde +++ b/libraries/Firmata/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.pde @@ -45,7 +45,7 @@ void setup() Firmata.setFirmwareVersion(0, 1); Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback); Firmata.attach(SET_PIN_MODE, setPinModeCallback); - Firmata.begin(); + Firmata.begin(57600); } void loop() diff --git a/libraries/Firmata/examples/StandardFirmata/Makefile b/libraries/Firmata/examples/StandardFirmata/Makefile index 55ca8c2..835187a 100644 --- a/libraries/Firmata/examples/StandardFirmata/Makefile +++ b/libraries/Firmata/examples/StandardFirmata/Makefile @@ -50,14 +50,20 @@ TARGET := $(shell pwd | sed 's|.*/\(.*\)|\1|') ARDUINO = /Applications/arduino ARDUINO_SRC = $(ARDUINO)/hardware/cores/arduino ARDUINO_LIB_SRC = $(ARDUINO)/hardware/libraries +ARDUINO_TOOLS = $(ARDUINO)/hardware/tools INCLUDE = -I$(ARDUINO_SRC) -I$(ARDUINO)/hardware/tools/avr/avr/include \ -I$(ARDUINO_LIB_SRC)/EEPROM \ -I$(ARDUINO_LIB_SRC)/Firmata \ + -I$(ARDUINO_LIB_SRC)/Matrix \ + -I$(ARDUINO_LIB_SRC)/Servo \ + -I$(ARDUINO_LIB_SRC)/Wire \ -I$(ARDUINO_LIB_SRC) SRC = $(wildcard $(ARDUINO_SRC)/*.c) CXXSRC = applet/$(TARGET).cpp $(ARDUINO_SRC)/HardwareSerial.cpp \ $(ARDUINO_LIB_SRC)/EEPROM/EEPROM.cpp \ $(ARDUINO_LIB_SRC)/Firmata/Firmata.cpp \ + $(ARDUINO_LIB_SRC)/Servo/Servo.cpp \ + $(ARDUINO_SRC)/Print.cpp \ $(ARDUINO_SRC)/WMath.cpp HEADERS = $(wildcard $(ARDUINO_SRC)/*.h) $(wildcard $(ARDUINO_LIB_SRC)/*/*.h) @@ -106,12 +112,14 @@ AVRDUDE_FLAGS = -F -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) \ -b $(UPLOAD_RATE) -q -V # Program settings -CC = avr-gcc -CXX = avr-g++ -OBJCOPY = avr-objcopy -OBJDUMP = avr-objdump -SIZE = avr-size -NM = avr-nm +ARDUINO_AVR_BIN = $(ARDUINO_TOOLS)/avr/bin +CC = $(ARDUINO_AVR_BIN)/avr-gcc +CXX = $(ARDUINO_AVR_BIN)/avr-g++ +OBJCOPY = $(ARDUINO_AVR_BIN)/avr-objcopy +OBJDUMP = $(ARDUINO_AVR_BIN)/avr-objdump +SIZE = $(ARDUINO_AVR_BIN)/avr-size +NM = $(ARDUINO_AVR_BIN)/avr-nm +#AVRDUDE = $(ARDUINO_AVR_BIN)/avrdude AVRDUDE = avrdude REMOVE = rm -f MV = mv -f @@ -204,7 +212,8 @@ applet/$(TARGET).cpp: $(TARGET).pde # Link: create ELF output file from object files. applet/$(TARGET).elf: applet/$(TARGET).cpp $(OBJ) - $(CC) $(ALL_CFLAGS) $(OBJ) --output $@ $(LDFLAGS) + $(CC) $(ALL_CFLAGS) $(OBJ) -lm --output $@ $(LDFLAGS) +# $(CC) $(ALL_CFLAGS) $(OBJ) $(ARDUINO_TOOLS)/avr/avr/lib/avr5/crtm168.o --output $@ $(LDFLAGS) pd_close_serial: echo 'close;' | /Applications/Pd-extended.app/Contents/Resources/bin/pdsend 34567 || true @@ -258,4 +267,7 @@ etags_MINGW: # etags -a /usr/include/*.h /usr/include/sys/*.h +path: + echo $(PATH) + echo $$PATH diff --git a/libraries/Firmata/examples/StandardFirmata/StandardFirmata.pde b/libraries/Firmata/examples/StandardFirmata/StandardFirmata.pde index 4cc8539..02192cc 100644 --- a/libraries/Firmata/examples/StandardFirmata/StandardFirmata.pde +++ b/libraries/Firmata/examples/StandardFirmata/StandardFirmata.pde @@ -1,21 +1,24 @@ /* Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights reserved. - + This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See file LICENSE.txt for further informations on licensing terms. - */ + + formatted using the GNU C formatting and indenting +*/ + /* - * TODO: add Servo support using setPinMode(pin, SERVO); + * TODO: add Servo support using setPinModeCallback(pin, SERVO); * TODO: use Program Control to load stored profiles from EEPROM */ -#include <EEPROM.h> #include <Firmata.h> +#include <Servo.h> /*============================================================================== * GLOBAL VARIABLES @@ -34,37 +37,45 @@ byte portStatus[TOTAL_PORTS]; /* timer variables */ unsigned long currentMillis; // store the current value from millis() unsigned long nextExecuteMillis; // for comparison with currentMillis +int samplingInterval = 19; // how often to run the main loop (in ms) +Servo servos[2]; // the servo library can control servos on pins 9 and 10 only /*============================================================================== - * FUNCTIONS + * FUNCTIONS *============================================================================*/ void outputPort(byte portNumber, byte portValue) { portValue = portValue &~ portStatus[portNumber]; if(previousPINs[portNumber] != portValue) { - Firmata.sendDigitalPort(portNumber, portValue); - previousPINs[portNumber] = portValue; - Firmata.sendDigitalPort(portNumber, portValue); - } + Firmata.sendDigitalPort(portNumber, portValue); + previousPINs[portNumber] = portValue; + Firmata.sendDigitalPort(portNumber, portValue); + } } /* ----------------------------------------------------------------------------- * check all the active digital inputs for change of state, then add any events * to the Serial output queue using Serial.print() */ -void checkDigitalInputs(void) +void checkDigitalInputs(void) { - byte i, tmp; - for(i=0; i < TOTAL_PORTS; i++) { - if(reportPINs[i]) { - switch(i) { - case 0: outputPort(0, PIND &~ B00000011); break; // ignore Rx/Tx 0/1 - case 1: outputPort(1, PINB); break; - case ANALOG_PORT: outputPort(ANALOG_PORT, PINC); break; - } - } + byte i, tmp; + for(i=0; i < TOTAL_PORTS; i++) { + if(reportPINs[i]) { + switch(i) { + case 0: + outputPort(0, PIND &~ B00000011); // ignore Rx/Tx 0/1 + break; + case 1: + outputPort(1, PINB); + break; + case ANALOG_PORT: + outputPort(ANALOG_PORT, PINC); + break; + } } + } } // ----------------------------------------------------------------------------- @@ -72,61 +83,87 @@ void checkDigitalInputs(void) * two bit-arrays that track Digital I/O and PWM status */ void setPinModeCallback(byte pin, int mode) { - byte port = 0; - byte offset = 0; - - if (pin < 8) { - port = 0; - offset = 0; - } else if (pin < 14) { - port = 1; - offset = 8; - } else if (pin < 22) { - port = 2; - offset = 14; - } + byte port = 0; + byte offset = 0; - if(pin > 1) { // ignore RxTx (pins 0 and 1) + // TODO: abstract for different boards + if (pin < 8) { + port = 0; + offset = 0; + } else if (pin < 14) { + port = 1; + offset = 8; + } else if (pin < 22) { + port = 2; + offset = 14; + } + + if(pin > 1) { // ignore RxTx (pins 0 and 1) + reportAnalogCallback(pin - 14, mode == ANALOG ? 1 : 0); // turn on/off reporting + switch(mode) { + case ANALOG: + digitalWrite(pin, LOW); // disable internal pull-ups and fall thru to 'case INPUT:' + case INPUT: + pinStatus[pin] = mode; + pinMode(pin, INPUT); + portStatus[port] = portStatus[port] &~ (1 << (pin - offset)); + break; + case OUTPUT: + digitalWrite(pin, LOW); // disable PWM and fall thru to 'case PWM:' + case PWM: + pinStatus[pin] = mode; + pinMode(pin, OUTPUT); + portStatus[port] = portStatus[port] | (1 << (pin - offset)); + break; + case SERVO: + if((pin == 9 || pin == 10)) pinStatus[pin] = mode; - switch(mode) { - case INPUT: - pinMode(pin, INPUT); - portStatus[port] = portStatus[port] &~ (1 << (pin - offset)); - break; - case OUTPUT: - digitalWrite(pin, LOW); // disable PWM - case PWM: - pinMode(pin, OUTPUT); - portStatus[port] = portStatus[port] | (1 << (pin - offset)); - break; - //case ANALOG: // TODO figure this out - default: - Firmata.sendString(""); - } - // TODO: save status to EEPROM here, if changed + else + Firmata.sendString("Servo only on pins 9 and 10"); + break; + case I2C: + pinStatus[pin] = mode; + Firmata.sendString("I2C mode not yet supported"); + break; + default: + Firmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM } + // TODO: save status to EEPROM here, if changed + } } void analogWriteCallback(byte pin, int value) { - setPinModeCallback(pin,PWM); + switch(pinStatus[pin]) { + case SERVO: + if(pin == 9) servos[0].write(value); + if(pin == 10) servos[1].write(value); + break; + case PWM: analogWrite(pin, value); + break; + } } void digitalWriteCallback(byte port, int value) { - switch(port) { - case 0: // pins 2-7 (don't change Rx/Tx, pins 0 and 1) - // 0xFF03 == B1111111100000011 0x03 == B00000011 - PORTD = (value &~ 0xFF03) | (PORTD & 0x03); - break; - case 1: // pins 8-13 (14,15 are disabled for the crystal) - PORTB = (byte)value; - break; - case 2: // analog pins used as digital - PORTC = (byte)value; - break; - } + switch(port) { + case 0: // pins 2-7 (don't change Rx/Tx, pins 0 and 1) + // 0xFF03 == B1111111100000011 0x03 == B00000011 + PORTD = (value &~ 0xFF03) | (PORTD & 0x03); + break; + case 1: // pins 8-13 (14,15 are disabled for the crystal) + PORTB = (byte)value; + break; + case 2: // analog pins used as digital + byte pin; + byte pinModeMask; + for(pin=0; pin<8; pin++) + if(pinStatus[pin] == OUTPUT) + pinModeMask += 1 << pin; + PORTC = (byte)value & pinModeMask; + break; + } } // ----------------------------------------------------------------------------- @@ -136,64 +173,93 @@ void digitalWriteCallback(byte port, int value) //} void reportAnalogCallback(byte pin, int value) { - if(value == 0) { - analogInputsToReport = analogInputsToReport &~ (1 << pin); - } - else { // everything but 0 enables reporting of that pin - analogInputsToReport = analogInputsToReport | (1 << pin); - } - // TODO: save status to EEPROM here, if changed + if(value == 0) { + analogInputsToReport = analogInputsToReport &~ (1 << pin); + } + else { // everything but 0 enables reporting of that pin + analogInputsToReport = analogInputsToReport | (1 << pin); + setPinModeCallback(pin, ANALOG); + } + // TODO: save status to EEPROM here, if changed } void reportDigitalCallback(byte port, int value) { - reportPINs[port] = (byte)value; - if(port == ANALOG_PORT) // turn off analog reporting when used as digital - analogInputsToReport = 0; + reportPINs[port] = (byte)value; + if(port == ANALOG_PORT) // turn off analog reporting when used as digital + analogInputsToReport = 0; +} + +/*============================================================================== + * SYSEX-BASED commands + *============================================================================*/ + +void sysexCallback(byte command, byte argc, byte *argv) +{ + switch(command) { + case SERVO_CONFIG: + if(argc > 4) { + // these vars are here for clarity, they'll optimized away by the compiler + byte pin = argv[0] - 9; // servos are pins 9 and 10, so offset for array + int minPulse = argv[1] + (argv[2] << 7); + int maxPulse = argv[3] + (argv[4] << 7); + servos[pin].attach(argv[0], minPulse, maxPulse); + // TODO does the Servo have to be detach()ed before reconfiguring? + setPinModeCallback(pin, SERVO); + } + break; + case SAMPLING_INTERVAL: + if (argc > 1) + samplingInterval = argv[0] + (argv[1] << 7); + else + Firmata.sendString("Not enough data"); + break; + } } + /*============================================================================== * SETUP() *============================================================================*/ void setup() { - byte i; + byte i; - Firmata.setFirmwareVersion(2, 0); + Firmata.setFirmwareVersion(2, 1); - Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); - Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback); - Firmata.attach(REPORT_ANALOG, reportAnalogCallback); - Firmata.attach(REPORT_DIGITAL, reportDigitalCallback); - Firmata.attach(SET_PIN_MODE, setPinModeCallback); + Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); + Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback); + Firmata.attach(REPORT_ANALOG, reportAnalogCallback); + Firmata.attach(REPORT_DIGITAL, reportDigitalCallback); + Firmata.attach(SET_PIN_MODE, setPinModeCallback); + Firmata.attach(START_SYSEX, sysexCallback); - portStatus[0] = B00000011; // ignore Tx/RX pins - portStatus[1] = B11000000; // ignore 14/15 pins - portStatus[2] = B00000000; + portStatus[0] = B00000011; // ignore Tx/RX pins + portStatus[1] = B11000000; // ignore 14/15 pins + portStatus[2] = B00000000; -// for(i=0; i<TOTAL_DIGITAL_PINS; ++i) { // TODO make this work with analogs - for(i=0; i<14; ++i) { - setPinModeCallback(i,OUTPUT); - } - // set all outputs to 0 to make sure internal pull-up resistors are off - PORTB = 0; // pins 8-15 - PORTC = 0; // analog port - PORTD = 0; // pins 0-7 - - // TODO rethink the init, perhaps it should report analog on default - for(i=0; i<TOTAL_PORTS; ++i) { - reportPINs[i] = false; - } - // TODO: load state from EEPROM here + for(i=0; i<TOTAL_DIGITAL_PINS; ++i) { // TODO make this work with analogs + setPinModeCallback(i,OUTPUT); + } + // set all outputs to 0 to make sure internal pull-up resistors are off + PORTB = 0; // pins 8-15 + PORTC = 0; // analog port + PORTD = 0; // pins 0-7 + + // TODO rethink the init, perhaps it should report analog on default + for(i=0; i<TOTAL_PORTS; ++i) { + reportPINs[i] = false; + } + // TODO: load state from EEPROM here - /* send digital inputs here, if enabled, to set the initial state on the - * host computer, since once in the loop(), this firmware will only send - * digital data on change. */ - if(reportPINs[0]) outputPort(0, PIND &~ B00000011); // ignore Rx/Tx 0/1 - if(reportPINs[1]) outputPort(1, PINB); - if(reportPINs[ANALOG_PORT]) outputPort(ANALOG_PORT, PINC); + /* send digital inputs here, if enabled, to set the initial state on the + * host computer, since once in the loop(), this firmware will only send + * digital data on change. */ + if(reportPINs[0]) outputPort(0, PIND &~ B00000011); // ignore Rx/Tx 0/1 + if(reportPINs[1]) outputPort(1, PINB); + if(reportPINs[ANALOG_PORT]) outputPort(ANALOG_PORT, PINC); - Firmata.begin(); + Firmata.begin(57600); } /*============================================================================== @@ -201,26 +267,26 @@ void setup() *============================================================================*/ void loop() { -/* DIGITALREAD - as fast as possible, check for changes and output them to the - * FTDI buffer using Serial.print() */ - checkDigitalInputs(); - currentMillis = millis(); - if(currentMillis > nextExecuteMillis) { - nextExecuteMillis = currentMillis + 19; // run this every 20ms - /* SERIALREAD - Serial.read() uses a 128 byte circular buffer, so handle - * all serialReads at once, i.e. empty the buffer */ - while(Firmata.available()) - Firmata.processInput(); - /* SEND FTDI WRITE BUFFER - make sure that the FTDI buffer doesn't go over - * 60 bytes. use a timer to sending an event character every 4 ms to - * trigger the buffer to dump. */ + /* DIGITALREAD - as fast as possible, check for changes and output them to the + * FTDI buffer using Serial.print() */ + checkDigitalInputs(); + currentMillis = millis(); + if(currentMillis > nextExecuteMillis) { + nextExecuteMillis = currentMillis + samplingInterval; + /* SERIALREAD - Serial.read() uses a 128 byte circular buffer, so handle + * all serialReads at once, i.e. empty the buffer */ + while(Firmata.available()) + Firmata.processInput(); + /* SEND FTDI WRITE BUFFER - make sure that the FTDI buffer doesn't go over + * 60 bytes. use a timer to sending an event character every 4 ms to + * trigger the buffer to dump. */ - /* ANALOGREAD - right after the event character, do all of the - * analogReads(). These only need to be done every 4ms. */ - for(analogPin=0;analogPin<TOTAL_ANALOG_PINS;analogPin++) { - if( analogInputsToReport & (1 << analogPin) ) { - Firmata.sendAnalog(analogPin, analogRead(analogPin)); - } - } + /* ANALOGREAD - right after the event character, do all of the + * analogReads(). These only need to be done every 4ms. */ + for(analogPin=0;analogPin<TOTAL_ANALOG_PINS;analogPin++) { + if( analogInputsToReport & (1 << analogPin) ) { + Firmata.sendAnalog(analogPin, analogRead(analogPin)); + } } + } } |