aboutsummaryrefslogtreecommitdiff
path: root/libraries/Firmata
diff options
context:
space:
mode:
authorDavid A. Mellis <d.mellis@arduino.cc>2009-08-15 14:48:42 +0000
committerDavid A. Mellis <d.mellis@arduino.cc>2009-08-15 14:48:42 +0000
commit50f77c7210a490d8fee28348fcda811ca0bdf615 (patch)
treec5ed76441bcdd7c51b6bf07d7b0ba16444dbaee6 /libraries/Firmata
parent159051b8f814edb7474912ad6d04058d34f2d173 (diff)
parent79b7ecdd92973f4aa67a6bcaa8bd12a10e5b5133 (diff)
Moving the processing-5503 branch (used for Arduino 0017) into the trunk.
Diffstat (limited to 'libraries/Firmata')
-rw-r--r--libraries/Firmata/Firmata.cpp466
-rw-r--r--libraries/Firmata/Firmata.h72
-rw-r--r--libraries/Firmata/examples/AnalogFirmata/AnalogFirmata.pde2
-rw-r--r--libraries/Firmata/examples/EchoString/EchoString.pde4
-rw-r--r--libraries/Firmata/examples/I2CFirmata/I2CFirmata.pde217
-rw-r--r--libraries/Firmata/examples/ServoFirmata/ServoFirmata.pde2
-rw-r--r--libraries/Firmata/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.pde2
-rw-r--r--libraries/Firmata/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.pde2
-rw-r--r--libraries/Firmata/examples/StandardFirmata/Makefile26
-rw-r--r--libraries/Firmata/examples/StandardFirmata/StandardFirmata.pde313
10 files changed, 731 insertions, 375 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..2732fd6 100644
--- a/libraries/Firmata/Firmata.h
+++ b/libraries/Firmata/Firmata.h
@@ -22,8 +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 VERSION_BLINK_PIN 13 // digital pin to blink version on
+#define FIRMATA_MINOR_VERSION 1 // for backwards compatible changes
#define MAX_DATA_BYTES 32 // max number of data bytes in non-Sysex messages
@@ -42,12 +41,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 +64,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
@@ -146,21 +156,71 @@ extern FirmataClass Firmata;
#define TOTAL_DIGITAL_PINS 22 // 14 digital + 8 analog
#define TOTAL_PORTS 3 // total number of ports for the board
#define ANALOG_PORT 2 // port# of analog used as digital
+#define FIRST_ANALOG_PIN 14 // pin# corresponding to analog 0
+#define VERSION_BLINK_PIN 13 // digital pin to blink version on
#elif defined(__AVR_ATmega8__) // old Arduinos
#define TOTAL_ANALOG_PINS 6
#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
+#define FIRST_ANALOG_PIN 14 // pin# corresponding to analog 0
+#define VERSION_BLINK_PIN 13 // digital pin to blink version on
+#elif defined(__AVR_ATmega1280__)// Arduino Mega
+#define TOTAL_ANALOG_PINS 16
+#define TOTAL_DIGITAL_PINS 70 // 54 digital + 16 analog
+#define TOTAL_PORTS 9 // total number of ports for the board
+#define ANALOG_PORT 8 // port# of analog used as digital
+#define FIRST_ANALOG_PIN 54 // pin# corresponding to analog 0
+#define VERSION_BLINK_PIN 13 // digital pin to blink version on
#elif defined(__AVR_ATmega128__)// Wiring
#define TOTAL_ANALOG_PINS 8
#define TOTAL_DIGITAL_PINS 51
+#define TOTAL_PORTS 7 // total number of ports for the board
+#define ANALOG_PORT 5 // port# of analog used as digital
+#define FIRST_ANALOG_PIN 40 // pin# corresponding to analog 0
+#define VERSION_BLINK_PIN 13 // digital pin to blink version on
+#elif defined(__AVR_AT90USB162__) // Teensy
+#define TOTAL_ANALOG_PINS 0
+#define TOTAL_DIGITAL_PINS 21 // 21 digital + no analog
+#define TOTAL_PORTS 4 // total number of ports for the board
+#define ANALOG_PORT 3 // port# of analog used as digital
+#define FIRST_ANALOG_PIN 21 // pin# corresponding to analog 0
+#define VERSION_BLINK_PIN 6 // digital pin to blink version on
+#elif defined(__AVR_ATmega32U4__) // Teensy
+#define TOTAL_ANALOG_PINS 12
+#define TOTAL_DIGITAL_PINS 25 // 11 digital + 12 analog
+#define TOTAL_PORTS 4 // total number of ports for the board
+#define ANALOG_PORT 3 // port# of analog used as digital
+#define FIRST_ANALOG_PIN 11 // pin# corresponding to analog 0
+#define VERSION_BLINK_PIN 11 // digital pin to blink version on
+#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) // Teensy++
+#define TOTAL_ANALOG_PINS 8
+#define TOTAL_DIGITAL_PINS 46 // 38 digital + 8 analog
#define TOTAL_PORTS 6 // total number of ports for the board
-#define ANALOG_PORT 2 // port# of analog used as digital
+#define ANALOG_PORT 5 // port# of analog used as digital
+#define FIRST_ANALOG_PIN 38 // pin# corresponding to analog 0
+#define VERSION_BLINK_PIN 6 // digital pin to blink version on
+#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__) // Sanguino
+#define TOTAL_ANALOG_PINS 8
+#define TOTAL_DIGITAL_PINS 32 // 24 digital + 8 analog
+#define TOTAL_PORTS 4 // total number of ports for the board
+#define ANALOG_PORT 3 // port# of analog used as digital
+#define FIRST_ANALOG_PIN 24 // pin# corresponding to analog 0
+#define VERSION_BLINK_PIN 0 // digital pin to blink version on
+#elif defined(__AVR_ATmega645__) // Illuminato
+#define TOTAL_ANALOG_PINS 6
+#define TOTAL_DIGITAL_PINS 42 // 36 digital + 6 analog
+#define TOTAL_PORTS 6 // total number of ports for the board
+#define ANALOG_PORT 4 // port# of analog used as digital
+#define FIRST_ANALOG_PIN 36 // pin# corresponding to analog 0
+#define VERSION_BLINK_PIN 13 // digital pin to blink version on
#else // anything else
#define TOTAL_ANALOG_PINS 6
#define TOTAL_DIGITAL_PINS 14
#define TOTAL_PORTS 3 // total number of ports for the board
#define ANALOG_PORT 2 // port# of analog used as digital
+#define FIRST_ANALOG_PIN 14 // pin# corresponding to analog 0
+#define VERSION_BLINK_PIN 13 // digital pin to blink version on
#endif
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..796a8d5
--- /dev/null
+++ b/libraries/Firmata/examples/I2CFirmata/I2CFirmata.pde
@@ -0,0 +1,217 @@
+/*
+ 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(PORTC3, PORTC2);
+ }
+
+ 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);
+ }
+
+ Firmata.begin(57600);
+ 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..16c8b87 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,88 @@ 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)
+ if(pin > 13)
+ 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 +174,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 +268,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));
+ }
}
+ }
}