1
0
mirror of https://github.com/arduino/Arduino.git synced 2025-02-19 13:54:23 +01:00

Updating Firmata (to r62 of their repository).

Changes include (according to Paul Stoffregen):
"1: Hardware abstraction layer to support Arduino Mega, Teensy and Sanguino.
2: Extended analog message, to facilitate using PWM and Servo above pin 15.
3: Capability queries (alpha), to allow automatic discovery of any board's features."
This commit is contained in:
David A. Mellis 2010-08-06 21:55:17 +00:00
parent 17beb9fcfb
commit 367a0ae9f4
10 changed files with 676 additions and 295 deletions

335
libraries/Firmata/Boards.h Normal file
View File

@ -0,0 +1,335 @@
/* Boards.h - Hardware Abstraction Layer for Firmata library */
#ifndef Firmata_Boards_h
#define Firmata_Boards_h
#include <WProgram.h> // for digitalRead, digitalWrite, etc
// Normally Servo.h must be included before Firmata.h (which then includes
// this file). If Servo.h wasn't included, this allows the code to still
// compile, but without support for any Servos. Hopefully that's what the
// user intended by not including Servo.h
#ifndef MAX_SERVOS
#define MAX_SERVOS 0
#endif
/*
Firmata Hardware Abstraction Layer
Firmata is built on top of the hardware abstraction functions of Arduino,
specifically digitalWrite, digitalRead, analogWrite, analogRead, and
pinMode. While these functions offer simple integer pin numbers, Firmata
needs more information than is provided by Arduino. This file provides
all other hardware specific details. To make Firmata support a new board,
only this file should require editing.
The key concept is every "pin" implemented by Firmata may be mapped to
any pin as implemented by Arduino. Usually a simple 1-to-1 mapping is
best, but such mapping should not be assumed. This hardware abstraction
layer allows Firmata to implement any number of pins which map onto the
Arduino implemented pins in almost any arbitrary way.
General Constants:
These constants provide basic information Firmata requires.
TOTAL_PINS: The total number of pins Firmata implemented by Firmata.
Usually this will match the number of pins the Arduino functions
implement, including any pins pins capable of analog or digital.
However, Firmata may implement any number of pins. For example,
on Arduino Mini with 8 analog inputs, 6 of these may be used
for digital functions, and 2 are analog only. On such boards,
Firmata can implement more pins than Arduino's pinMode()
function, in order to accommodate those special pins. The
Firmata protocol supports a maximum of 128 pins, so this
constant must not exceed 128.
TOTAL_ANALOG_PINS: The total number of analog input pins implemented.
The Firmata protocol allows up to 16 analog inputs, accessed
using offsets 0 to 15. Because Firmata presents the analog
inputs using different offsets than the actual pin numbers
(a legacy of Arduino's analogRead function, and the way the
analog input capable pins are physically labeled on all
Arduino boards), the total number of analog input signals
must be specified. 16 is the maximum.
VERSION_BLINK_PIN: When Firmata starts up, it will blink the version
number. This constant is the Arduino pin number where a
LED is connected.
Pin Mapping Macros:
These macros provide the mapping between pins as implemented by
Firmata protocol and the actual pin numbers used by the Arduino
functions. Even though such mappings are often simple, pin
numbers received by Firmata protocol should always be used as
input to these macros, and the result of the macro should be
used with with any Arduino function.
When Firmata is extended to support a new pin mode or feature,
a pair of macros should be added and used for all hardware
access. For simple 1:1 mapping, these macros add no actual
overhead, yet their consistent use allows source code which
uses them consistently to be easily adapted to all other boards
with different requirements.
IS_PIN_XXXX(pin): The IS_PIN macros resolve to true or non-zero
if a pin as implemented by Firmata corresponds to a pin
that actually implements the named feature.
PIN_TO_XXXX(pin): The PIN_TO macros translate pin numbers as
implemented by Firmata to the pin numbers needed as inputs
to the Arduino functions. The corresponding IS_PIN macro
should always be tested before using a PIN_TO macro, so
these macros only need to handle valid Firmata pin
numbers for the named feature.
Port Access Inline Funtions:
For efficiency, Firmata protocol provides access to digital
input and output pins grouped by 8 bit ports. When these
groups of 8 correspond to actual 8 bit ports as implemented
by the hardware, these inline functions can provide high
speed direct port access. Otherwise, a default implementation
using 8 calls to digitalWrite or digitalRead is used.
When porting Firmata to a new board, it is recommended to
use the default functions first and focus only on the constants
and macros above. When those are working, if optimized port
access is desired, these inline functions may be extended.
The recommended approach defines a symbol indicating which
optimization to use, and then conditional complication is
used within these functions.
readPort(port, bitmask): Read an 8 bit port, returning the value.
port: The port number, Firmata pins port*8 to port*8+7
bitmask: The actual pins to read, indicated by 1 bits.
writePort(port, value, bitmask): Write an 8 bit port.
port: The port number, Firmata pins port*8 to port*8+7
value: The 8 bit value to write
bitmask: The actual pins to write, indicated by 1 bits.
*/
/*==============================================================================
* Board Specific Configuration
*============================================================================*/
// Arduino Duemilanove, Diecimila, and NG
#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__)
#define TOTAL_ANALOG_PINS 8
#define TOTAL_PINS 24 // 14 digital + 2 unused + 8 analog
#define VERSION_BLINK_PIN 13
#define IS_PIN_DIGITAL(p) (((p) >= 2 && (p) <= 13) || ((p) >= 16 && (p) <= 21))
#define IS_PIN_ANALOG(p) ((p) >= 16 && (p) <= 23)
#define IS_PIN_PWM(p) IS_PIN_DIGITAL(p)
#define IS_PIN_SERVO(p) ((p) >= 2 && (p) <= 13 && (p) - 2 < MAX_SERVOS)
#define IS_PIN_I2C(p) (0)
#define PIN_TO_DIGITAL(p) (((p) < 16) ? (p) : (p) - 2)
#define PIN_TO_ANALOG(p) ((p) - 16)
#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
#define PIN_TO_SERVO(p) ((p) - 2)
#define ARDUINO_PINOUT_OPTIMIZE 1
// old Arduinos
#elif defined(__AVR_ATmega8__)
#define TOTAL_ANALOG_PINS 6
#define TOTAL_PINS 22 // 14 digital + 2 unused + 6 analog
#define VERSION_BLINK_PIN 13
#define IS_PIN_DIGITAL(p) (((p) >= 2 && (p) <= 13) || ((p) >= 16 && (p) <= 21))
#define IS_PIN_ANALOG(p) ((p) >= 16 && (p) <= 21)
#define IS_PIN_PWM(p) IS_PIN_DIGITAL(p)
#define IS_PIN_SERVO(p) ((p) >= 2 && (p) <= 13 && (p) - 2 < MAX_SERVOS)
#define IS_PIN_I2C(p) (0)
#define PIN_TO_DIGITAL(p) (((p) < 16) ? (p) : (p) - 2)
#define PIN_TO_ANALOG(p) ((p) - 16)
#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
#define PIN_TO_SERVO(p) ((p) - 2)
#define ARDUINO_PINOUT_OPTIMIZE 1
// Arduino Mega
#elif defined(__AVR_ATmega1280__)
#define TOTAL_ANALOG_PINS 16
#define TOTAL_PINS 70 // 54 digital + 16 analog
#define VERSION_BLINK_PIN 13
#define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < TOTAL_PINS)
#define IS_PIN_ANALOG(p) ((p) >= 54 && (p) < TOTAL_PINS)
#define IS_PIN_PWM(p) IS_PIN_DIGITAL(p)
#define IS_PIN_SERVO(p) ((p) >= 2 && (p) - 2 < MAX_SERVOS)
#define IS_PIN_I2C(p) (0)
#define PIN_TO_DIGITAL(p) (p)
#define PIN_TO_ANALOG(p) ((p) - 54)
#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
#define PIN_TO_SERVO(p) ((p) - 2)
// Wiring
#elif defined(__AVR_ATmega128__)
#define TOTAL_ANALOG_PINS 8
#define TOTAL_PINS 51
#define VERSION_BLINK_PIN 48
// TODO: hardware abstraction for wiring board
// Teensy 1.0
#elif defined(__AVR_AT90USB162__)
#define TOTAL_ANALOG_PINS 0
#define TOTAL_PINS 21 // 21 digital + no analog
#define VERSION_BLINK_PIN 6
#define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS)
#define IS_PIN_ANALOG(p) (0)
#define IS_PIN_PWM(p) IS_PIN_DIGITAL(p)
#define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS)
#define IS_PIN_I2C(p) (0)
#define PIN_TO_DIGITAL(p) (p)
#define PIN_TO_ANALOG(p) (0)
#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
#define PIN_TO_SERVO(p) (p)
// Teensy 2.0
#elif defined(__AVR_ATmega32U4__)
#define TOTAL_ANALOG_PINS 12
#define TOTAL_PINS 25 // 11 digital + 12 analog
#define VERSION_BLINK_PIN 11
#define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS)
#define IS_PIN_ANALOG(p) ((p) >= 11 && (p) <= 22)
#define IS_PIN_PWM(p) IS_PIN_DIGITAL(p)
#define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS)
#define IS_PIN_I2C(p) (0)
#define PIN_TO_DIGITAL(p) (p)
#define PIN_TO_ANALOG(p) (((p)<22)?21-(p):11)
#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
#define PIN_TO_SERVO(p) (p)
// Teensy++ 1.0 and 2.0
#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
#define TOTAL_ANALOG_PINS 8
#define TOTAL_PINS 46 // 38 digital + 8 analog
#define VERSION_BLINK_PIN 6
#define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS)
#define IS_PIN_ANALOG(p) ((p) >= 38 && (p) < TOTAL_PINS)
#define IS_PIN_PWM(p) IS_PIN_DIGITAL(p)
#define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS)
#define IS_PIN_I2C(p) (0)
#define PIN_TO_DIGITAL(p) (p)
#define PIN_TO_ANALOG(p) ((p) - 38)
#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
#define PIN_TO_SERVO(p) (p)
// Sanguino
#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__)
#define TOTAL_ANALOG_PINS 8
#define TOTAL_PINS 32 // 24 digital + 8 analog
#define VERSION_BLINK_PIN 0
#define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < TOTAL_PINS)
#define IS_PIN_ANALOG(p) ((p) >= 24 && (p) < TOTAL_PINS)
#define IS_PIN_PWM(p) IS_PIN_DIGITAL(p)
#define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS)
#define IS_PIN_I2C(p) (0)
#define PIN_TO_DIGITAL(p) (p)
#define PIN_TO_ANALOG(p) ((p) - 24)
#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
#define PIN_TO_SERVO(p) ((p) - 2)
// Illuminato
#elif defined(__AVR_ATmega645__)
#define TOTAL_ANALOG_PINS 6
#define TOTAL_PINS 42 // 36 digital + 6 analog
#define VERSION_BLINK_PIN 13
#define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < TOTAL_PINS)
#define IS_PIN_ANALOG(p) ((p) >= 36 && (p) < TOTAL_PINS)
#define IS_PIN_PWM(p) IS_PIN_DIGITAL(p)
#define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS)
#define IS_PIN_I2C(p) (0)
#define PIN_TO_DIGITAL(p) (p)
#define PIN_TO_ANALOG(p) ((p) - 36)
#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
#define PIN_TO_SERVO(p) ((p) - 2)
// anything else
#else
#error "Please edit Boards.h with a hardware abstraction for this board"
#endif
/*==============================================================================
* readPort() - Read an 8 bit port
*============================================================================*/
static inline unsigned char readPort(byte, byte) __attribute__((always_inline, unused));
static inline unsigned char readPort(byte port, byte bitmask)
{
#if defined(ARDUINO_PINOUT_OPTIMIZE)
if (port == 0) return PIND & B11111100 & bitmask; // ignore Rx/Tx 0/1
if (port == 1) return PINB & B00111111 & bitmask; // pins 8-13 (14,15 are disabled for the crystal)
if (port == 2) return PINC & bitmask;
return 0;
#else
unsigned char out=0, pin=port*8;
if (IS_PIN_DIGITAL(pin+0) && (bitmask & 0x01) && digitalRead(PIN_TO_DIGITAL(pin+0))) out |= 0x01;
if (IS_PIN_DIGITAL(pin+1) && (bitmask & 0x02) && digitalRead(PIN_TO_DIGITAL(pin+1))) out |= 0x02;
if (IS_PIN_DIGITAL(pin+2) && (bitmask & 0x04) && digitalRead(PIN_TO_DIGITAL(pin+2))) out |= 0x04;
if (IS_PIN_DIGITAL(pin+3) && (bitmask & 0x08) && digitalRead(PIN_TO_DIGITAL(pin+3))) out |= 0x08;
if (IS_PIN_DIGITAL(pin+4) && (bitmask & 0x10) && digitalRead(PIN_TO_DIGITAL(pin+4))) out |= 0x10;
if (IS_PIN_DIGITAL(pin+5) && (bitmask & 0x20) && digitalRead(PIN_TO_DIGITAL(pin+5))) out |= 0x20;
if (IS_PIN_DIGITAL(pin+6) && (bitmask & 0x40) && digitalRead(PIN_TO_DIGITAL(pin+6))) out |= 0x40;
if (IS_PIN_DIGITAL(pin+7) && (bitmask & 0x80) && digitalRead(PIN_TO_DIGITAL(pin+7))) out |= 0x80;
return out;
#endif
}
/*==============================================================================
* writePort() - Write an 8 bit port, only touch pins specified by a bitmask
*============================================================================*/
static inline unsigned char writePort(byte, byte, byte) __attribute__((always_inline, unused));
static inline unsigned char writePort(byte port, byte value, byte bitmask)
{
#if defined(ARDUINO_PINOUT_OPTIMIZE)
if (port == 0) {
bitmask = bitmask & 0xFC; // Tx & Rx pins
cli();
PORTD = (PORTD & ~bitmask) | (bitmask & value);
sei();
} else if (port == 1) {
cli();
PORTB = (PORTB & ~bitmask) | (bitmask & value);
sei();
} else if (port == 2) {
cli();
PORTC = (PORTC & ~bitmask) | (bitmask & value);
sei();
}
#else
byte pin=port*8;
if ((bitmask & 0x01)) digitalWrite(PIN_TO_DIGITAL(pin+0), (value & 0x01));
if ((bitmask & 0x02)) digitalWrite(PIN_TO_DIGITAL(pin+1), (value & 0x02));
if ((bitmask & 0x04)) digitalWrite(PIN_TO_DIGITAL(pin+2), (value & 0x04));
if ((bitmask & 0x08)) digitalWrite(PIN_TO_DIGITAL(pin+3), (value & 0x08));
if ((bitmask & 0x10)) digitalWrite(PIN_TO_DIGITAL(pin+4), (value & 0x10));
if ((bitmask & 0x20)) digitalWrite(PIN_TO_DIGITAL(pin+5), (value & 0x20));
if ((bitmask & 0x40)) digitalWrite(PIN_TO_DIGITAL(pin+6), (value & 0x40));
if ((bitmask & 0x80)) digitalWrite(PIN_TO_DIGITAL(pin+7), (value & 0x80));
#endif
}
#ifndef TOTAL_PORTS
#define TOTAL_PORTS ((TOTAL_PINS + 7) / 8)
#endif
#endif /* Firmata_Boards_h */

View File

@ -47,7 +47,14 @@
#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 I2C_CONFIG 0x78 // config I2C settings such as delay times and power pins
#define EXTENDED_ANALOG 0x6F // analog write (PWM, Servo, etc) to any pin
#define PIN_STATE_QUERY 0x6D // ask for a pin's current mode and value
#define PIN_STATE_RESPONSE 0x6E // reply with pin's current mode and value
#define CAPABILITY_QUERY 0x6B // ask for supported modes and resolution of all pins
#define CAPABILITY_RESPONSE 0x6C // reply with supported modes and resolution
#define ANALOG_MAPPING_QUERY 0x69 // ask for mapping of analog to pin numbers
#define ANALOG_MAPPING_RESPONSE 0x6A // reply with mapping info
#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
@ -66,6 +73,7 @@
#define SERVO 0x04 // digital pin in Servo output mode
#define SHIFT 0x05 // shiftIn/shiftOut mode
#define I2C 0x06 // pin included in I2C setup
#define TOTAL_PIN_MODES 7
extern "C" {
// callback function types
@ -147,84 +155,8 @@ extern FirmataClass Firmata;
*/
#define setFirmwareVersion(x, y) setFirmwareNameAndVersion(__FILE__, x, y)
// total number of pins currently supported
#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) // Arduino NG and Diecimila
#define TOTAL_ANALOG_PINS 8
#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
#define FIRST_SERVO_PIN 2 // pin# of the first servo pin
#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
#define FIRST_SERVO_PIN 2 // pin# of the first servo pin
#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
#define FIRST_SERVO_PIN 2 // pin# of the first servo pin
#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 48 // digital pin to blink version on
#define FIRST_SERVO_PIN 8 // pin# of the first servo pin
#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 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
/* Hardware Abstraction Layer */
#include "Boards.h"
#endif /* Firmata_h */

View File

@ -11,19 +11,19 @@ byte pin;
int analogValue;
int previousAnalogValues[TOTAL_ANALOG_PINS];
byte portStatus[TOTAL_PORTS];
byte portStatus[TOTAL_PORTS]; // each bit: 1=pin is digital input, 0=other/ignore
byte previousPINs[TOTAL_PORTS];
/* timer variables */
unsigned long currentMillis; // store the current value from millis()
unsigned long nextExecuteMillis; // for comparison with currentMillis
unsigned long previousMillis; // for comparison with currentMillis
/* make sure that the FTDI buffer doesn't go over 60 bytes, otherwise you
get long, random delays. So only read analogs every 20ms or so */
int samplingInterval = 19; // how often to run the main loop (in ms)
void sendPort(byte portNumber, byte portValue)
{
portValue = portValue &~ portStatus[portNumber];
portValue = portValue & portStatus[portNumber];
if(previousPINs[portNumber] != portValue) {
Firmata.sendDigitalPort(portNumber, portValue);
previousPINs[portNumber] = portValue;
@ -32,29 +32,37 @@ void sendPort(byte portNumber, byte portValue)
void setup()
{
byte i, port, status;
Firmata.setFirmwareVersion(0, 1);
for(pin = 0; pin < TOTAL_DIGITAL_PINS; pin++) {
pinMode(pin, INPUT);
for(pin = 0; pin < TOTAL_PINS; pin++) {
if IS_PIN_DIGITAL(pin) pinMode(PIN_TO_DIGITAL(pin), INPUT);
}
portStatus[0] = B00000011; // ignore Tx/RX pins
portStatus[1] = B11000000; // ignore 14/15 pins
portStatus[2] = B00000000;
for (port=0; port<TOTAL_PORTS; port++) {
status = 0;
for (i=0; i<8; i++) {
if (IS_PIN_DIGITAL(port * 8 + i)) status |= (1 << i);
}
portStatus[port] = status;
}
Firmata.begin(57600);
}
void loop()
{
sendPort(0, PIND);
sendPort(1, PINB);
sendPort(2, PINC);
byte i;
for (i=0; i<TOTAL_PORTS; i++) {
sendPort(i, readPort(i));
}
/* make sure that the FTDI buffer doesn't go over 60 bytes, otherwise you
get long, random delays. So only read analogs every 20ms or so */
currentMillis = millis();
if(currentMillis > nextExecuteMillis) {
nextExecuteMillis = currentMillis + samplingInterval;
if(currentMillis - previousMillis > samplingInterval) {
previousMillis += samplingInterval;
while(Firmata.available()) {
Firmata.processInput();
}

View File

@ -3,8 +3,8 @@
*
* This example code is in the public domain.
*/
#include <Firmata.h>
#include <Servo.h>
#include <Firmata.h>
/*==============================================================================
* GLOBAL VARIABLES
@ -17,7 +17,7 @@ int analogInputsToReport = 0; // bitwise array to store pin reporting
int analogPin = 0; // counter for reading analog pins
/* timer variables */
unsigned long currentMillis; // store the current value from millis()
unsigned long nextExecuteMillis; // for comparison with currentMillis
unsigned long previousMillis; // for comparison with currentMillis
/*==============================================================================
@ -72,8 +72,8 @@ void loop()
while(Firmata.available())
Firmata.processInput();
currentMillis = millis();
if(currentMillis > nextExecuteMillis) {
nextExecuteMillis = currentMillis + 19; // run this every 20ms
if(currentMillis - previousMillis > 20) {
previousMillis += 20; // run this every 20ms
for(analogPin=0;analogPin<TOTAL_ANALOG_PINS;analogPin++) {
if( analogInputsToReport & (1 << analogPin) )
Firmata.sendAnalog(analogPin, analogRead(analogPin));

View File

@ -23,7 +23,7 @@
#define MAX_QUERIES 8
unsigned long currentMillis; // store the current value from millis()
unsigned long nextExecuteMillis; // for comparison with currentMillis
unsigned long previousMillis; // 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
@ -192,7 +192,7 @@ void setup()
Firmata.attach(START_SYSEX, sysexCallback);
Firmata.attach(SYSTEM_RESET, systemResetCallback);
for (int i = 0; i < TOTAL_DIGITAL_PINS; ++i) {
for (int i = 0; i < TOTAL_PINS; ++i) {
pinMode(i, OUTPUT);
}
@ -207,8 +207,8 @@ void loop()
}
currentMillis = millis();
if (currentMillis > nextExecuteMillis) {
nextExecuteMillis = currentMillis + samplingInterval;
if (currentMillis - previousMillis > samplingInterval) {
previousMillis += samplingInterval;
for (byte i = 0; i < queryIndex; i++) {
readAndReportData(query[i].addr, query[i].reg, query[i].bytes);

View File

@ -30,12 +30,12 @@ int analogPin = 0; // counter for reading analog pins
/* digital pins */
byte reportPINs[TOTAL_PORTS]; // PIN == input port
byte previousPINs[TOTAL_PORTS]; // PIN == input port
byte pinStatus[TOTAL_DIGITAL_PINS]; // store pin status, default OUTPUT
byte pinStatus[TOTAL_PINS]; // store pin status, default OUTPUT
byte portStatus[TOTAL_PORTS];
/* timer variables */
unsigned long currentMillis; // store the current value from millis()
unsigned long nextExecuteMillis; // for comparison with currentMillis
unsigned long previousMillis; // for comparison with currentMillis
/*==============================================================================
@ -63,7 +63,7 @@ void checkDigitalInputs(void)
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;
case 2: outputPort(2, PINC); break;
}
}
}
@ -150,7 +150,7 @@ void reportAnalogCallback(byte pin, int value)
void reportDigitalCallback(byte port, int value)
{
reportPINs[port] = (byte)value;
if(port == ANALOG_PORT) // turn off analog reporting when used as digital
if(port == 2) // turn off analog reporting when used as digital
analogInputsToReport = 0;
}
@ -173,7 +173,7 @@ void setup()
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<TOTAL_PINS; ++i) { // TODO make this work with analogs
for(i=0; i<14; ++i) {
setPinModeCallback(i,OUTPUT);
}
@ -193,7 +193,7 @@ void setup()
* 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);
if(reportPINs[2]) outputPort(2, PINC);
Firmata.begin(115200);
}
@ -207,8 +207,8 @@ void loop()
* FTDI buffer using Serial.print() */
checkDigitalInputs();
currentMillis = millis();
if(currentMillis > nextExecuteMillis) {
nextExecuteMillis = currentMillis + 19; // run this every 20ms
if(currentMillis - previousMillis > 20) {
previousMillis += 20; // 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())

View File

@ -1,32 +1,35 @@
/* This firmware supports as many servos as possible using the Servo" library
* included in Arduino 0012
/* This firmware supports as many servos as possible using the Servo library
* included in Arduino 0017
*
* TODO add message to configure minPulse/maxPulse/degrees
*
* This example code is in the public domain.
*/
#include <Firmata.h>
#include <Servo.h>
#include <Firmata.h>
Servo servo9;
Servo servo10;
Servo servos[MAX_SERVOS];
void analogWriteCallback(byte pin, int value)
{
if(pin == 9)
servo9.write(value);
if(pin == 10)
servo10.write(value);
if (IS_PIN_SERVO(pin)) {
servos[PIN_TO_SERVO(pin)].write(value);
}
}
void setup()
{
byte pin;
Firmata.setFirmwareVersion(0, 2);
Firmata.attach(ANALOG_MESSAGE, analogWriteCallback);
servo9.attach(9);
servo10.attach(10);
for (pin=0; pin < TOTAL_PINS; pin++) {
if (IS_PIN_SERVO(pin)) {
servos[PIN_TO_SERVO(pin)].attach(PIN_TO_DIGITAL(pin));
}
}
Firmata.begin(57600);
}

View File

@ -4,12 +4,14 @@
*/
#include <Firmata.h>
byte analogPin;
byte analogPin = 0;
void analogWriteCallback(byte pin, int value)
{
pinMode(pin,OUTPUT);
analogWrite(pin, value);
if (IS_PIN_PWM(pin)) {
pinMode(PIN_TO_DIGITAL(pin), OUTPUT);
analogWrite(PIN_TO_PWM(pin), value);
}
}
void setup()
@ -24,9 +26,10 @@ void loop()
while(Firmata.available()) {
Firmata.processInput();
}
for(analogPin = 0; analogPin < TOTAL_ANALOG_PINS; analogPin++) {
Firmata.sendAnalog(analogPin, analogRead(analogPin));
}
// do one analogRead per loop, so if PC is sending a lot of
// analog write messages, we will only delay 1 analogRead
Firmata.sendAnalog(analogPin, analogRead(analogPin));
analogPin = analogPin + 1;
if (analogPin >= TOTAL_ANALOG_PINS) analogPin = 0;
}

View File

@ -4,21 +4,21 @@
*/
#include <Firmata.h>
byte previousPIN[2]; // PIN means PORT for input
byte previousPORT[2];
byte previousPIN[TOTAL_PORTS]; // PIN means PORT for input
byte previousPORT[TOTAL_PORTS];
void outputPort(byte portNumber, byte portValue)
{
// only send the data when it changes, otherwise you get too many messages!
if(previousPIN[portNumber] != portValue) {
// only send the data when it changes, otherwise you get too many messages!
if (previousPIN[portNumber] != portValue) {
Firmata.sendDigitalPort(portNumber, portValue);
previousPIN[portNumber] = portValue;
}
}
void setPinModeCallback(byte pin, int mode) {
if(pin > 1) { // don't touch RxTx pins (0,1)
pinMode(pin, mode);
if (IS_PIN_DIGITAL(pin)) {
pinMode(PIN_TO_DIGITAL(pin), mode);
}
}
@ -27,7 +27,7 @@ void digitalWriteCallback(byte port, int value)
byte i;
byte currentPinValue, previousPinValue;
if(value != previousPORT[port]) {
if (port < TOTAL_PORTS && value != previousPORT[port]) {
for(i=0; i<8; i++) {
currentPinValue = (byte) value & (1 << i);
previousPinValue = previousPORT[port] & (1 << i);
@ -49,8 +49,12 @@ void setup()
void loop()
{
outputPort(0, PIND &~ B00000011); // pins 0-7, ignoring Rx/Tx pins (0/1)
outputPort(1, PINB); // pins 8-13
byte i;
for (i=0; i<TOTAL_PORTS; i++) {
outputPort(i, readPort(i));
}
while(Firmata.available()) {
Firmata.processInput();
}

View File

@ -15,8 +15,8 @@
* TODO: use Program Control to load stored profiles from EEPROM
*/
#include <Firmata.h>
#include <Servo.h>
#include <Firmata.h>
/*==============================================================================
* GLOBAL VARIABLES
@ -24,18 +24,20 @@
/* analog inputs */
int analogInputsToReport = 0; // bitwise array to store pin reporting
int analogPin = 0; // counter for reading analog pins
/* digital pins */
byte reportPINs[TOTAL_PORTS]; // PIN == input port
byte previousPINs[TOTAL_PORTS]; // PIN == input port
byte pinStatus[TOTAL_DIGITAL_PINS]; // store pin status, default OUTPUT
byte portStatus[TOTAL_PORTS];
/* digital input ports */
byte reportPINs[TOTAL_PORTS]; // 1 = report this port, 0 = silence
byte previousPINs[TOTAL_PORTS]; // previous 8 bits sent
/* pins configuration */
byte pinConfig[TOTAL_PINS]; // configuration of every pin
byte portConfigInputs[TOTAL_PORTS]; // each bit: 1 = pin in INPUT, 0 = anything else
int pinState[TOTAL_PINS]; // any value that has been written
/* 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)
unsigned long currentMillis; // store the current value from millis()
unsigned long previousMillis; // for comparison with currentMillis
int samplingInterval = 19; // how often to run the main loop (in ms)
Servo servos[MAX_SERVOS];
@ -43,10 +45,12 @@ Servo servos[MAX_SERVOS];
* FUNCTIONS
*============================================================================*/
void outputPort(byte portNumber, byte portValue)
void outputPort(byte portNumber, byte portValue, byte forceSend)
{
portValue = portValue &~ portStatus[portNumber];
if(previousPINs[portNumber] != portValue) {
// pins not configured as INPUT are cleared to zeros
portValue = portValue & portConfigInputs[portNumber];
// only send if the value is different than previously sent
if(forceSend || previousPINs[portNumber] != portValue) {
Firmata.sendDigitalPort(portNumber, portValue);
previousPINs[portNumber] = portValue;
}
@ -57,140 +61,169 @@ void outputPort(byte portNumber, byte portValue)
* to the Serial output queue using Serial.print() */
void checkDigitalInputs(void)
{
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;
}
}
}
/* Using non-looping code allows constants to be given to readPort().
* The compiler will apply substantial optimizations if the inputs
* to readPort() are compile-time constants. */
if (TOTAL_PORTS > 0 && reportPINs[0]) outputPort(0, readPort(0, portConfigInputs[0]), false);
if (TOTAL_PORTS > 1 && reportPINs[1]) outputPort(1, readPort(1, portConfigInputs[1]), false);
if (TOTAL_PORTS > 2 && reportPINs[2]) outputPort(2, readPort(2, portConfigInputs[2]), false);
if (TOTAL_PORTS > 3 && reportPINs[3]) outputPort(3, readPort(3, portConfigInputs[3]), false);
if (TOTAL_PORTS > 4 && reportPINs[4]) outputPort(4, readPort(4, portConfigInputs[4]), false);
if (TOTAL_PORTS > 5 && reportPINs[5]) outputPort(5, readPort(5, portConfigInputs[5]), false);
if (TOTAL_PORTS > 6 && reportPINs[6]) outputPort(6, readPort(6, portConfigInputs[6]), false);
if (TOTAL_PORTS > 7 && reportPINs[7]) outputPort(7, readPort(7, portConfigInputs[7]), false);
if (TOTAL_PORTS > 8 && reportPINs[8]) outputPort(8, readPort(8, portConfigInputs[8]), false);
if (TOTAL_PORTS > 9 && reportPINs[9]) outputPort(9, readPort(9, portConfigInputs[9]), false);
if (TOTAL_PORTS > 10 && reportPINs[10]) outputPort(10, readPort(10, portConfigInputs[10]), false);
if (TOTAL_PORTS > 11 && reportPINs[11]) outputPort(11, readPort(11, portConfigInputs[11]), false);
if (TOTAL_PORTS > 12 && reportPINs[12]) outputPort(12, readPort(12, portConfigInputs[12]), false);
if (TOTAL_PORTS > 13 && reportPINs[13]) outputPort(13, readPort(13, portConfigInputs[13]), false);
if (TOTAL_PORTS > 14 && reportPINs[14]) outputPort(14, readPort(14, portConfigInputs[14]), false);
if (TOTAL_PORTS > 15 && reportPINs[15]) outputPort(15, readPort(15, portConfigInputs[15]), false);
}
// -----------------------------------------------------------------------------
/* sets the pin mode to the correct state and sets the relevant bits in the
* two bit-arrays that track Digital I/O and PWM status
*/
void setPinModeCallback(byte pin, int mode) {
byte port = 0;
byte offset = 0;
// 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;
void setPinModeCallback(byte pin, int mode)
{
if (IS_PIN_SERVO(pin) && mode != SERVO && servos[PIN_TO_SERVO(pin)].attached()) {
servos[PIN_TO_SERVO(pin)].detach();
}
if(pin > 1) { // ignore RxTx (pins 0 and 1)
if (isServoSupportedPin(pin) && mode != SERVO)
if (servos[pin - FIRST_SERVO_PIN].attached())
servos[pin - FIRST_SERVO_PIN].detach();
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:
// TODO: Support Arduino Mega
if (isServoSupportedPin(pin)) {
pinStatus[pin] = mode;
if (!servos[pin - FIRST_SERVO_PIN].attached())
servos[pin - FIRST_SERVO_PIN].attach(pin);
} else
Firmata.sendString("Servo only on pins from 2 to 13");
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
if (IS_PIN_ANALOG(pin)) {
reportAnalogCallback(PIN_TO_ANALOG(pin), mode == ANALOG ? 1 : 0); // turn on/off reporting
}
if (IS_PIN_DIGITAL(pin)) {
if (mode == INPUT) {
portConfigInputs[pin/8] |= (1 << (pin & 7));
} else {
portConfigInputs[pin/8] &= ~(1 << (pin & 7));
}
// TODO: save status to EEPROM here, if changed
}
pinState[pin] = 0;
switch(mode) {
case ANALOG:
if (IS_PIN_ANALOG(pin)) {
if (IS_PIN_DIGITAL(pin)) {
pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver
digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups
}
pinConfig[pin] = ANALOG;
}
break;
case INPUT:
if (IS_PIN_DIGITAL(pin)) {
pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver
digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups
pinConfig[pin] = INPUT;
}
break;
case OUTPUT:
if (IS_PIN_DIGITAL(pin)) {
digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM
pinMode(PIN_TO_DIGITAL(pin), OUTPUT);
pinConfig[pin] = OUTPUT;
}
break;
case PWM:
if (IS_PIN_PWM(pin)) {
pinMode(PIN_TO_PWM(pin), OUTPUT);
analogWrite(PIN_TO_PWM(pin), 0);
pinConfig[pin] = PWM;
}
break;
case SERVO:
if (IS_PIN_SERVO(pin)) {
pinConfig[pin] = SERVO;
if (!servos[PIN_TO_SERVO(pin)].attached()) {
servos[PIN_TO_SERVO(pin)].attach(PIN_TO_DIGITAL(pin));
} else {
Firmata.sendString("Servo only on pins from 2 to 13");
}
}
break;
case I2C:
pinConfig[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)
{
switch(pinStatus[pin]) {
case SERVO:
if (isServoSupportedPin(pin))
servos[pin - FIRST_SERVO_PIN].write(value);
break;
case PWM:
analogWrite(pin, value);
break;
if (pin < TOTAL_PINS) {
switch(pinConfig[pin]) {
case SERVO:
if (IS_PIN_SERVO(pin))
servos[PIN_TO_SERVO(pin)].write(value);
pinState[pin] = value;
break;
case PWM:
if (IS_PIN_PWM(pin))
analogWrite(PIN_TO_PWM(pin), value);
pinState[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
byte pin;
byte pinModeMask;
for(pin=0; pin<8; pin++)
if(pinStatus[pin] == OUTPUT)
pinModeMask += 1 << pin;
PORTC = (byte)value & pinModeMask;
break;
byte pin, lastPin, mask=1, pinWriteMask=0;
if (port < TOTAL_PORTS) {
// create a mask of the pins on this port that are writable.
lastPin = port*8+8;
if (lastPin > TOTAL_PINS) lastPin = TOTAL_PINS;
for (pin=port*8; pin < lastPin; pin++) {
// do not disturb non-digital pins (eg, Rx & Tx)
if (IS_PIN_DIGITAL(pin)) {
// only write to OUTPUT and INPUT (enables pullup)
// do not touch pins in PWM, ANALOG, SERVO or other modes
if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) {
pinWriteMask |= mask;
pinState[pin] = ((byte)value & mask) ? 1 : 0;
}
}
mask = mask << 1;
}
writePort(port, (byte)value, pinWriteMask);
}
}
// -----------------------------------------------------------------------------
/* sets bits in a bit array (int) to toggle the reporting of the analogIns
*/
//void FirmataClass::setAnalogPinReporting(byte pin, byte state) {
//}
void reportAnalogCallback(byte pin, int value)
void reportAnalogCallback(byte analogPin, int value)
{
if(value == 0) {
analogInputsToReport = analogInputsToReport &~ (1 << pin);
}
else { // everything but 0 enables reporting of that pin
analogInputsToReport = analogInputsToReport | (1 << pin);
if (analogPin < TOTAL_ANALOG_PINS) {
if(value == 0) {
analogInputsToReport = analogInputsToReport &~ (1 << analogPin);
} else {
analogInputsToReport = analogInputsToReport | (1 << analogPin);
}
}
// 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;
if (port < TOTAL_PORTS) {
reportPINs[port] = (byte)value;
}
// do not disable analog reporting on these 8 pins, to allow some
// pins used for digital, others analog. Instead, allow both types
// of reporting to be enabled, but check if the pin is configured
// as analog when sampling the analog inputs. Likewise, while
// scanning digital pins, portConfigInputs will mask off values from any
// pins configured as analog
}
/*==============================================================================
@ -207,11 +240,11 @@ void sysexCallback(byte command, byte argc, byte *argv)
int minPulse = argv[1] + (argv[2] << 7);
int maxPulse = argv[3] + (argv[4] << 7);
if (isServoSupportedPin(pin)) {
if (IS_PIN_SERVO(pin)) {
// servos are pins from 2 to 13, so offset for array
if (servos[pin - FIRST_SERVO_PIN].attached())
servos[pin - FIRST_SERVO_PIN].detach();
servos[pin - FIRST_SERVO_PIN].attach(pin, minPulse, maxPulse);
if (servos[PIN_TO_SERVO(pin)].attached())
servos[PIN_TO_SERVO(pin)].detach();
servos[PIN_TO_SERVO(pin)].attach(PIN_TO_DIGITAL(pin), minPulse, maxPulse);
setPinModeCallback(pin, SERVO);
}
}
@ -222,13 +255,66 @@ void sysexCallback(byte command, byte argc, byte *argv)
else
Firmata.sendString("Not enough data");
break;
case EXTENDED_ANALOG:
if (argc > 1) {
int val = argv[1];
if (argc > 2) val |= (argv[2] << 7);
if (argc > 3) val |= (argv[3] << 14);
analogWriteCallback(argv[0], val);
}
break;
case CAPABILITY_QUERY:
Serial.write(START_SYSEX);
Serial.write(CAPABILITY_RESPONSE);
for (byte pin=0; pin < TOTAL_PINS; pin++) {
if (IS_PIN_DIGITAL(pin)) {
Serial.write((byte)INPUT);
Serial.write(1);
Serial.write((byte)OUTPUT);
Serial.write(1);
}
if (IS_PIN_ANALOG(pin)) {
Serial.write(ANALOG);
Serial.write(10);
}
if (IS_PIN_PWM(pin)) {
Serial.write(PWM);
Serial.write(8);
}
if (IS_PIN_SERVO(pin)) {
Serial.write(SERVO);
Serial.write(14);
}
Serial.write(127);
}
Serial.write(END_SYSEX);
break;
case PIN_STATE_QUERY:
if (argc > 0) {
byte pin=argv[0];
Serial.write(START_SYSEX);
Serial.write(PIN_STATE_RESPONSE);
Serial.write(pin);
if (pin < TOTAL_PINS) {
Serial.write((byte)pinConfig[pin]);
Serial.write((byte)pinState[pin] & 0x7F);
if (pinState[pin] & 0xFF80) Serial.write((byte)(pinState[pin] >> 7) & 0x7F);
if (pinState[pin] & 0xC000) Serial.write((byte)(pinState[pin] >> 14) & 0x7F);
}
Serial.write(END_SYSEX);
}
break;
case ANALOG_MAPPING_QUERY:
Serial.write(START_SYSEX);
Serial.write(ANALOG_MAPPING_RESPONSE);
for (byte pin=0; pin < TOTAL_PINS; pin++) {
Serial.write(IS_PIN_ANALOG(pin) ? PIN_TO_ANALOG(pin) : 127);
}
Serial.write(END_SYSEX);
break;
}
}
boolean isServoSupportedPin(byte pin)
{
return ((FIRST_SERVO_PIN <= pin) && (pin <= (FIRST_SERVO_PIN + MAX_SERVOS)));
}
/*==============================================================================
* SETUP()
@ -237,7 +323,7 @@ void setup()
{
byte i;
Firmata.setFirmwareVersion(2, 1);
Firmata.setFirmwareVersion(2, 2);
Firmata.attach(ANALOG_MESSAGE, analogWriteCallback);
Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback);
@ -246,32 +332,34 @@ void setup()
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;
for(i=0; i < FIRST_ANALOG_PIN; ++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
/* 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);
/* these are initialized to zero by the compiler startup code
for (i=0; i < TOTAL_PORTS; i++) {
reportPINs[i] = false;
portConfigInputs[i] = 0;
previousPINs[i] = 0;
}
*/
for (i=0; i < TOTAL_PINS; i++) {
if (IS_PIN_ANALOG(i)) {
// turns off pullup, configures everything
setPinModeCallback(i, ANALOG);
} else {
// sets the output to 0, configures portConfigInputs
setPinModeCallback(i, OUTPUT);
}
}
// by defult, do not report any analog inputs
analogInputsToReport = 0;
Firmata.begin(57600);
/* send digital inputs to set the initial state on the host computer,
* since once in the loop(), this firmware will only send on change */
for (i=0; i < TOTAL_PORTS; i++) {
outputPort(i, readPort(i, portConfigInputs[i]), true);
}
}
/*==============================================================================
@ -279,23 +367,31 @@ void setup()
*============================================================================*/
void loop()
{
/* DIGITALREAD - as fast as possible, check for changes and output them */
byte pin, analogPin;
/* DIGITALREAD - as fast as possible, check for changes and output them to the
* FTDI buffer using Serial.print() */
checkDigitalInputs();
/* SERIALREAD - processing incoming messagse as soon as possible, while still
* checking digital inputs. */
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. */
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. Ideally this could send an "event character" every 4 ms to
* trigger the buffer to dump. */
/* ANALOGREAD - do all of the analogReads() once per poll cycle */
for(analogPin=0;analogPin<TOTAL_ANALOG_PINS;analogPin++) {
if( analogInputsToReport & (1 << analogPin) ) {
Firmata.sendAnalog(analogPin, analogRead(analogPin));
if (currentMillis - previousMillis > samplingInterval) {
previousMillis += samplingInterval;
/* ANALOGREAD - do all analogReads() at the configured sampling interval */
for(pin=0; pin<TOTAL_PINS; pin++) {
if (IS_PIN_ANALOG(pin) && pinConfig[pin] == ANALOG) {
analogPin = PIN_TO_ANALOG(pin);
if (analogInputsToReport & (1 << analogPin)) {
Firmata.sendAnalog(analogPin, analogRead(analogPin));
}
}
}
}