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

@ -60,7 +60,7 @@ 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();
@ -154,7 +154,7 @@ void FirmataClass::processSysexMessage(void)
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));
@ -327,7 +327,7 @@ void FirmataClass::sendString(byte command, const char* 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);
} }
@ -355,7 +355,7 @@ void FirmataClass::attach(byte command, systemResetCallbackFunction newFunction)
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;
} }
} }
@ -368,7 +368,7 @@ 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);

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

@ -7,15 +7,18 @@
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,7 +37,9 @@ 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
@ -59,9 +64,15 @@ void checkDigitalInputs(void)
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;
} }
} }
} }
@ -75,6 +86,7 @@ void setPinModeCallback(byte pin, int mode) {
byte port = 0; byte port = 0;
byte offset = 0; byte offset = 0;
// TODO: abstract for different boards
if (pin < 8) { if (pin < 8) {
port = 0; port = 0;
offset = 0; offset = 0;
@ -87,21 +99,34 @@ void setPinModeCallback(byte pin, int mode) {
} }
if(pin > 1) { // ignore RxTx (pins 0 and 1) if(pin > 1) { // ignore RxTx (pins 0 and 1)
pinStatus[pin] = mode; reportAnalogCallback(pin - 14, mode == ANALOG ? 1 : 0); // turn on/off reporting
switch(mode) { switch(mode) {
case ANALOG:
digitalWrite(pin, LOW); // disable internal pull-ups and fall thru to 'case INPUT:'
case INPUT: case INPUT:
pinStatus[pin] = mode;
pinMode(pin, INPUT); pinMode(pin, INPUT);
portStatus[port] = portStatus[port] &~ (1 << (pin - offset)); portStatus[port] = portStatus[port] &~ (1 << (pin - offset));
break; break;
case OUTPUT: case OUTPUT:
digitalWrite(pin, LOW); // disable PWM digitalWrite(pin, LOW); // disable PWM and fall thru to 'case PWM:'
case PWM: case PWM:
pinStatus[pin] = mode;
pinMode(pin, OUTPUT); pinMode(pin, OUTPUT);
portStatus[port] = portStatus[port] | (1 << (pin - offset)); portStatus[port] = portStatus[port] | (1 << (pin - offset));
break; break;
//case ANALOG: // TODO figure this out case SERVO:
if((pin == 9 || pin == 10))
pinStatus[pin] = mode;
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: default:
Firmata.sendString(""); Firmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM
} }
// TODO: save status to EEPROM here, if changed // TODO: save status to EEPROM here, if changed
} }
@ -109,8 +134,15 @@ void setPinModeCallback(byte pin, int mode) {
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)
@ -124,7 +156,12 @@ void digitalWriteCallback(byte port, int value)
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;
byte pinModeMask;
for(pin=0; pin<8; pin++)
if(pinStatus[pin] == OUTPUT)
pinModeMask += 1 << pin;
PORTC = (byte)value & pinModeMask;
break; break;
} }
} }
@ -141,6 +178,7 @@ void reportAnalogCallback(byte pin, int value)
} }
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
} }
@ -152,6 +190,34 @@ void reportDigitalCallback(byte port, int value)
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()
*============================================================================*/ *============================================================================*/
@ -159,20 +225,20 @@ 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
@ -193,7 +259,7 @@ void setup()
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);
} }
/*============================================================================== /*==============================================================================
@ -206,7 +272,7 @@ void loop()
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())