Updating to Firmata-2.1beta1 (rev 23).

This commit is contained in:
David A. Mellis 2009-07-14 21:32:55 +00:00
parent 17dd739777
commit 3f5220e454
10 changed files with 683 additions and 369 deletions

View File

@ -29,18 +29,18 @@ extern "C" {
void sendValueAsTwo7bitBytes(int value) void sendValueAsTwo7bitBytes(int value)
{ {
Serial.print(value & B01111111, BYTE); // LSB Serial.print(value & B01111111, BYTE); // LSB
Serial.print(value >> 7 & B01111111, BYTE); // MSB Serial.print(value >> 7 & B01111111, BYTE); // MSB
} }
void startSysex(void) void startSysex(void)
{ {
Serial.print(START_SYSEX, BYTE); Serial.print(START_SYSEX, BYTE);
} }
void endSysex(void) void endSysex(void)
{ {
Serial.print(END_SYSEX, BYTE); Serial.print(END_SYSEX, BYTE);
} }
//****************************************************************************** //******************************************************************************
@ -49,8 +49,8 @@ void endSysex(void)
FirmataClass::FirmataClass(void) FirmataClass::FirmataClass(void)
{ {
firmwareVersionCount = 0; firmwareVersionCount = 0;
systemReset(); systemReset();
} }
//****************************************************************************** //******************************************************************************
@ -60,83 +60,83 @@ FirmataClass::FirmataClass(void)
/* begin method for overriding default serial bitrate */ /* begin method for overriding default serial bitrate */
void FirmataClass::begin(void) void FirmataClass::begin(void)
{ {
Serial.begin(115200); Serial.begin(57600);
blinkVersion(); blinkVersion();
delay(300); delay(300);
printVersion(); printVersion();
} }
/* begin method for overriding default serial bitrate */ /* begin method for overriding default serial bitrate */
void FirmataClass::begin(long speed) void FirmataClass::begin(long speed)
{ {
blinkVersion(); blinkVersion();
#if defined(__AVR_ATmega128__) // Wiring #if defined(__AVR_ATmega128__) // Wiring
Serial.begin((uint32_t)speed); Serial.begin((uint32_t)speed);
#else #else
Serial.begin(speed); Serial.begin(speed);
#endif #endif
delay(300); delay(300);
printVersion(); printVersion();
printFirmwareVersion(); printFirmwareVersion();
} }
// output the protocol version message to the serial port // output the protocol version message to the serial port
void FirmataClass::printVersion(void) { void FirmataClass::printVersion(void) {
Serial.print(REPORT_VERSION, BYTE); Serial.print(REPORT_VERSION, BYTE);
Serial.print(FIRMATA_MAJOR_VERSION, BYTE); Serial.print(FIRMATA_MAJOR_VERSION, BYTE);
Serial.print(FIRMATA_MINOR_VERSION, BYTE); Serial.print(FIRMATA_MINOR_VERSION, BYTE);
} }
void FirmataClass::blinkVersion(void) 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, 200, 400);
delay(300); delay(300);
pin13strobe(2,1,4); // separator, a quick burst pin13strobe(2,1,4); // separator, a quick burst
delay(300); delay(300);
pin13strobe(FIRMATA_MINOR_VERSION, 200, 400); pin13strobe(FIRMATA_MINOR_VERSION, 200, 400);
} }
void FirmataClass::printFirmwareVersion(void) void FirmataClass::printFirmwareVersion(void)
{ {
byte i; byte i;
if(firmwareVersionCount) { // make sure that the name has been set before reporting if(firmwareVersionCount) { // make sure that the name has been set before reporting
startSysex(); startSysex();
Serial.print(REPORT_FIRMWARE, BYTE); Serial.print(REPORT_FIRMWARE, BYTE);
Serial.print(firmwareVersionVector[0]); // major version number Serial.print(firmwareVersionVector[0]); // major version number
Serial.print(firmwareVersionVector[1]); // minor version number Serial.print(firmwareVersionVector[1]); // minor version number
for(i=2; i<firmwareVersionCount; ++i) { for(i=2; i<firmwareVersionCount; ++i) {
sendValueAsTwo7bitBytes(firmwareVersionVector[i]); sendValueAsTwo7bitBytes(firmwareVersionVector[i]);
}
endSysex();
} }
endSysex();
}
} }
void FirmataClass::setFirmwareNameAndVersion(const char *name, byte major, byte minor) void FirmataClass::setFirmwareNameAndVersion(const char *name, byte major, byte minor)
{ {
const char *filename; const char *filename;
char *extension; char *extension;
// parse out ".cpp" and "applet/" that comes from using __FILE__ // parse out ".cpp" and "applet/" that comes from using __FILE__
extension = strstr(name, ".cpp"); extension = strstr(name, ".cpp");
filename = strrchr(name, '/') + 1; //points to slash, +1 gets to start of filename filename = strrchr(name, '/') + 1; //points to slash, +1 gets to start of filename
// add two bytes for version numbers // add two bytes for version numbers
if(extension && filename) { if(extension && filename) {
firmwareVersionCount = extension - filename + 2; firmwareVersionCount = extension - filename + 2;
} else { } else {
firmwareVersionCount = strlen(name) + 2; firmwareVersionCount = strlen(name) + 2;
filename = name; filename = name;
} }
firmwareVersionVector = (byte *) malloc(firmwareVersionCount); firmwareVersionVector = (byte *) malloc(firmwareVersionCount);
firmwareVersionVector[firmwareVersionCount] = 0; firmwareVersionVector[firmwareVersionCount] = 0;
firmwareVersionVector[0] = major; firmwareVersionVector[0] = major;
firmwareVersionVector[1] = minor; firmwareVersionVector[1] = minor;
strncpy((char*)firmwareVersionVector + 2, filename, firmwareVersionCount - 2); strncpy((char*)firmwareVersionVector + 2, filename, firmwareVersionCount - 2);
// alas, no snprintf on Arduino // alas, no snprintf on Arduino
// snprintf(firmwareVersionVector, MAX_DATA_BYTES, "%c%c%s", // snprintf(firmwareVersionVector, MAX_DATA_BYTES, "%c%c%s",
// (char)major, (char)minor, firmwareVersionVector); // (char)major, (char)minor, firmwareVersionVector);
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -144,123 +144,123 @@ void FirmataClass::setFirmwareNameAndVersion(const char *name, byte major, byte
int FirmataClass::available(void) int FirmataClass::available(void)
{ {
return Serial.available(); return Serial.available();
} }
void FirmataClass::processSysexMessage(void) void FirmataClass::processSysexMessage(void)
{ {
switch(storedInputData[0]) { //first byte in buffer is command switch(storedInputData[0]) { //first byte in buffer is command
case REPORT_FIRMWARE: case REPORT_FIRMWARE:
printFirmwareVersion(); printFirmwareVersion();
break; break;
case FIRMATA_STRING: case STRING_DATA:
if(currentStringCallback) { if(currentStringCallback) {
byte bufferLength = (sysexBytesRead - 1) / 2; byte bufferLength = (sysexBytesRead - 1) / 2;
char *buffer = (char*)malloc(bufferLength * sizeof(char)); char *buffer = (char*)malloc(bufferLength * sizeof(char));
byte i = 1; byte i = 1;
byte j = 0; byte j = 0;
while(j < bufferLength) { while(j < bufferLength) {
buffer[j] = (char)storedInputData[i]; buffer[j] = (char)storedInputData[i];
i++; i++;
buffer[j] += (char)(storedInputData[i] << 7); buffer[j] += (char)(storedInputData[i] << 7);
i++; i++;
j++; j++;
} }
(*currentStringCallback)(buffer); (*currentStringCallback)(buffer);
}
break;
default:
if(currentSysexCallback)
(*currentSysexCallback)(storedInputData[0], sysexBytesRead - 1, storedInputData + 1);
} }
break;
default:
if(currentSysexCallback)
(*currentSysexCallback)(storedInputData[0], sysexBytesRead - 1, storedInputData + 1);
}
} }
void FirmataClass::processInput(void) void FirmataClass::processInput(void)
{ {
int inputData = Serial.read(); // this is 'int' to handle -1 when no data int inputData = Serial.read(); // this is 'int' to handle -1 when no data
int command; int command;
// TODO make sure it handles -1 properly // TODO make sure it handles -1 properly
if (parsingSysex) { if (parsingSysex) {
if(inputData == END_SYSEX) { if(inputData == END_SYSEX) {
//stop sysex byte //stop sysex byte
parsingSysex = false; parsingSysex = false;
//fire off handler function //fire off handler function
processSysexMessage(); 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;
}
} else { } else {
// remove channel info from command byte if less than 0xF0 //normal data byte - add to buffer
if(inputData < 0xF0) { storedInputData[sysexBytesRead] = inputData;
command = inputData & 0xF0; sysexBytesRead++;
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;
}
} }
} 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;
}
} 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 // send an analog message
void FirmataClass::sendAnalog(byte pin, int value) void FirmataClass::sendAnalog(byte pin, int value)
{ {
// pin can only be 0-15, so chop higher bits // pin can only be 0-15, so chop higher bits
Serial.print(ANALOG_MESSAGE | (pin & 0xF), BYTE); Serial.print(ANALOG_MESSAGE | (pin & 0xF), BYTE);
sendValueAsTwo7bitBytes(value); sendValueAsTwo7bitBytes(value);
} }
// send a single digital pin in a digital message // send a single digital pin in a digital message
void FirmataClass::sendDigital(byte pin, int value) void FirmataClass::sendDigital(byte pin, int value)
{ {
/* TODO add single pin digital messages to the protocol, this needs to /* 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 * 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 * one bit in the packet. This is complicated by the fact that the
* numbering of the pins will probably differ on Arduino, Wiring, and * 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 * 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 * probably easier to send 8 bit ports for any board with more than 14
* digital pins. * digital pins.
*/ */
// TODO: the digital message should not be sent on the serial port every // 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 // 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 // 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 // before the digital message is sent on the serial port, it should send a
// digital message for each change. // digital message for each change.
// if(value == 0) // if(value == 0)
// sendDigitalPortPair(); // sendDigitalPortPair();
} }
@ -301,33 +301,33 @@ void FirmataClass::sendDigital(byte pin, int value)
// send an 8-bit port in a single digital message (protocol v2) // send an 8-bit port in a single digital message (protocol v2)
void FirmataClass::sendDigitalPort(byte portNumber, int portData) void FirmataClass::sendDigitalPort(byte portNumber, int portData)
{ {
Serial.print(DIGITAL_MESSAGE | (portNumber & 0xF),BYTE); Serial.print(DIGITAL_MESSAGE | (portNumber & 0xF),BYTE);
Serial.print(portData % 128, BYTE); // Tx bits 0-6 Serial.print(portData % 128, BYTE); // Tx bits 0-6
Serial.print(portData >> 7, BYTE); // Tx bits 7-13 Serial.print(portData >> 7, BYTE); // Tx bits 7-13
} }
void FirmataClass::sendSysex(byte command, byte bytec, byte* bytev) void FirmataClass::sendSysex(byte command, byte bytec, byte* bytev)
{ {
byte i; byte i;
startSysex(); startSysex();
Serial.print(command, BYTE); Serial.print(command, BYTE);
for(i=0; i<bytec; i++) { for(i=0; i<bytec; i++) {
sendValueAsTwo7bitBytes(bytev[i]); sendValueAsTwo7bitBytes(bytev[i]);
} }
endSysex(); endSysex();
} }
void FirmataClass::sendString(byte command, const char* string) 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 // send a string as the protocol string type
void FirmataClass::sendString(const char* string) 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 // generic callbacks
void FirmataClass::attach(byte command, callbackFunction newFunction) void FirmataClass::attach(byte command, callbackFunction newFunction)
{ {
switch(command) { switch(command) {
case ANALOG_MESSAGE: currentAnalogCallback = newFunction; break; case ANALOG_MESSAGE: currentAnalogCallback = newFunction; break;
case DIGITAL_MESSAGE: currentDigitalCallback = newFunction; break; case DIGITAL_MESSAGE: currentDigitalCallback = newFunction; break;
case REPORT_ANALOG: currentReportAnalogCallback = newFunction; break; case REPORT_ANALOG: currentReportAnalogCallback = newFunction; break;
case REPORT_DIGITAL: currentReportDigitalCallback = newFunction; break; case REPORT_DIGITAL: currentReportDigitalCallback = newFunction; break;
case SET_PIN_MODE: currentPinModeCallback = newFunction; break; case SET_PIN_MODE: currentPinModeCallback = newFunction; break;
} }
} }
void FirmataClass::attach(byte command, systemResetCallbackFunction newFunction) void FirmataClass::attach(byte command, systemResetCallbackFunction newFunction)
{ {
switch(command) { switch(command) {
case SYSTEM_RESET: currentSystemResetCallback = newFunction; break; case SYSTEM_RESET: currentSystemResetCallback = newFunction; break;
} }
} }
void FirmataClass::attach(byte command, stringCallbackFunction newFunction) void FirmataClass::attach(byte command, stringCallbackFunction newFunction)
{ {
switch(command) { switch(command) {
case FIRMATA_STRING: currentStringCallback = newFunction; break; case STRING_DATA: currentStringCallback = newFunction; break;
} }
} }
void FirmataClass::attach(byte command, sysexCallbackFunction newFunction) void FirmataClass::attach(byte command, sysexCallbackFunction newFunction)
{ {
currentSysexCallback = newFunction; currentSysexCallback = newFunction;
} }
void FirmataClass::detach(byte command) void FirmataClass::detach(byte command)
{ {
switch(command) { switch(command) {
case SYSTEM_RESET: currentSystemResetCallback = NULL; break; case SYSTEM_RESET: currentSystemResetCallback = NULL; break;
case FIRMATA_STRING: currentStringCallback = NULL; break; case STRING_DATA: currentStringCallback = NULL; break;
case START_SYSEX: currentSysexCallback = NULL; break; case START_SYSEX: currentSysexCallback = NULL; break;
default: default:
attach(command, (callbackFunction)NULL); attach(command, (callbackFunction)NULL);
} }
} }
// sysex callbacks // sysex callbacks
@ -402,24 +402,24 @@ void FirmataClass::detach(byte command)
// resets the system state upon a SYSTEM_RESET message from the host software // resets the system state upon a SYSTEM_RESET message from the host software
void FirmataClass::systemReset(void) void FirmataClass::systemReset(void)
{ {
byte i; byte i;
waitForData = 0; // this flag says the next serial input will be data waitForData = 0; // this flag says the next serial input will be data
executeMultiByteCommand = 0; // execute this after getting multi-byte data executeMultiByteCommand = 0; // execute this after getting multi-byte data
multiByteChannel = 0; // channel data for multiByteCommands multiByteChannel = 0; // channel data for multiByteCommands
for(i=0; i<MAX_DATA_BYTES; i++) { for(i=0; i<MAX_DATA_BYTES; i++) {
storedInputData[i] = 0; storedInputData[i] = 0;
} }
parsingSysex = false; parsingSysex = false;
sysexBytesRead = 0; sysexBytesRead = 0;
if(currentSystemResetCallback) if(currentSystemResetCallback)
(*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 // used for flashing the pin for the version number
void FirmataClass::pin13strobe(int count, int onInterval, int offInterval) void FirmataClass::pin13strobe(int count, int onInterval, int offInterval)
{ {
byte i; byte i;
pinMode(VERSION_BLINK_PIN, OUTPUT); pinMode(VERSION_BLINK_PIN, OUTPUT);
for(i=0; i<count; i++) { for(i=0; i<count; i++) {
delay(offInterval); delay(offInterval);
digitalWrite(VERSION_BLINK_PIN, HIGH); digitalWrite(VERSION_BLINK_PIN, HIGH);
delay(onInterval); delay(onInterval);
digitalWrite(VERSION_BLINK_PIN, LOW); digitalWrite(VERSION_BLINK_PIN, LOW);
} }
} }

View File

@ -22,7 +22,7 @@
* software can test whether it will be compatible with the currently * software can test whether it will be compatible with the currently
* installed firmware. */ * installed firmware. */
#define FIRMATA_MAJOR_VERSION 2 // for non-compatible changes #define FIRMATA_MAJOR_VERSION 2 // for non-compatible changes
#define FIRMATA_MINOR_VERSION 0 // for backwards compatible changes #define FIRMATA_MINOR_VERSION 1 // for backwards compatible changes
#define VERSION_BLINK_PIN 13 // digital pin to blink version on #define VERSION_BLINK_PIN 13 // digital pin to blink version on
#define MAX_DATA_BYTES 32 // max number of data bytes in non-Sysex messages #define MAX_DATA_BYTES 32 // max number of data bytes in non-Sysex messages
@ -42,12 +42,22 @@
#define END_SYSEX 0xF7 // end a MIDI Sysex message #define END_SYSEX 0xF7 // end a MIDI Sysex message
// extended command set using sysex (0-127/0x00-0x7F) // 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 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 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_NON_REALTIME 0x7E // MIDI Reserved for non-realtime messages
#define SYSEX_REALTIME 0x7F // MIDI Reserved for 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 // pin modes
//#define INPUT 0x00 // defined in wiring.h //#define INPUT 0x00 // defined in wiring.h
@ -55,7 +65,8 @@
#define ANALOG 0x02 // analog pin in analogInput mode #define ANALOG 0x02 // analog pin in analogInput mode
#define PWM 0x03 // digital pin in PWM output mode #define PWM 0x03 // digital pin in PWM output mode
#define SERVO 0x04 // digital pin in Servo 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" { extern "C" {
// callback function types // callback function types
@ -151,6 +162,11 @@ extern FirmataClass Firmata;
#define TOTAL_DIGITAL_PINS 20 // 14 digital + 6 analog #define TOTAL_DIGITAL_PINS 20 // 14 digital + 6 analog
#define TOTAL_PORTS 3 // total number of ports for the board #define TOTAL_PORTS 3 // total number of ports for the board
#define ANALOG_PORT 2 // port# of analog used as digital #define ANALOG_PORT 2 // port# of analog used as digital
#elif defined(__AVR_ATmega1280__)// Arduino Mega
#define TOTAL_ANALOG_PINS 16
#define TOTAL_DIGITAL_PINS 54
#define TOTAL_PORTS 8 // total number of ports for the board
#define ANALOG_PORT 2 // port# of analog used as digital
#elif defined(__AVR_ATmega128__)// Wiring #elif defined(__AVR_ATmega128__)// Wiring
#define TOTAL_ANALOG_PINS 8 #define TOTAL_ANALOG_PINS 8
#define TOTAL_DIGITAL_PINS 51 #define TOTAL_DIGITAL_PINS 51

View File

@ -61,7 +61,7 @@ void setup()
servo9.attach(9); servo9.attach(9);
servo10.attach(10); servo10.attach(10);
Firmata.begin(); Firmata.begin(57600);
} }
/*============================================================================== /*==============================================================================

View File

@ -25,9 +25,9 @@ void sysexCallback(byte command, byte argc, byte*argv)
void setup() void setup()
{ {
Firmata.setFirmwareVersion(0, 1); Firmata.setFirmwareVersion(0, 1);
Firmata.attach(FIRMATA_STRING, stringCallback); Firmata.attach(STRING_DATA, stringCallback);
Firmata.attach(START_SYSEX, sysexCallback); Firmata.attach(START_SYSEX, sysexCallback);
Firmata.begin(); Firmata.begin(57600);
} }
void loop() void loop()

View File

@ -0,0 +1,220 @@
/*
Copyright (C) 2009 Jeff Hoefs. All rights reserved.
Copyright (C) 2009 Shigeru Kobayashi. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See file LICENSE.txt for further informations on licensing terms.
*/
#include <Wire.h>
#include <Firmata.h>
#define I2C_WRITE B00000000
#define I2C_READ B00001000
#define I2C_READ_CONTINUOUSLY B00010000
#define I2C_STOP_READING B00011000
#define I2C_READ_WRITE_MODE_MASK B00011000
#define MAX_QUERIES 8
unsigned long currentMillis; // store the current value from millis()
unsigned long nextExecuteMillis; // for comparison with currentMillis
unsigned int samplingInterval = 32; // default sampling interval is 33ms
unsigned int i2cReadDelayTime = 0; // default delay time between i2c read request and Wire.requestFrom()
unsigned int powerPinsEnabled = 0; // use as boolean to prevent enablePowerPins from being called more than once
#define MINIMUM_SAMPLING_INTERVAL 10
#define REGISTER_NOT_SPECIFIED -1
struct i2c_device_info {
byte addr;
byte reg;
byte bytes;
};
i2c_device_info query[MAX_QUERIES];
byte i2cRxData[32];
boolean readingContinuously = false;
byte queryIndex = 0;
void readAndReportData(byte address, int theRegister, byte numBytes)
{
if (theRegister != REGISTER_NOT_SPECIFIED) {
Wire.beginTransmission(address);
Wire.send((byte)theRegister);
Wire.endTransmission();
delayMicroseconds(i2cReadDelayTime); // delay is necessary for some devices such as WiiNunchuck
}
else {
theRegister = 0; // fill the register with a dummy value
}
Wire.requestFrom(address, numBytes);
// check to be sure correct number of bytes were returned by slave
if(numBytes == Wire.available()) {
i2cRxData[0] = address;
i2cRxData[1] = theRegister;
for (int i = 0; i < numBytes; i++) {
i2cRxData[2 + i] = Wire.receive();
}
// send slave address, register and received bytes
Firmata.sendSysex(I2C_REPLY, numBytes + 2, i2cRxData);
}
else {
if(numBytes > Wire.available()) {
Firmata.sendString("I2C Read Error: Too many bytes received");
} else {
Firmata.sendString("I2C Read Error: Too few bytes received");
}
}
}
void sysexCallback(byte command, byte argc, byte *argv)
{
byte mode;
byte slaveAddress;
byte slaveRegister;
byte data;
int delayTime;
if (command == I2C_REQUEST) {
mode = argv[1] & I2C_READ_WRITE_MODE_MASK;
slaveAddress = argv[0];
switch(mode) {
case I2C_WRITE:
Wire.beginTransmission(slaveAddress);
for (byte i = 2; i < argc; i += 2) {
data = argv[i] + (argv[i + 1] << 7);
Wire.send(data);
}
Wire.endTransmission();
delayMicroseconds(70); // TODO is this needed?
break;
case I2C_READ:
if (argc == 6) {
// a slave register is specified
slaveRegister = argv[2] + (argv[3] << 7);
data = argv[4] + (argv[5] << 7); // bytes to read
readAndReportData(slaveAddress, (int)slaveRegister, data);
}
else {
// a slave register is NOT specified
data = argv[2] + (argv[3] << 7); // bytes to read
readAndReportData(slaveAddress, (int)REGISTER_NOT_SPECIFIED, data);
}
break;
case I2C_READ_CONTINUOUSLY:
if ((queryIndex + 1) >= MAX_QUERIES) {
// too many queries, just ignore
Firmata.sendString("too many queries");
break;
}
query[queryIndex].addr = slaveAddress;
query[queryIndex].reg = argv[2] + (argv[3] << 7);
query[queryIndex].bytes = argv[4] + (argv[5] << 7);
readingContinuously = true;
queryIndex++;
break;
case I2C_STOP_READING:
readingContinuously = false;
queryIndex = 0;
break;
default:
break;
}
}
else if (command == SAMPLING_INTERVAL) {
samplingInterval = argv[0] + (argv[1] << 7);
if (samplingInterval < MINIMUM_SAMPLING_INTERVAL) {
samplingInterval = MINIMUM_SAMPLING_INTERVAL;
}
samplingInterval -= 1;
Firmata.sendString("sampling interval");
}
else if (command == I2C_CONFIG) {
delayTime = (argv[4] + (argv[5] << 7)); // MSB
delayTime = (delayTime << 8) + (argv[2] + (argv[3] << 7)); // add LSB
if((argv[0] + (argv[1] << 7)) > 0) {
enablePowerPins(PC3, PC2);
}
if(delayTime > 0) {
i2cReadDelayTime = delayTime;
}
if(argc > 6) {
// If you extend I2C_Config, handle your data here
}
}
}
void systemResetCallback()
{
readingContinuously = false;
queryIndex = 0;
}
/* reference: BlinkM_funcs.h by Tod E. Kurt, ThingM, http://thingm.com/ */
// Enables Pins A2 and A3 to be used as GND and Power
// so that I2C devices can be plugged directly
// into Arduino header (pins A2 - A5)
static void enablePowerPins(byte pwrpin, byte gndpin)
{
if(powerPinsEnabled == 0) {
DDRC |= _BV(pwrpin) | _BV(gndpin);
PORTC &=~ _BV(gndpin);
PORTC |= _BV(pwrpin);
powerPinsEnabled = 1;
Firmata.sendString("Power pins enabled");
delay(100);
}
}
void setup()
{
Firmata.setFirmwareVersion(2, 0);
Firmata.attach(START_SYSEX, sysexCallback);
Firmata.attach(SYSTEM_RESET, systemResetCallback);
for (int i = 0; i < TOTAL_DIGITAL_PINS; ++i) {
pinMode(i, OUTPUT);
}
/* I2C data is not reliable at higher baud rates, you'll need to change the
baud rate on the host computer as well. To get a firmware running with
minimal effort, you can try using the default baud rate (115200) */
Firmata.begin(38400);
Wire.begin();
}
void loop()
{
while (Firmata.available()) {
Firmata.processInput();
}
currentMillis = millis();
if (currentMillis > nextExecuteMillis) {
nextExecuteMillis = currentMillis + samplingInterval;
for (byte i = 0; i < queryIndex; i++) {
readAndReportData(query[i].addr, query[i].reg, query[i].bytes);
}
}
}

View File

@ -28,7 +28,7 @@ void setup()
servo9.attach(9); servo9.attach(9);
servo10.attach(10); servo10.attach(10);
Firmata.begin(); Firmata.begin(57600);
} }
void loop() void loop()

View File

@ -16,7 +16,7 @@ void setup()
{ {
Firmata.setFirmwareVersion(0, 1); Firmata.setFirmwareVersion(0, 1);
Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); Firmata.attach(ANALOG_MESSAGE, analogWriteCallback);
Firmata.begin(); Firmata.begin(57600);
} }
void loop() void loop()

View File

@ -45,7 +45,7 @@ void setup()
Firmata.setFirmwareVersion(0, 1); Firmata.setFirmwareVersion(0, 1);
Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback); Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback);
Firmata.attach(SET_PIN_MODE, setPinModeCallback); Firmata.attach(SET_PIN_MODE, setPinModeCallback);
Firmata.begin(); Firmata.begin(57600);
} }
void loop() void loop()

View File

@ -50,14 +50,20 @@ TARGET := $(shell pwd | sed 's|.*/\(.*\)|\1|')
ARDUINO = /Applications/arduino ARDUINO = /Applications/arduino
ARDUINO_SRC = $(ARDUINO)/hardware/cores/arduino ARDUINO_SRC = $(ARDUINO)/hardware/cores/arduino
ARDUINO_LIB_SRC = $(ARDUINO)/hardware/libraries ARDUINO_LIB_SRC = $(ARDUINO)/hardware/libraries
ARDUINO_TOOLS = $(ARDUINO)/hardware/tools
INCLUDE = -I$(ARDUINO_SRC) -I$(ARDUINO)/hardware/tools/avr/avr/include \ INCLUDE = -I$(ARDUINO_SRC) -I$(ARDUINO)/hardware/tools/avr/avr/include \
-I$(ARDUINO_LIB_SRC)/EEPROM \ -I$(ARDUINO_LIB_SRC)/EEPROM \
-I$(ARDUINO_LIB_SRC)/Firmata \ -I$(ARDUINO_LIB_SRC)/Firmata \
-I$(ARDUINO_LIB_SRC)/Matrix \
-I$(ARDUINO_LIB_SRC)/Servo \
-I$(ARDUINO_LIB_SRC)/Wire \
-I$(ARDUINO_LIB_SRC) -I$(ARDUINO_LIB_SRC)
SRC = $(wildcard $(ARDUINO_SRC)/*.c) SRC = $(wildcard $(ARDUINO_SRC)/*.c)
CXXSRC = applet/$(TARGET).cpp $(ARDUINO_SRC)/HardwareSerial.cpp \ CXXSRC = applet/$(TARGET).cpp $(ARDUINO_SRC)/HardwareSerial.cpp \
$(ARDUINO_LIB_SRC)/EEPROM/EEPROM.cpp \ $(ARDUINO_LIB_SRC)/EEPROM/EEPROM.cpp \
$(ARDUINO_LIB_SRC)/Firmata/Firmata.cpp \ $(ARDUINO_LIB_SRC)/Firmata/Firmata.cpp \
$(ARDUINO_LIB_SRC)/Servo/Servo.cpp \
$(ARDUINO_SRC)/Print.cpp \
$(ARDUINO_SRC)/WMath.cpp $(ARDUINO_SRC)/WMath.cpp
HEADERS = $(wildcard $(ARDUINO_SRC)/*.h) $(wildcard $(ARDUINO_LIB_SRC)/*/*.h) 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 -b $(UPLOAD_RATE) -q -V
# Program settings # Program settings
CC = avr-gcc ARDUINO_AVR_BIN = $(ARDUINO_TOOLS)/avr/bin
CXX = avr-g++ CC = $(ARDUINO_AVR_BIN)/avr-gcc
OBJCOPY = avr-objcopy CXX = $(ARDUINO_AVR_BIN)/avr-g++
OBJDUMP = avr-objdump OBJCOPY = $(ARDUINO_AVR_BIN)/avr-objcopy
SIZE = avr-size OBJDUMP = $(ARDUINO_AVR_BIN)/avr-objdump
NM = avr-nm SIZE = $(ARDUINO_AVR_BIN)/avr-size
NM = $(ARDUINO_AVR_BIN)/avr-nm
#AVRDUDE = $(ARDUINO_AVR_BIN)/avrdude
AVRDUDE = avrdude AVRDUDE = avrdude
REMOVE = rm -f REMOVE = rm -f
MV = mv -f MV = mv -f
@ -204,7 +212,8 @@ applet/$(TARGET).cpp: $(TARGET).pde
# Link: create ELF output file from object files. # Link: create ELF output file from object files.
applet/$(TARGET).elf: applet/$(TARGET).cpp $(OBJ) 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: pd_close_serial:
echo 'close;' | /Applications/Pd-extended.app/Contents/Resources/bin/pdsend 34567 || true 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 # etags -a /usr/include/*.h /usr/include/sys/*.h
path:
echo $(PATH)
echo $$PATH

View File

@ -1,21 +1,24 @@
/* /*
Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights reserved. Copyright (C) 2006-2008 Hans-Christoph Steiner. 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
License as published by the Free Software Foundation; either License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. version 2.1 of the License, or (at your option) any later version.
See file LICENSE.txt for further informations on licensing terms. 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 * TODO: use Program Control to load stored profiles from EEPROM
*/ */
#include <EEPROM.h>
#include <Firmata.h> #include <Firmata.h>
#include <Servo.h>
/*============================================================================== /*==============================================================================
* GLOBAL VARIABLES * GLOBAL VARIABLES
@ -34,37 +37,45 @@ byte portStatus[TOTAL_PORTS];
/* timer variables */ /* timer variables */
unsigned long currentMillis; // store the current value from millis() unsigned long currentMillis; // store the current value from millis()
unsigned long nextExecuteMillis; // for comparison with currentMillis 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) void outputPort(byte portNumber, byte portValue)
{ {
portValue = portValue &~ portStatus[portNumber]; portValue = portValue &~ portStatus[portNumber];
if(previousPINs[portNumber] != portValue) { if(previousPINs[portNumber] != portValue) {
Firmata.sendDigitalPort(portNumber, portValue); Firmata.sendDigitalPort(portNumber, portValue);
previousPINs[portNumber] = portValue; previousPINs[portNumber] = portValue;
Firmata.sendDigitalPort(portNumber, portValue); Firmata.sendDigitalPort(portNumber, portValue);
} }
} }
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
* check all the active digital inputs for change of state, then add any events * check all the active digital inputs for change of state, then add any events
* to the Serial output queue using Serial.print() */ * to the Serial output queue using Serial.print() */
void checkDigitalInputs(void) void checkDigitalInputs(void)
{ {
byte i, tmp; byte i, tmp;
for(i=0; i < TOTAL_PORTS; i++) { for(i=0; i < TOTAL_PORTS; i++) {
if(reportPINs[i]) { if(reportPINs[i]) {
switch(i) { switch(i) {
case 0: outputPort(0, PIND &~ B00000011); break; // ignore Rx/Tx 0/1 case 0:
case 1: outputPort(1, PINB); break; outputPort(0, PIND &~ B00000011); // ignore Rx/Tx 0/1
case ANALOG_PORT: outputPort(ANALOG_PORT, PINC); break; break;
} case 1:
} outputPort(1, PINB);
break;
case ANALOG_PORT:
outputPort(ANALOG_PORT, PINC);
break;
}
} }
}
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -72,61 +83,87 @@ void checkDigitalInputs(void)
* two bit-arrays that track Digital I/O and PWM status * two bit-arrays that track Digital I/O and PWM status
*/ */
void setPinModeCallback(byte pin, int mode) { void setPinModeCallback(byte pin, int mode) {
byte port = 0; byte port = 0;
byte offset = 0; byte offset = 0;
if (pin < 8) { // TODO: abstract for different boards
port = 0; if (pin < 8) {
offset = 0; port = 0;
} else if (pin < 14) { offset = 0;
port = 1; } else if (pin < 14) {
offset = 8; port = 1;
} else if (pin < 22) { offset = 8;
port = 2; } else if (pin < 22) {
offset = 14; port = 2;
} offset = 14;
}
if(pin > 1) { // ignore RxTx (pins 0 and 1)
if(pin > 1) { // ignore RxTx (pins 0 and 1)
reportAnalogCallback(pin - 14, mode == ANALOG ? 1 : 0); // turn on/off reporting
switch(mode) {
case ANALOG:
digitalWrite(pin, LOW); // disable internal pull-ups and fall thru to 'case INPUT:'
case INPUT:
pinStatus[pin] = mode;
pinMode(pin, INPUT);
portStatus[port] = portStatus[port] &~ (1 << (pin - offset));
break;
case OUTPUT:
digitalWrite(pin, LOW); // disable PWM and fall thru to 'case PWM:'
case PWM:
pinStatus[pin] = mode;
pinMode(pin, OUTPUT);
portStatus[port] = portStatus[port] | (1 << (pin - offset));
break;
case SERVO:
if((pin == 9 || pin == 10))
pinStatus[pin] = mode; pinStatus[pin] = mode;
switch(mode) { else
case INPUT: Firmata.sendString("Servo only on pins 9 and 10");
pinMode(pin, INPUT); break;
portStatus[port] = portStatus[port] &~ (1 << (pin - offset)); case I2C:
break; pinStatus[pin] = mode;
case OUTPUT: Firmata.sendString("I2C mode not yet supported");
digitalWrite(pin, LOW); // disable PWM break;
case PWM: default:
pinMode(pin, OUTPUT); Firmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM
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
} }
// TODO: save status to EEPROM here, if changed
}
} }
void analogWriteCallback(byte pin, int value) 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); analogWrite(pin, value);
break;
}
} }
void digitalWriteCallback(byte port, int value) void digitalWriteCallback(byte port, int value)
{ {
switch(port) { switch(port) {
case 0: // pins 2-7 (don't change Rx/Tx, pins 0 and 1) case 0: // pins 2-7 (don't change Rx/Tx, pins 0 and 1)
// 0xFF03 == B1111111100000011 0x03 == B00000011 // 0xFF03 == B1111111100000011 0x03 == B00000011
PORTD = (value &~ 0xFF03) | (PORTD & 0x03); PORTD = (value &~ 0xFF03) | (PORTD & 0x03);
break; break;
case 1: // pins 8-13 (14,15 are disabled for the crystal) case 1: // pins 8-13 (14,15 are disabled for the crystal)
PORTB = (byte)value; PORTB = (byte)value;
break; break;
case 2: // analog pins used as digital case 2: // analog pins used as digital
PORTC = (byte)value; byte pin;
break; byte pinModeMask;
} for(pin=0; pin<8; pin++)
if(pinStatus[pin] == OUTPUT)
pinModeMask += 1 << pin;
PORTC = (byte)value & pinModeMask;
break;
}
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -136,64 +173,93 @@ void digitalWriteCallback(byte port, int value)
//} //}
void reportAnalogCallback(byte pin, int value) void reportAnalogCallback(byte pin, int value)
{ {
if(value == 0) { if(value == 0) {
analogInputsToReport = analogInputsToReport &~ (1 << pin); analogInputsToReport = analogInputsToReport &~ (1 << pin);
} }
else { // everything but 0 enables reporting of that pin else { // everything but 0 enables reporting of that pin
analogInputsToReport = analogInputsToReport | (1 << pin); analogInputsToReport = analogInputsToReport | (1 << pin);
} setPinModeCallback(pin, ANALOG);
// TODO: save status to EEPROM here, if changed }
// TODO: save status to EEPROM here, if changed
} }
void reportDigitalCallback(byte port, int value) void reportDigitalCallback(byte port, int value)
{ {
reportPINs[port] = (byte)value; reportPINs[port] = (byte)value;
if(port == ANALOG_PORT) // turn off analog reporting when used as digital if(port == ANALOG_PORT) // turn off analog reporting when used as digital
analogInputsToReport = 0; 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() * SETUP()
*============================================================================*/ *============================================================================*/
void setup() void setup()
{ {
byte i; byte i;
Firmata.setFirmwareVersion(2, 0); Firmata.setFirmwareVersion(2, 1);
Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); Firmata.attach(ANALOG_MESSAGE, analogWriteCallback);
Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback); Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback);
Firmata.attach(REPORT_ANALOG, reportAnalogCallback); Firmata.attach(REPORT_ANALOG, reportAnalogCallback);
Firmata.attach(REPORT_DIGITAL, reportDigitalCallback); Firmata.attach(REPORT_DIGITAL, reportDigitalCallback);
Firmata.attach(SET_PIN_MODE, setPinModeCallback); Firmata.attach(SET_PIN_MODE, setPinModeCallback);
Firmata.attach(START_SYSEX, sysexCallback);
portStatus[0] = B00000011; // ignore Tx/RX pins portStatus[0] = B00000011; // ignore Tx/RX pins
portStatus[1] = B11000000; // ignore 14/15 pins portStatus[1] = B11000000; // ignore 14/15 pins
portStatus[2] = B00000000; portStatus[2] = B00000000;
// for(i=0; i<TOTAL_DIGITAL_PINS; ++i) { // TODO make this work with analogs for(i=0; i<TOTAL_DIGITAL_PINS; ++i) { // TODO make this work with analogs
for(i=0; i<14; ++i) { setPinModeCallback(i,OUTPUT);
setPinModeCallback(i,OUTPUT); }
} // set all outputs to 0 to make sure internal pull-up resistors are off
// set all outputs to 0 to make sure internal pull-up resistors are off PORTB = 0; // pins 8-15
PORTB = 0; // pins 8-15 PORTC = 0; // analog port
PORTC = 0; // analog port PORTD = 0; // pins 0-7
PORTD = 0; // pins 0-7
// TODO rethink the init, perhaps it should report analog on default // TODO rethink the init, perhaps it should report analog on default
for(i=0; i<TOTAL_PORTS; ++i) { for(i=0; i<TOTAL_PORTS; ++i) {
reportPINs[i] = false; reportPINs[i] = false;
} }
// TODO: load state from EEPROM here // TODO: load state from EEPROM here
/* send digital inputs here, if enabled, to set the initial state on the /* 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 * host computer, since once in the loop(), this firmware will only send
* digital data on change. */ * digital data on change. */
if(reportPINs[0]) outputPort(0, PIND &~ B00000011); // ignore Rx/Tx 0/1 if(reportPINs[0]) outputPort(0, PIND &~ B00000011); // ignore Rx/Tx 0/1
if(reportPINs[1]) outputPort(1, PINB); if(reportPINs[1]) outputPort(1, PINB);
if(reportPINs[ANALOG_PORT]) outputPort(ANALOG_PORT, PINC); if(reportPINs[ANALOG_PORT]) outputPort(ANALOG_PORT, PINC);
Firmata.begin(); Firmata.begin(57600);
} }
/*============================================================================== /*==============================================================================
@ -201,26 +267,26 @@ void setup()
*============================================================================*/ *============================================================================*/
void loop() void loop()
{ {
/* DIGITALREAD - as fast as possible, check for changes and output them to the /* DIGITALREAD - as fast as possible, check for changes and output them to the
* FTDI buffer using Serial.print() */ * FTDI buffer using Serial.print() */
checkDigitalInputs(); checkDigitalInputs();
currentMillis = millis(); currentMillis = millis();
if(currentMillis > nextExecuteMillis) { if(currentMillis > nextExecuteMillis) {
nextExecuteMillis = currentMillis + 19; // run this every 20ms nextExecuteMillis = currentMillis + samplingInterval;
/* SERIALREAD - Serial.read() uses a 128 byte circular buffer, so handle /* SERIALREAD - Serial.read() uses a 128 byte circular buffer, so handle
* all serialReads at once, i.e. empty the buffer */ * all serialReads at once, i.e. empty the buffer */
while(Firmata.available()) while(Firmata.available())
Firmata.processInput(); Firmata.processInput();
/* SEND FTDI WRITE BUFFER - make sure that the FTDI buffer doesn't go over /* 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 * 60 bytes. use a timer to sending an event character every 4 ms to
* trigger the buffer to dump. */ * trigger the buffer to dump. */
/* ANALOGREAD - right after the event character, do all of the /* ANALOGREAD - right after the event character, do all of the
* analogReads(). These only need to be done every 4ms. */ * analogReads(). These only need to be done every 4ms. */
for(analogPin=0;analogPin<TOTAL_ANALOG_PINS;analogPin++) { for(analogPin=0;analogPin<TOTAL_ANALOG_PINS;analogPin++) {
if( analogInputsToReport & (1 << analogPin) ) { if( analogInputsToReport & (1 << analogPin) ) {
Firmata.sendAnalog(analogPin, analogRead(analogPin)); Firmata.sendAnalog(analogPin, analogRead(analogPin));
} }
}
} }
}
} }