From 3f5220e4549900f1d1dd768ca204b34625ca9558 Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Tue, 14 Jul 2009 21:32:55 +0000 Subject: Updating to Firmata-2.1beta1 (rev 23). --- .../Firmata/examples/StandardFirmata/Makefile | 26 +- .../examples/StandardFirmata/StandardFirmata.pde | 312 +++++++++++++-------- 2 files changed, 208 insertions(+), 130 deletions(-) (limited to 'libraries/Firmata/examples/StandardFirmata') 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..02192cc 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 #include +#include /*============================================================================== * 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,87 @@ 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) + 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 +173,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 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