1
0
mirror of https://github.com/arduino/Arduino.git synced 2024-12-02 13:24:12 +01:00

Updating to Firmata r82 (e.g. including I2C in StandardFirmata).

http://code.google.com/p/arduino/issues/detail?id=633
This commit is contained in:
David A. Mellis 2011-09-09 17:11:42 -04:00
parent 5ba38fa9bd
commit b722028c7b
11 changed files with 377 additions and 49 deletions

View File

@ -124,6 +124,10 @@ writePort(port, value, bitmask): Write an 8 bit port.
* Board Specific Configuration * Board Specific Configuration
*============================================================================*/ *============================================================================*/
#ifndef digitalPinHasPWM
#define digitalPinHasPWM(p) IS_PIN_DIGITAL(p)
#endif
// Arduino Duemilanove, Diecimila, and NG // Arduino Duemilanove, Diecimila, and NG
#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__)
#if defined(NUM_ANALOG_INPUTS) && NUM_ANALOG_INPUTS == 6 #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 VERSION_BLINK_PIN 13
#define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) <= 19) #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) <= 19)
#define IS_PIN_ANALOG(p) ((p) >= 14 && (p) < 14 + TOTAL_ANALOG_PINS) #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_SERVO(p) (IS_PIN_DIGITAL(p) && (p) - 2 < MAX_SERVOS)
#define IS_PIN_I2C(p) ((p) == 18 || (p) == 19) #define IS_PIN_I2C(p) ((p) == 18 || (p) == 19)
#define PIN_TO_DIGITAL(p) (p) #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 VERSION_BLINK_PIN WLED
#define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS) #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_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_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS)
#define IS_PIN_I2C(p) ((p) == SDA || (p) == SCL) #define IS_PIN_I2C(p) ((p) == SDA || (p) == SCL)
#define PIN_TO_DIGITAL(p) (p) #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 VERSION_BLINK_PIN 13
#define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) <= 19) #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) <= 19)
#define IS_PIN_ANALOG(p) ((p) >= 14 && (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_SERVO(p) (IS_PIN_DIGITAL(p) && (p) - 2 < MAX_SERVOS)
#define IS_PIN_I2C(p) ((p) == 18 || (p) == 19) #define IS_PIN_I2C(p) ((p) == 18 || (p) == 19)
#define PIN_TO_DIGITAL(p) (p) #define PIN_TO_DIGITAL(p) (p)
@ -178,13 +182,13 @@ writePort(port, value, bitmask): Write an 8 bit port.
// Arduino Mega // Arduino Mega
#elif defined(__AVR_ATmega1280__) #elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
#define TOTAL_ANALOG_PINS 16 #define TOTAL_ANALOG_PINS 16
#define TOTAL_PINS 70 // 54 digital + 16 analog #define TOTAL_PINS 70 // 54 digital + 16 analog
#define VERSION_BLINK_PIN 13 #define VERSION_BLINK_PIN 13
#define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < TOTAL_PINS) #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < TOTAL_PINS)
#define IS_PIN_ANALOG(p) ((p) >= 54 && (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_SERVO(p) ((p) >= 2 && (p) - 2 < MAX_SERVOS)
#define IS_PIN_I2C(p) ((p) == 20 || (p) == 21) #define IS_PIN_I2C(p) ((p) == 20 || (p) == 21)
#define PIN_TO_DIGITAL(p) (p) #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 VERSION_BLINK_PIN 6
#define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS) #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS)
#define IS_PIN_ANALOG(p) (0) #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_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS)
#define IS_PIN_I2C(p) (0) #define IS_PIN_I2C(p) (0)
#define PIN_TO_DIGITAL(p) (p) #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 VERSION_BLINK_PIN 11
#define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS) #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS)
#define IS_PIN_ANALOG(p) ((p) >= 11 && (p) <= 22) #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_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS)
#define IS_PIN_I2C(p) ((p) == 5 || (p) == 6) #define IS_PIN_I2C(p) ((p) == 5 || (p) == 6)
#define PIN_TO_DIGITAL(p) (p) #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 VERSION_BLINK_PIN 6
#define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS) #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS)
#define IS_PIN_ANALOG(p) ((p) >= 38 && (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_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS)
#define IS_PIN_I2C(p) ((p) == 0 || (p) == 1) #define IS_PIN_I2C(p) ((p) == 0 || (p) == 1)
#define PIN_TO_DIGITAL(p) (p) #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 VERSION_BLINK_PIN 0
#define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < TOTAL_PINS) #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < TOTAL_PINS)
#define IS_PIN_ANALOG(p) ((p) >= 24 && (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_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS)
#define IS_PIN_I2C(p) ((p) == 16 || (p) == 17) #define IS_PIN_I2C(p) ((p) == 16 || (p) == 17)
#define PIN_TO_DIGITAL(p) (p) #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 VERSION_BLINK_PIN 13
#define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < TOTAL_PINS) #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < TOTAL_PINS)
#define IS_PIN_ANALOG(p) ((p) >= 36 && (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_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS)
#define IS_PIN_I2C(p) ((p) == 4 || (p) == 5) #define IS_PIN_I2C(p) ((p) == 4 || (p) == 5)
#define PIN_TO_DIGITAL(p) (p) #define PIN_TO_DIGITAL(p) (p)

View File

@ -68,7 +68,6 @@ void FirmataClass::begin(long speed)
Serial.begin(speed); Serial.begin(speed);
FirmataSerial = Serial; FirmataSerial = Serial;
blinkVersion(); blinkVersion();
delay(300);
printVersion(); printVersion();
printFirmwareVersion(); printFirmwareVersion();
} }
@ -92,11 +91,10 @@ void FirmataClass::blinkVersion(void)
{ {
// flash the pin with the protocol version // flash the pin with the protocol version
pinMode(VERSION_BLINK_PIN,OUTPUT); pinMode(VERSION_BLINK_PIN,OUTPUT);
pin13strobe(FIRMATA_MAJOR_VERSION, 200, 400); pin13strobe(FIRMATA_MAJOR_VERSION, 40, 210);
delay(300); delay(250);
pin13strobe(2,1,4); // separator, a quick burst pin13strobe(FIRMATA_MINOR_VERSION, 40, 210);
delay(300); delay(125);
pin13strobe(FIRMATA_MINOR_VERSION, 200, 400);
} }
void FirmataClass::printFirmwareVersion(void) void FirmataClass::printFirmwareVersion(void)

View File

@ -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 * 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. * inspired by the ease-of-use of the Arduino2Max program.

View File

@ -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, /* This firmware supports as many analog ports as possible, all analog inputs,
* four PWM outputs, and two with servo support. * four PWM outputs, and two with servo support.
* *

View File

@ -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 sketch accepts strings and raw sysex messages and echos them back.
* *
* This example code is in the public domain. * This example code is in the public domain.

View File

@ -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 Jeff Hoefs. All rights reserved.
Copyright (C) 2009 Shigeru Kobayashi. All rights reserved. Copyright (C) 2009 Shigeru Kobayashi. All rights reserved.

View File

@ -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. Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights reserved.

View File

@ -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 /* This firmware supports as many servos as possible using the Servo library
* included in Arduino 0017 * included in Arduino 0017
* *

View File

@ -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. /* Supports as many analog inputs and analog PWM outputs as possible.
* *
* This example code is in the public domain. * This example code is in the public domain.

View File

@ -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. /* Supports as many digital inputs and outputs as possible.
* *
* This example code is in the public domain. * This example code is in the public domain.

View File

@ -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) 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 This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public modify it under the terms of the GNU Lesser General Public
@ -16,8 +30,22 @@
*/ */
#include <Servo.h> #include <Servo.h>
#include <Wire.h>
#include <Firmata.h> #include <Firmata.h>
// 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 * GLOBAL VARIABLES
*============================================================================*/ *============================================================================*/
@ -39,12 +67,69 @@ unsigned long currentMillis; // store the current value from millis()
unsigned long previousMillis; // for comparison with currentMillis unsigned long previousMillis; // for comparison with currentMillis
int samplingInterval = 19; // how often to run the main loop (in ms) 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 * 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) void outputPort(byte portNumber, byte portValue, byte forceSend)
{ {
// pins not configured as INPUT are cleared to zeros // pins not configured as INPUT are cleared to zeros
@ -88,6 +173,11 @@ void checkDigitalInputs(void)
*/ */
void setPinModeCallback(byte pin, int mode) 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()) { if (IS_PIN_SERVO(pin) && mode != SERVO && servos[PIN_TO_SERVO(pin)].attached()) {
servos[PIN_TO_SERVO(pin)].detach(); servos[PIN_TO_SERVO(pin)].detach();
} }
@ -138,14 +228,15 @@ void setPinModeCallback(byte pin, int mode)
pinConfig[pin] = SERVO; pinConfig[pin] = SERVO;
if (!servos[PIN_TO_SERVO(pin)].attached()) { if (!servos[PIN_TO_SERVO(pin)].attached()) {
servos[PIN_TO_SERVO(pin)].attach(PIN_TO_DIGITAL(pin)); servos[PIN_TO_SERVO(pin)].attach(PIN_TO_DIGITAL(pin));
} else {
Firmata.sendString("Servo only on pins from 2 to 13");
} }
} }
break; break;
case I2C: case I2C:
pinConfig[pin] = mode; if (IS_PIN_I2C(pin)) {
Firmata.sendString("I2C mode not yet supported"); // mark the pin as i2c
// the user must call I2C_CONFIG to enable I2C for a device
pinConfig[pin] = I2C;
}
break; break;
default: default:
Firmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM 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) void sysexCallback(byte command, byte argc, byte *argv)
{ {
byte mode;
byte slaveAddress;
byte slaveRegister;
byte data;
unsigned int delayTime;
switch(command) { 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<queryIndex + 1; i++) {
if (i < MAX_QUERIES) {
query[i].addr = query[i+1].addr;
query[i].reg = query[i+1].addr;
query[i].bytes = query[i+1].bytes;
}
}
queryIndex--;
}
break;
default:
break;
}
break;
case I2C_CONFIG:
delayTime = (argv[0] + (argv[1] << 7));
if(delayTime > 0) {
i2cReadDelayTime = delayTime;
}
if (!isI2CEnabled) {
enableI2CPins();
}
break;
case SERVO_CONFIG: case SERVO_CONFIG:
if(argc > 4) { if(argc > 4) {
// these vars are here for clarity, they'll optimized away by the compiler // 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); int maxPulse = argv[3] + (argv[4] << 7);
if (IS_PIN_SERVO(pin)) { if (IS_PIN_SERVO(pin)) {
// servos are pins from 2 to 13, so offset for array
if (servos[PIN_TO_SERVO(pin)].attached()) if (servos[PIN_TO_SERVO(pin)].attached())
servos[PIN_TO_SERVO(pin)].detach(); servos[PIN_TO_SERVO(pin)].detach();
servos[PIN_TO_SERVO(pin)].attach(PIN_TO_DIGITAL(pin), minPulse, maxPulse); 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; break;
case SAMPLING_INTERVAL: case SAMPLING_INTERVAL:
if (argc > 1) if (argc > 1) {
samplingInterval = argv[0] + (argv[1] << 7); samplingInterval = argv[0] + (argv[1] << 7);
else if (samplingInterval < MINIMUM_SAMPLING_INTERVAL) {
Firmata.sendString("Not enough data"); samplingInterval = MINIMUM_SAMPLING_INTERVAL;
}
} else {
//Firmata.sendString("Not enough data");
}
break; break;
case EXTENDED_ANALOG: case EXTENDED_ANALOG:
if (argc > 1) { if (argc > 1) {
@ -285,6 +476,10 @@ void sysexCallback(byte command, byte argc, byte *argv)
Serial.write(SERVO); Serial.write(SERVO);
Serial.write(14); Serial.write(14);
} }
if (IS_PIN_I2C(pin)) {
Serial.write(I2C);
Serial.write(1); // to do: determine appropriate value
}
Serial.write(127); Serial.write(127);
} }
Serial.write(END_SYSEX); 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() * SETUP()
*============================================================================*/ *============================================================================*/
void setup()
void systemResetCallback()
{ {
byte i; // initialize a defalt state
// TODO: option to load config from EEPROM instead of default
Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); if (isI2CEnabled) {
disableI2CPins();
Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); }
Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback); for (byte i=0; i < TOTAL_PORTS; i++) {
Firmata.attach(REPORT_ANALOG, reportAnalogCallback); reportPINs[i] = false; // by default, reporting off
Firmata.attach(REPORT_DIGITAL, reportDigitalCallback); portConfigInputs[i] = 0; // until activated
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;
previousPINs[i] = 0; previousPINs[i] = 0;
} }
*/ // pins with analog capability default to analog input
for (i=0; i < TOTAL_PINS; i++) { // otherwise, pins default to digital output
for (byte i=0; i < TOTAL_PINS; i++) {
if (IS_PIN_ANALOG(i)) { if (IS_PIN_ANALOG(i)) {
// turns off pullup, configures everything // turns off pullup, configures everything
setPinModeCallback(i, ANALOG); setPinModeCallback(i, ANALOG);
@ -350,16 +564,34 @@ void setup()
setPinModeCallback(i, OUTPUT); setPinModeCallback(i, OUTPUT);
} }
} }
// by defult, do not report any analog inputs // by default, do not report any analog inputs
analogInputsToReport = 0; analogInputsToReport = 0;
Firmata.begin(57600);
/* send digital inputs to set the initial state on the host computer, /* send digital inputs to set the initial state on the host computer,
* since once in the loop(), this firmware will only send on change */ * 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); 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);
}
}
} }
} }