1313 Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights reserved.
1414 Copyright (C) 2010-2011 Paul Stoffregen. All rights reserved.
1515 Copyright (C) 2009 Shigeru Kobayashi. All rights reserved.
16- Copyright (C) 2009-2013 Jeff Hoefs. All rights reserved.
16+ Copyright (C) 2009-2015 Jeff Hoefs. All rights reserved.
1717
1818 This library is free software; you can redistribute it and/or
1919 modify it under the terms of the GNU Lesser General Public
@@ -77,16 +77,62 @@ struct i2c_device_info {
7777/* for i2c read continuous more */
7878i2c_device_info query[MAX_QUERIES];
7979
80+ boolean isResetting = false ;
81+
8082byte i2cRxData[32 ];
8183boolean isI2CEnabled = false ;
8284signed char queryIndex = -1 ;
8385unsigned int i2cReadDelayTime = 0 ; // default delay time between i2c read request and Wire.requestFrom()
8486
8587Servo servos[MAX_SERVOS];
88+ byte servoPinMap[TOTAL_PINS];
89+ byte detachedServos[MAX_SERVOS];
90+ byte detachedServoCount = 0 ;
91+ byte servoCount = 0 ;
92+
93+
8694/* ==============================================================================
8795 * FUNCTIONS
8896 *============================================================================*/
8997
98+ void attachServo (byte pin, int minPulse, int maxPulse)
99+ {
100+ if (servoCount < MAX_SERVOS) {
101+ // reuse indexes of detached servos until all have been reallocated
102+ if (detachedServoCount > 0 ) {
103+ servoPinMap[pin] = detachedServos[detachedServoCount - 1 ];
104+ if (detachedServoCount > 0 ) detachedServoCount--;
105+ } else {
106+ servoPinMap[pin] = servoCount;
107+ servoCount++;
108+ }
109+ if (minPulse > 0 && maxPulse > 0 ) {
110+ servos[servoPinMap[pin]].attach (PIN_TO_DIGITAL (pin), minPulse, maxPulse);
111+ } else {
112+ servos[servoPinMap[pin]].attach (PIN_TO_DIGITAL (pin));
113+ }
114+ } else {
115+ Firmata.sendString (" Max servos attached" );
116+ }
117+ }
118+
119+ void detachServo (byte pin)
120+ {
121+ servos[servoPinMap[pin]].detach ();
122+ // if we're detaching the last servo, decrement the count
123+ // otherwise store the index of the detached servo
124+ if (servoPinMap[pin] == servoCount && servoCount > 0 ) {
125+ servoCount--;
126+ } else if (servoCount > 0 ) {
127+ // keep track of detached servos because we want to reuse their indexes
128+ // before incrementing the count of attached servos
129+ detachedServoCount++;
130+ detachedServos[detachedServoCount - 1 ] = servoPinMap[pin];
131+ }
132+
133+ servoPinMap[pin] = 255 ;
134+ }
135+
90136void readAndReportData (byte address, int theRegister, byte numBytes) {
91137 // allow I2C requests that don't require a register read
92138 // for example, some devices using an interrupt pin to signify new data available
@@ -111,23 +157,21 @@ void readAndReportData(byte address, int theRegister, byte numBytes) {
111157 Wire.requestFrom (address, numBytes); // all bytes are returned in requestFrom
112158
113159 // check to be sure correct number of bytes were returned by slave
114- if (numBytes == Wire.available ()) {
115- i2cRxData[0 ] = address;
116- i2cRxData[1 ] = theRegister;
117- for (int i = 0 ; i < numBytes; i++) {
160+ if (numBytes < Wire.available ()) {
161+ Firmata.sendString (" I2C Read Error: Too many bytes received" );
162+ } else if (numBytes > Wire.available ()) {
163+ Firmata.sendString (" I2C Read Error: Too few bytes received" );
164+ }
165+
166+ i2cRxData[0 ] = address;
167+ i2cRxData[1 ] = theRegister;
168+
169+ for (int i = 0 ; i < numBytes && Wire.available (); i++) {
118170#if ARDUINO >= 100
119- i2cRxData[2 + i] = Wire.read ();
171+ i2cRxData[2 + i] = Wire.read ();
120172#else
121- i2cRxData[2 + i] = Wire.receive ();
173+ i2cRxData[2 + i] = Wire.receive ();
122174#endif
123- }
124- }
125- else {
126- if (numBytes > Wire.available ()) {
127- Firmata.sendString (" I2C: Too many bytes received" );
128- } else {
129- Firmata.sendString (" I2C: Too few bytes received" );
130- }
131175 }
132176
133177 // send slave address, register and received bytes
@@ -182,8 +226,10 @@ void setPinModeCallback(byte pin, int mode)
182226 // the following if statements should reconfigure the pins properly
183227 disableI2CPins ();
184228 }
185- if (IS_PIN_SERVO (pin) && mode != SERVO && servos[PIN_TO_SERVO (pin)].attached ()) {
186- servos[PIN_TO_SERVO (pin)].detach ();
229+ if (IS_PIN_DIGITAL (pin) && mode != SERVO) {
230+ if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached ()) {
231+ detachServo (pin);
232+ }
187233 }
188234 if (IS_PIN_ANALOG (pin)) {
189235 reportAnalogCallback (PIN_TO_ANALOG (pin), mode == ANALOG ? 1 : 0 ); // turn on/off reporting
@@ -228,10 +274,12 @@ void setPinModeCallback(byte pin, int mode)
228274 }
229275 break ;
230276 case SERVO:
231- if (IS_PIN_SERVO (pin)) {
277+ if (IS_PIN_DIGITAL (pin)) {
232278 pinConfig[pin] = SERVO;
233- if (!servos[PIN_TO_SERVO (pin)].attached ()) {
234- servos[PIN_TO_SERVO (pin)].attach (PIN_TO_DIGITAL (pin));
279+ if (servoPinMap[pin] == 255 || !servos[servoPinMap[pin]].attached ()) {
280+ // pass -1 for min and max pulse values to use default values set
281+ // by Servo library
282+ attachServo (pin, -1 , -1 );
235283 }
236284 }
237285 break ;
@@ -253,8 +301,8 @@ void analogWriteCallback(byte pin, int value)
253301 if (pin < TOTAL_PINS) {
254302 switch (pinConfig[pin]) {
255303 case SERVO:
256- if (IS_PIN_SERVO (pin))
257- servos[PIN_TO_SERVO ( pin) ].write (value);
304+ if (IS_PIN_DIGITAL (pin))
305+ servos[servoPinMap[ pin] ].write (value);
258306 pinState[pin] = value;
259307 break ;
260308 case PWM:
@@ -303,6 +351,14 @@ void reportAnalogCallback(byte analogPin, int value)
303351 analogInputsToReport = analogInputsToReport & ~ (1 << analogPin);
304352 } else {
305353 analogInputsToReport = analogInputsToReport | (1 << analogPin);
354+ // prevent during system reset or all analog pin values will be reported
355+ // which may report noise for unconnected analog pins
356+ if (!isResetting) {
357+ // Send pin value immediately. This is helpful when connected via
358+ // ethernet, wi-fi or bluetooth so pin states can be known upon
359+ // reconnecting.
360+ Firmata.sendAnalog (analogPin, analogRead (analogPin));
361+ }
306362 }
307363 }
308364 // TODO: save status to EEPROM here, if changed
@@ -312,6 +368,10 @@ void reportDigitalCallback(byte port, int value)
312368{
313369 if (port < TOTAL_PORTS) {
314370 reportPINs[port] = (byte)value;
371+ // Send port value immediately. This is helpful when connected via
372+ // ethernet, wi-fi or bluetooth so pin states can be known upon
373+ // reconnecting.
374+ if (value) outputPort (port, readPort (port, portConfigInputs[port]), true );
315375 }
316376 // do not disable analog reporting on these 8 pins, to allow some
317377 // pins used for digital, others analog. Instead, allow both types
@@ -412,7 +472,7 @@ void sysexCallback(byte command, byte argc, byte *argv)
412472 for (byte i = queryIndexToSkip; i < queryIndex + 1 ; i++) {
413473 if (i < MAX_QUERIES) {
414474 query[i].addr = query[i + 1 ].addr ;
415- query[i].reg = query[i + 1 ].addr ;
475+ query[i].reg = query[i + 1 ].reg ;
416476 query[i].bytes = query[i + 1 ].bytes ;
417477 }
418478 }
@@ -442,10 +502,11 @@ void sysexCallback(byte command, byte argc, byte *argv)
442502 int minPulse = argv[1 ] + (argv[2 ] << 7 );
443503 int maxPulse = argv[3 ] + (argv[4 ] << 7 );
444504
445- if (IS_PIN_SERVO (pin)) {
446- if (servos[PIN_TO_SERVO (pin)].attached ())
447- servos[PIN_TO_SERVO (pin)].detach ();
448- servos[PIN_TO_SERVO (pin)].attach (PIN_TO_DIGITAL (pin), minPulse, maxPulse);
505+ if (IS_PIN_DIGITAL (pin)) {
506+ if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached ()) {
507+ detachServo (pin);
508+ }
509+ attachServo (pin, minPulse, maxPulse);
449510 setPinModeCallback (pin, SERVO);
450511 }
451512 }
@@ -486,7 +547,7 @@ void sysexCallback(byte command, byte argc, byte *argv)
486547 Firmata.write (PWM);
487548 Firmata.write (8 );
488549 }
489- if (IS_PIN_SERVO (pin)) {
550+ if (IS_PIN_DIGITAL (pin)) {
490551 Firmata.write (SERVO);
491552 Firmata.write (14 );
492553 }
@@ -547,8 +608,6 @@ void disableI2CPins() {
547608 isI2CEnabled = false ;
548609 // disable read continuous mode for all devices
549610 queryIndex = -1 ;
550- // uncomment the following if or when the end() method is added to Wire library
551- // Wire.end();
552611}
553612
554613/* ==============================================================================
@@ -557,30 +616,38 @@ void disableI2CPins() {
557616
558617void systemResetCallback ()
559618{
619+ isResetting = true ;
560620 // initialize a defalt state
561621 // TODO: option to load config from EEPROM instead of default
562622 if (isI2CEnabled) {
563623 disableI2CPins ();
564624 }
625+
565626 for (byte i = 0 ; i < TOTAL_PORTS; i++) {
566627 reportPINs[i] = false ; // by default, reporting off
567628 portConfigInputs[i] = 0 ; // until activated
568629 previousPINs[i] = 0 ;
569630 }
570- // pins with analog capability default to analog input
571- // otherwise, pins default to digital output
631+
572632 for (byte i = 0 ; i < TOTAL_PINS; i++) {
633+ // pins with analog capability default to analog input
634+ // otherwise, pins default to digital output
573635 if (IS_PIN_ANALOG (i)) {
574636 // turns off pullup, configures everything
575637 setPinModeCallback (i, ANALOG);
576638 } else {
577639 // sets the output to 0, configures portConfigInputs
578640 setPinModeCallback (i, OUTPUT);
579641 }
642+
643+ servoPinMap[i] = 255 ;
580644 }
581645 // by default, do not report any analog inputs
582646 analogInputsToReport = 0 ;
583647
648+ detachedServoCount = 0 ;
649+ servoCount = 0 ;
650+
584651 /* send digital inputs to set the initial state on the host computer,
585652 * since once in the loop(), this firmware will only send on change */
586653 /*
@@ -590,6 +657,7 @@ void systemResetCallback()
590657 outputPort(i, readPort(i, portConfigInputs[i]), true);
591658 }
592659 */
660+ isResetting = false ;
593661}
594662
595663void setup ()
0 commit comments