From b722028c7b0535cd9f642d985e62c35f5ca55282 Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Fri, 9 Sep 2011 17:11:42 -0400 Subject: [PATCH] Updating to Firmata r82 (e.g. including I2C in StandardFirmata). http://code.google.com/p/arduino/issues/detail?id=633 --- libraries/Firmata/Boards.h | 24 +- libraries/Firmata/Firmata.cpp | 10 +- .../AllInputsFirmata/AllInputsFirmata.ino | 11 + .../examples/AnalogFirmata/AnalogFirmata.ino | 11 + .../examples/EchoString/EchoString.ino | 11 + .../examples/I2CFirmata/I2CFirmata.ino | 11 + .../OldStandardFirmata/OldStandardFirmata.ino | 11 + .../examples/ServoFirmata/ServoFirmata.ino | 11 + .../SimpleAnalogFirmata.ino | 11 + .../SimpleDigitalFirmata.ino | 11 + .../StandardFirmata/StandardFirmata.ino | 304 ++++++++++++++++-- 11 files changed, 377 insertions(+), 49 deletions(-) diff --git a/libraries/Firmata/Boards.h b/libraries/Firmata/Boards.h index 52f61873f..06f69c629 100644 --- a/libraries/Firmata/Boards.h +++ b/libraries/Firmata/Boards.h @@ -124,6 +124,10 @@ writePort(port, value, bitmask): Write an 8 bit port. * Board Specific Configuration *============================================================================*/ +#ifndef digitalPinHasPWM +#define digitalPinHasPWM(p) IS_PIN_DIGITAL(p) +#endif + // Arduino Duemilanove, Diecimila, and NG #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) #if defined(NUM_ANALOG_INPUTS) && NUM_ANALOG_INPUTS == 6 @@ -136,7 +140,7 @@ writePort(port, value, bitmask): Write an 8 bit port. #define VERSION_BLINK_PIN 13 #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) <= 19) #define IS_PIN_ANALOG(p) ((p) >= 14 && (p) < 14 + TOTAL_ANALOG_PINS) -#define IS_PIN_PWM(p) IS_PIN_DIGITAL(p) +#define IS_PIN_PWM(p) digitalPinHasPWM(p) #define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) - 2 < MAX_SERVOS) #define IS_PIN_I2C(p) ((p) == 18 || (p) == 19) #define PIN_TO_DIGITAL(p) (p) @@ -151,7 +155,7 @@ writePort(port, value, bitmask): Write an 8 bit port. #define VERSION_BLINK_PIN WLED #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS) #define IS_PIN_ANALOG(p) ((p) >= FIRST_ANALOG_PIN && (p) < (FIRST_ANALOG_PIN+TOTAL_ANALOG_PINS)) -#define IS_PIN_PWM(p) IS_PIN_DIGITAL(p) +#define IS_PIN_PWM(p) digitalPinHasPWM(p) #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS) #define IS_PIN_I2C(p) ((p) == SDA || (p) == SCL) #define PIN_TO_DIGITAL(p) (p) @@ -167,7 +171,7 @@ writePort(port, value, bitmask): Write an 8 bit port. #define VERSION_BLINK_PIN 13 #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) <= 19) #define IS_PIN_ANALOG(p) ((p) >= 14 && (p) <= 19) -#define IS_PIN_PWM(p) IS_PIN_DIGITAL(p) +#define IS_PIN_PWM(p) digitalPinHasPWM(p) #define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) - 2 < MAX_SERVOS) #define IS_PIN_I2C(p) ((p) == 18 || (p) == 19) #define PIN_TO_DIGITAL(p) (p) @@ -178,13 +182,13 @@ writePort(port, value, bitmask): Write an 8 bit port. // Arduino Mega -#elif defined(__AVR_ATmega1280__) +#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) #define TOTAL_ANALOG_PINS 16 #define TOTAL_PINS 70 // 54 digital + 16 analog #define VERSION_BLINK_PIN 13 #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < TOTAL_PINS) #define IS_PIN_ANALOG(p) ((p) >= 54 && (p) < TOTAL_PINS) -#define IS_PIN_PWM(p) IS_PIN_DIGITAL(p) +#define IS_PIN_PWM(p) digitalPinHasPWM(p) #define IS_PIN_SERVO(p) ((p) >= 2 && (p) - 2 < MAX_SERVOS) #define IS_PIN_I2C(p) ((p) == 20 || (p) == 21) #define PIN_TO_DIGITAL(p) (p) @@ -200,7 +204,7 @@ writePort(port, value, bitmask): Write an 8 bit port. #define VERSION_BLINK_PIN 6 #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS) #define IS_PIN_ANALOG(p) (0) -#define IS_PIN_PWM(p) IS_PIN_DIGITAL(p) +#define IS_PIN_PWM(p) digitalPinHasPWM(p) #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS) #define IS_PIN_I2C(p) (0) #define PIN_TO_DIGITAL(p) (p) @@ -216,7 +220,7 @@ writePort(port, value, bitmask): Write an 8 bit port. #define VERSION_BLINK_PIN 11 #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS) #define IS_PIN_ANALOG(p) ((p) >= 11 && (p) <= 22) -#define IS_PIN_PWM(p) IS_PIN_DIGITAL(p) +#define IS_PIN_PWM(p) digitalPinHasPWM(p) #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS) #define IS_PIN_I2C(p) ((p) == 5 || (p) == 6) #define PIN_TO_DIGITAL(p) (p) @@ -232,7 +236,7 @@ writePort(port, value, bitmask): Write an 8 bit port. #define VERSION_BLINK_PIN 6 #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS) #define IS_PIN_ANALOG(p) ((p) >= 38 && (p) < TOTAL_PINS) -#define IS_PIN_PWM(p) IS_PIN_DIGITAL(p) +#define IS_PIN_PWM(p) digitalPinHasPWM(p) #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS) #define IS_PIN_I2C(p) ((p) == 0 || (p) == 1) #define PIN_TO_DIGITAL(p) (p) @@ -248,7 +252,7 @@ writePort(port, value, bitmask): Write an 8 bit port. #define VERSION_BLINK_PIN 0 #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < TOTAL_PINS) #define IS_PIN_ANALOG(p) ((p) >= 24 && (p) < TOTAL_PINS) -#define IS_PIN_PWM(p) IS_PIN_DIGITAL(p) +#define IS_PIN_PWM(p) digitalPinHasPWM(p) #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS) #define IS_PIN_I2C(p) ((p) == 16 || (p) == 17) #define PIN_TO_DIGITAL(p) (p) @@ -264,7 +268,7 @@ writePort(port, value, bitmask): Write an 8 bit port. #define VERSION_BLINK_PIN 13 #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < TOTAL_PINS) #define IS_PIN_ANALOG(p) ((p) >= 36 && (p) < TOTAL_PINS) -#define IS_PIN_PWM(p) IS_PIN_DIGITAL(p) +#define IS_PIN_PWM(p) digitalPinHasPWM(p) #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS) #define IS_PIN_I2C(p) ((p) == 4 || (p) == 5) #define PIN_TO_DIGITAL(p) (p) diff --git a/libraries/Firmata/Firmata.cpp b/libraries/Firmata/Firmata.cpp index 0d68a5744..e81c10bb1 100644 --- a/libraries/Firmata/Firmata.cpp +++ b/libraries/Firmata/Firmata.cpp @@ -68,7 +68,6 @@ void FirmataClass::begin(long speed) Serial.begin(speed); FirmataSerial = Serial; blinkVersion(); - delay(300); printVersion(); printFirmwareVersion(); } @@ -92,11 +91,10 @@ 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); + pin13strobe(FIRMATA_MAJOR_VERSION, 40, 210); + delay(250); + pin13strobe(FIRMATA_MINOR_VERSION, 40, 210); + delay(125); } void FirmataClass::printFirmwareVersion(void) diff --git a/libraries/Firmata/examples/AllInputsFirmata/AllInputsFirmata.ino b/libraries/Firmata/examples/AllInputsFirmata/AllInputsFirmata.ino index 775594938..bff736699 100644 --- a/libraries/Firmata/examples/AllInputsFirmata/AllInputsFirmata.ino +++ b/libraries/Firmata/examples/AllInputsFirmata/AllInputsFirmata.ino @@ -1,3 +1,14 @@ +/* + * Firmata is a generic protocol for communicating with microcontrollers + * from software on a host computer. It is intended to work with + * any host computer software package. + * + * To download a host software package, please clink on the following link + * to open the download page in your default browser. + * + * http://firmata.org/wiki/Download + */ + /* * This firmware reads all inputs and sends them as fast as it can. It was * inspired by the ease-of-use of the Arduino2Max program. diff --git a/libraries/Firmata/examples/AnalogFirmata/AnalogFirmata.ino b/libraries/Firmata/examples/AnalogFirmata/AnalogFirmata.ino index df8b674b9..ff1d664b8 100644 --- a/libraries/Firmata/examples/AnalogFirmata/AnalogFirmata.ino +++ b/libraries/Firmata/examples/AnalogFirmata/AnalogFirmata.ino @@ -1,3 +1,14 @@ +/* + * Firmata is a generic protocol for communicating with microcontrollers + * from software on a host computer. It is intended to work with + * any host computer software package. + * + * To download a host software package, please clink on the following link + * to open the download page in your default browser. + * + * http://firmata.org/wiki/Download + */ + /* This firmware supports as many analog ports as possible, all analog inputs, * four PWM outputs, and two with servo support. * diff --git a/libraries/Firmata/examples/EchoString/EchoString.ino b/libraries/Firmata/examples/EchoString/EchoString.ino index e708ec210..5079697a5 100644 --- a/libraries/Firmata/examples/EchoString/EchoString.ino +++ b/libraries/Firmata/examples/EchoString/EchoString.ino @@ -1,3 +1,14 @@ +/* + * Firmata is a generic protocol for communicating with microcontrollers + * from software on a host computer. It is intended to work with + * any host computer software package. + * + * To download a host software package, please clink on the following link + * to open the download page in your default browser. + * + * http://firmata.org/wiki/Download + */ + /* This sketch accepts strings and raw sysex messages and echos them back. * * This example code is in the public domain. diff --git a/libraries/Firmata/examples/I2CFirmata/I2CFirmata.ino b/libraries/Firmata/examples/I2CFirmata/I2CFirmata.ino index f2c931b95..1da8963a0 100644 --- a/libraries/Firmata/examples/I2CFirmata/I2CFirmata.ino +++ b/libraries/Firmata/examples/I2CFirmata/I2CFirmata.ino @@ -1,3 +1,14 @@ +/* + * Firmata is a generic protocol for communicating with microcontrollers + * from software on a host computer. It is intended to work with + * any host computer software package. + * + * To download a host software package, please clink on the following link + * to open the download page in your default browser. + * + * http://firmata.org/wiki/Download + */ + /* Copyright (C) 2009 Jeff Hoefs. All rights reserved. Copyright (C) 2009 Shigeru Kobayashi. All rights reserved. diff --git a/libraries/Firmata/examples/OldStandardFirmata/OldStandardFirmata.ino b/libraries/Firmata/examples/OldStandardFirmata/OldStandardFirmata.ino index 56a47acd4..d306c70d7 100644 --- a/libraries/Firmata/examples/OldStandardFirmata/OldStandardFirmata.ino +++ b/libraries/Firmata/examples/OldStandardFirmata/OldStandardFirmata.ino @@ -1,3 +1,14 @@ +/* + * Firmata is a generic protocol for communicating with microcontrollers + * from software on a host computer. It is intended to work with + * any host computer software package. + * + * To download a host software package, please clink on the following link + * to open the download page in your default browser. + * + * http://firmata.org/wiki/Download + */ + /* Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights reserved. diff --git a/libraries/Firmata/examples/ServoFirmata/ServoFirmata.ino b/libraries/Firmata/examples/ServoFirmata/ServoFirmata.ino index 6f78ccd32..cdcfff04d 100644 --- a/libraries/Firmata/examples/ServoFirmata/ServoFirmata.ino +++ b/libraries/Firmata/examples/ServoFirmata/ServoFirmata.ino @@ -1,3 +1,14 @@ +/* + * Firmata is a generic protocol for communicating with microcontrollers + * from software on a host computer. It is intended to work with + * any host computer software package. + * + * To download a host software package, please clink on the following link + * to open the download page in your default browser. + * + * http://firmata.org/wiki/Download + */ + /* This firmware supports as many servos as possible using the Servo library * included in Arduino 0017 * diff --git a/libraries/Firmata/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.ino b/libraries/Firmata/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.ino index b505b3391..44ea91eea 100644 --- a/libraries/Firmata/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.ino +++ b/libraries/Firmata/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.ino @@ -1,3 +1,14 @@ +/* + * Firmata is a generic protocol for communicating with microcontrollers + * from software on a host computer. It is intended to work with + * any host computer software package. + * + * To download a host software package, please clink on the following link + * to open the download page in your default browser. + * + * http://firmata.org/wiki/Download + */ + /* Supports as many analog inputs and analog PWM outputs as possible. * * This example code is in the public domain. diff --git a/libraries/Firmata/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.ino b/libraries/Firmata/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.ino index bbe42ed8d..a0d764f72 100644 --- a/libraries/Firmata/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.ino +++ b/libraries/Firmata/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.ino @@ -1,3 +1,14 @@ +/* + * Firmata is a generic protocol for communicating with microcontrollers + * from software on a host computer. It is intended to work with + * any host computer software package. + * + * To download a host software package, please clink on the following link + * to open the download page in your default browser. + * + * http://firmata.org/wiki/Download + */ + /* Supports as many digital inputs and outputs as possible. * * This example code is in the public domain. diff --git a/libraries/Firmata/examples/StandardFirmata/StandardFirmata.ino b/libraries/Firmata/examples/StandardFirmata/StandardFirmata.ino index 51f090c31..1a987eebb 100644 --- a/libraries/Firmata/examples/StandardFirmata/StandardFirmata.ino +++ b/libraries/Firmata/examples/StandardFirmata/StandardFirmata.ino @@ -1,5 +1,19 @@ +/* + * Firmata is a generic protocol for communicating with microcontrollers + * from software on a host computer. It is intended to work with + * any host computer software package. + * + * To download a host software package, please clink on the following link + * to open the download page in your default browser. + * + * http://firmata.org/wiki/Download + */ + /* Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights reserved. + Copyright (C) 2010-2011 Paul Stoffregen. All rights reserved. + Copyright (C) 2009 Shigeru Kobayashi. All rights reserved. + Copyright (C) 2009-2011 Jeff Hoefs. 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 @@ -16,8 +30,22 @@ */ #include +#include #include +// move the following defines to 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 I2C_10BIT_ADDRESS_MODE_MASK B00100000 + +#define MAX_QUERIES 8 +#define MINIMUM_SAMPLING_INTERVAL 10 + +#define REGISTER_NOT_SPECIFIED -1 + /*============================================================================== * GLOBAL VARIABLES *============================================================================*/ @@ -39,12 +67,69 @@ unsigned long currentMillis; // store the current value from millis() unsigned long previousMillis; // for comparison with currentMillis int samplingInterval = 19; // how often to run the main loop (in ms) -Servo servos[MAX_SERVOS]; +/* i2c data */ +struct i2c_device_info { + byte addr; + byte reg; + byte bytes; +}; +/* for i2c read continuous more */ +i2c_device_info query[MAX_QUERIES]; + +byte i2cRxData[32]; +boolean isI2CEnabled = false; +signed char queryIndex = -1; +unsigned int i2cReadDelayTime = 0; // default delay time between i2c read request and Wire.requestFrom() + +Servo servos[MAX_SERVOS]; /*============================================================================== * FUNCTIONS *============================================================================*/ +void readAndReportData(byte address, int theRegister, byte numBytes) { + // allow I2C requests that don't require a register read + // for example, some devices using an interrupt pin to signify new data available + // do not always require the register read so upon interrupt you call Wire.requestFrom() + if (theRegister != REGISTER_NOT_SPECIFIED) { + Wire.beginTransmission(address); + #if ARDUINO >= 100 + Wire.write((byte)theRegister); + #else + Wire.send((byte)theRegister); + #endif + 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); // all bytes are returned in requestFrom + + // 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++) { + #if ARDUINO >= 100 + i2cRxData[2 + i] = Wire.read(); + #else + i2cRxData[2 + i] = Wire.receive(); + #endif + } + } + else { + if(numBytes > Wire.available()) { + Firmata.sendString("I2C Read Error: Too many bytes received"); + } else { + Firmata.sendString("I2C Read Error: Too few bytes received"); + } + } + + // send slave address, register and received bytes + Firmata.sendSysex(SYSEX_I2C_REPLY, numBytes + 2, i2cRxData); +} + void outputPort(byte portNumber, byte portValue, byte forceSend) { // pins not configured as INPUT are cleared to zeros @@ -88,6 +173,11 @@ void checkDigitalInputs(void) */ void setPinModeCallback(byte pin, int mode) { + if (pinConfig[pin] == I2C && isI2CEnabled && mode != I2C) { + // disable i2c so pins can be used for other functions + // the following if statements should reconfigure the pins properly + disableI2CPins(); + } if (IS_PIN_SERVO(pin) && mode != SERVO && servos[PIN_TO_SERVO(pin)].attached()) { servos[PIN_TO_SERVO(pin)].detach(); } @@ -138,14 +228,15 @@ void setPinModeCallback(byte pin, int mode) pinConfig[pin] = SERVO; if (!servos[PIN_TO_SERVO(pin)].attached()) { servos[PIN_TO_SERVO(pin)].attach(PIN_TO_DIGITAL(pin)); - } else { - Firmata.sendString("Servo only on pins from 2 to 13"); } } break; case I2C: - pinConfig[pin] = mode; - Firmata.sendString("I2C mode not yet supported"); + if (IS_PIN_I2C(pin)) { + // mark the pin as i2c + // the user must call I2C_CONFIG to enable I2C for a device + pinConfig[pin] = I2C; + } break; default: Firmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM @@ -232,7 +323,104 @@ void reportDigitalCallback(byte port, int value) void sysexCallback(byte command, byte argc, byte *argv) { + byte mode; + byte slaveAddress; + byte slaveRegister; + byte data; + unsigned int delayTime; + switch(command) { + case I2C_REQUEST: + mode = argv[1] & I2C_READ_WRITE_MODE_MASK; + if (argv[1] & I2C_10BIT_ADDRESS_MODE_MASK) { + Firmata.sendString("10-bit addressing mode is not yet supported"); + return; + } + else { + 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); + #if ARDUINO >= 100 + Wire.write(data); + #else + Wire.send(data); + #endif + } + Wire.endTransmission(); + delayMicroseconds(70); + 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; + } + queryIndex++; + query[queryIndex].addr = slaveAddress; + query[queryIndex].reg = argv[2] + (argv[3] << 7); + query[queryIndex].bytes = argv[4] + (argv[5] << 7); + break; + case I2C_STOP_READING: + byte queryIndexToSkip; + // if read continuous mode is enabled for only 1 i2c device, disable + // read continuous reporting for that device + if (queryIndex <= 0) { + queryIndex = -1; + } else { + // if read continuous mode is enabled for multiple devices, + // determine which device to stop reading and remove it's data from + // the array, shifiting other array data to fill the space + for (byte i = 0; i < queryIndex + 1; i++) { + if (query[i].addr = slaveAddress) { + queryIndexToSkip = i; + break; + } + } + + for (byte i = queryIndexToSkip; i 0) { + i2cReadDelayTime = delayTime; + } + + if (!isI2CEnabled) { + enableI2CPins(); + } + + break; case SERVO_CONFIG: if(argc > 4) { // these vars are here for clarity, they'll optimized away by the compiler @@ -241,7 +429,6 @@ void sysexCallback(byte command, byte argc, byte *argv) int maxPulse = argv[3] + (argv[4] << 7); if (IS_PIN_SERVO(pin)) { - // servos are pins from 2 to 13, so offset for array if (servos[PIN_TO_SERVO(pin)].attached()) servos[PIN_TO_SERVO(pin)].detach(); servos[PIN_TO_SERVO(pin)].attach(PIN_TO_DIGITAL(pin), minPulse, maxPulse); @@ -250,10 +437,14 @@ void sysexCallback(byte command, byte argc, byte *argv) } break; case SAMPLING_INTERVAL: - if (argc > 1) + if (argc > 1) { samplingInterval = argv[0] + (argv[1] << 7); - else - Firmata.sendString("Not enough data"); + if (samplingInterval < MINIMUM_SAMPLING_INTERVAL) { + samplingInterval = MINIMUM_SAMPLING_INTERVAL; + } + } else { + //Firmata.sendString("Not enough data"); + } break; case EXTENDED_ANALOG: if (argc > 1) { @@ -285,6 +476,10 @@ void sysexCallback(byte command, byte argc, byte *argv) Serial.write(SERVO); Serial.write(14); } + if (IS_PIN_I2C(pin)) { + Serial.write(I2C); + Serial.write(1); // to do: determine appropriate value + } Serial.write(127); } Serial.write(END_SYSEX); @@ -315,33 +510,52 @@ void sysexCallback(byte command, byte argc, byte *argv) } } +void enableI2CPins() +{ + byte i; + // is there a faster way to do this? would probaby require importing + // Arduino.h to get SCL and SDA pins + for (i=0; i < TOTAL_PINS; i++) { + if(IS_PIN_I2C(i)) { + // mark pins as i2c so they are ignore in non i2c data requests + setPinModeCallback(i, I2C); + } + } + + isI2CEnabled = true; + + // is there enough time before the first I2C request to call this here? + Wire.begin(); +} + +/* disable the i2c pins so they can be used for other functions */ +void disableI2CPins() { + isI2CEnabled = false; + // disable read continuous mode for all devices + queryIndex = -1; + // uncomment the following if or when the end() method is added to Wire library + // Wire.end(); +} /*============================================================================== * SETUP() *============================================================================*/ -void setup() + +void systemResetCallback() { - byte i; - - Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); - - 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); - - // TODO: load state from EEPROM here - - /* these are initialized to zero by the compiler startup code - for (i=0; i < TOTAL_PORTS; i++) { - reportPINs[i] = false; - portConfigInputs[i] = 0; + // initialize a defalt state + // TODO: option to load config from EEPROM instead of default + if (isI2CEnabled) { + disableI2CPins(); + } + for (byte i=0; i < TOTAL_PORTS; i++) { + reportPINs[i] = false; // by default, reporting off + portConfigInputs[i] = 0; // until activated previousPINs[i] = 0; } - */ - for (i=0; i < TOTAL_PINS; i++) { + // pins with analog capability default to analog input + // otherwise, pins default to digital output + for (byte i=0; i < TOTAL_PINS; i++) { if (IS_PIN_ANALOG(i)) { // turns off pullup, configures everything setPinModeCallback(i, ANALOG); @@ -350,16 +564,34 @@ void setup() setPinModeCallback(i, OUTPUT); } } - // by defult, do not report any analog inputs + // by default, do not report any analog inputs analogInputsToReport = 0; - Firmata.begin(57600); - /* send digital inputs to set the initial state on the host computer, * since once in the loop(), this firmware will only send on change */ - for (i=0; i < TOTAL_PORTS; i++) { + /* + TODO: this can never execute, since no pins default to digital input + but it will be needed when/if we support EEPROM stored config + for (byte i=0; i < TOTAL_PORTS; i++) { outputPort(i, readPort(i, portConfigInputs[i]), true); } + */ +} + +void setup() +{ + Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); + + 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); + Firmata.attach(SYSTEM_RESET, systemResetCallback); + + Firmata.begin(57600); + systemResetCallback(); // reset to default config } /*============================================================================== @@ -394,5 +626,11 @@ void loop() } } } + // report i2c data for all device with read continuous mode enabled + if (queryIndex > -1) { + for (byte i = 0; i < queryIndex + 1; i++) { + readAndReportData(query[i].addr, query[i].reg, query[i].bytes); + } + } } }