1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-08-07 00:04:36 +03: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

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));
}
}
}
}