source: arduino-1-6-7/trunk/fuentes/arduino-ide-amd64/libraries/Firmata/examples/StandardFirmata/StandardFirmata.ino @ 46

Last change on this file since 46 was 46, checked in by jrpelegrina, 4 years ago

First release to Xenial

  • Property svn:executable set to *
File size: 25.7 KB
Line 
1/*
2  Firmata is a generic protocol for communicating with microcontrollers
3  from software on a host computer. It is intended to work with
4  any host computer software package.
5
6  To download a host software package, please clink on the following link
7  to open the list of Firmata client libraries your default browser.
8
9  https://github.com/firmata/arduino#firmata-client-libraries
10
11  Copyright (C) 2006-2008 Hans-Christoph Steiner.  All rights reserved.
12  Copyright (C) 2010-2011 Paul Stoffregen.  All rights reserved.
13  Copyright (C) 2009 Shigeru Kobayashi.  All rights reserved.
14  Copyright (C) 2009-2015 Jeff Hoefs.  All rights reserved.
15
16  This library is free software; you can redistribute it and/or
17  modify it under the terms of the GNU Lesser General Public
18  License as published by the Free Software Foundation; either
19  version 2.1 of the License, or (at your option) any later version.
20
21  See file LICENSE.txt for further informations on licensing terms.
22
23  Last updated by Jeff Hoefs: November 7th, 2015
24*/
25
26#include <Servo.h>
27#include <Wire.h>
28#include <Firmata.h>
29
30#define I2C_WRITE                   B00000000
31#define I2C_READ                    B00001000
32#define I2C_READ_CONTINUOUSLY       B00010000
33#define I2C_STOP_READING            B00011000
34#define I2C_READ_WRITE_MODE_MASK    B00011000
35#define I2C_10BIT_ADDRESS_MODE_MASK B00100000
36#define I2C_MAX_QUERIES             8
37#define I2C_REGISTER_NOT_SPECIFIED  -1
38
39// the minimum interval for sampling analog input
40#define MINIMUM_SAMPLING_INTERVAL   1
41
42
43/*==============================================================================
44 * GLOBAL VARIABLES
45 *============================================================================*/
46
47/* analog inputs */
48int analogInputsToReport = 0; // bitwise array to store pin reporting
49
50/* digital input ports */
51byte reportPINs[TOTAL_PORTS];       // 1 = report this port, 0 = silence
52byte previousPINs[TOTAL_PORTS];     // previous 8 bits sent
53
54/* pins configuration */
55byte pinConfig[TOTAL_PINS];         // configuration of every pin
56byte portConfigInputs[TOTAL_PORTS]; // each bit: 1 = pin in INPUT, 0 = anything else
57int pinState[TOTAL_PINS];           // any value that has been written
58
59/* timer variables */
60unsigned long currentMillis;        // store the current value from millis()
61unsigned long previousMillis;       // for comparison with currentMillis
62unsigned int samplingInterval = 19; // how often to run the main loop (in ms)
63
64/* i2c data */
65struct i2c_device_info {
66  byte addr;
67  int reg;
68  byte bytes;
69};
70
71/* for i2c read continuous more */
72i2c_device_info query[I2C_MAX_QUERIES];
73
74byte i2cRxData[32];
75boolean isI2CEnabled = false;
76signed char queryIndex = -1;
77// default delay time between i2c read request and Wire.requestFrom()
78unsigned int i2cReadDelayTime = 0;
79
80Servo servos[MAX_SERVOS];
81byte servoPinMap[TOTAL_PINS];
82byte detachedServos[MAX_SERVOS];
83byte detachedServoCount = 0;
84byte servoCount = 0;
85
86boolean isResetting = false;
87
88/* utility functions */
89void wireWrite(byte data)
90{
91#if ARDUINO >= 100
92  Wire.write((byte)data);
93#else
94  Wire.send(data);
95#endif
96}
97
98byte wireRead(void)
99{
100#if ARDUINO >= 100
101  return Wire.read();
102#else
103  return Wire.receive();
104#endif
105}
106
107/*==============================================================================
108 * FUNCTIONS
109 *============================================================================*/
110
111void attachServo(byte pin, int minPulse, int maxPulse)
112{
113  if (servoCount < MAX_SERVOS) {
114    // reuse indexes of detached servos until all have been reallocated
115    if (detachedServoCount > 0) {
116      servoPinMap[pin] = detachedServos[detachedServoCount - 1];
117      if (detachedServoCount > 0) detachedServoCount--;
118    } else {
119      servoPinMap[pin] = servoCount;
120      servoCount++;
121    }
122    if (minPulse > 0 && maxPulse > 0) {
123      servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin), minPulse, maxPulse);
124    } else {
125      servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin));
126    }
127  } else {
128    Firmata.sendString("Max servos attached");
129  }
130}
131
132void detachServo(byte pin)
133{
134  servos[servoPinMap[pin]].detach();
135  // if we're detaching the last servo, decrement the count
136  // otherwise store the index of the detached servo
137  if (servoPinMap[pin] == servoCount && servoCount > 0) {
138    servoCount--;
139  } else if (servoCount > 0) {
140    // keep track of detached servos because we want to reuse their indexes
141    // before incrementing the count of attached servos
142    detachedServoCount++;
143    detachedServos[detachedServoCount - 1] = servoPinMap[pin];
144  }
145
146  servoPinMap[pin] = 255;
147}
148
149void readAndReportData(byte address, int theRegister, byte numBytes) {
150  // allow I2C requests that don't require a register read
151  // for example, some devices using an interrupt pin to signify new data available
152  // do not always require the register read so upon interrupt you call Wire.requestFrom()
153  if (theRegister != I2C_REGISTER_NOT_SPECIFIED) {
154    Wire.beginTransmission(address);
155    wireWrite((byte)theRegister);
156    Wire.endTransmission();
157    // do not set a value of 0
158    if (i2cReadDelayTime > 0) {
159      // delay is necessary for some devices such as WiiNunchuck
160      delayMicroseconds(i2cReadDelayTime);
161    }
162  } else {
163    theRegister = 0;  // fill the register with a dummy value
164  }
165
166  Wire.requestFrom(address, numBytes);  // all bytes are returned in requestFrom
167
168  // check to be sure correct number of bytes were returned by slave
169  if (numBytes < Wire.available()) {
170    Firmata.sendString("I2C: Too many bytes received");
171  } else if (numBytes > Wire.available()) {
172    Firmata.sendString("I2C: Too few bytes received");
173  }
174
175  i2cRxData[0] = address;
176  i2cRxData[1] = theRegister;
177
178  for (int i = 0; i < numBytes && Wire.available(); i++) {
179    i2cRxData[2 + i] = wireRead();
180  }
181
182  // send slave address, register and received bytes
183  Firmata.sendSysex(SYSEX_I2C_REPLY, numBytes + 2, i2cRxData);
184}
185
186void outputPort(byte portNumber, byte portValue, byte forceSend)
187{
188  // pins not configured as INPUT are cleared to zeros
189  portValue = portValue & portConfigInputs[portNumber];
190  // only send if the value is different than previously sent
191  if (forceSend || previousPINs[portNumber] != portValue) {
192    Firmata.sendDigitalPort(portNumber, portValue);
193    previousPINs[portNumber] = portValue;
194  }
195}
196
197/* -----------------------------------------------------------------------------
198 * check all the active digital inputs for change of state, then add any events
199 * to the Serial output queue using Serial.print() */
200void checkDigitalInputs(void)
201{
202  /* Using non-looping code allows constants to be given to readPort().
203   * The compiler will apply substantial optimizations if the inputs
204   * to readPort() are compile-time constants. */
205  if (TOTAL_PORTS > 0 && reportPINs[0]) outputPort(0, readPort(0, portConfigInputs[0]), false);
206  if (TOTAL_PORTS > 1 && reportPINs[1]) outputPort(1, readPort(1, portConfigInputs[1]), false);
207  if (TOTAL_PORTS > 2 && reportPINs[2]) outputPort(2, readPort(2, portConfigInputs[2]), false);
208  if (TOTAL_PORTS > 3 && reportPINs[3]) outputPort(3, readPort(3, portConfigInputs[3]), false);
209  if (TOTAL_PORTS > 4 && reportPINs[4]) outputPort(4, readPort(4, portConfigInputs[4]), false);
210  if (TOTAL_PORTS > 5 && reportPINs[5]) outputPort(5, readPort(5, portConfigInputs[5]), false);
211  if (TOTAL_PORTS > 6 && reportPINs[6]) outputPort(6, readPort(6, portConfigInputs[6]), false);
212  if (TOTAL_PORTS > 7 && reportPINs[7]) outputPort(7, readPort(7, portConfigInputs[7]), false);
213  if (TOTAL_PORTS > 8 && reportPINs[8]) outputPort(8, readPort(8, portConfigInputs[8]), false);
214  if (TOTAL_PORTS > 9 && reportPINs[9]) outputPort(9, readPort(9, portConfigInputs[9]), false);
215  if (TOTAL_PORTS > 10 && reportPINs[10]) outputPort(10, readPort(10, portConfigInputs[10]), false);
216  if (TOTAL_PORTS > 11 && reportPINs[11]) outputPort(11, readPort(11, portConfigInputs[11]), false);
217  if (TOTAL_PORTS > 12 && reportPINs[12]) outputPort(12, readPort(12, portConfigInputs[12]), false);
218  if (TOTAL_PORTS > 13 && reportPINs[13]) outputPort(13, readPort(13, portConfigInputs[13]), false);
219  if (TOTAL_PORTS > 14 && reportPINs[14]) outputPort(14, readPort(14, portConfigInputs[14]), false);
220  if (TOTAL_PORTS > 15 && reportPINs[15]) outputPort(15, readPort(15, portConfigInputs[15]), false);
221}
222
223// -----------------------------------------------------------------------------
224/* sets the pin mode to the correct state and sets the relevant bits in the
225 * two bit-arrays that track Digital I/O and PWM status
226 */
227void setPinModeCallback(byte pin, int mode)
228{
229  if (pinConfig[pin] == PIN_MODE_IGNORE)
230    return;
231
232  if (pinConfig[pin] == PIN_MODE_I2C && isI2CEnabled && mode != PIN_MODE_I2C) {
233    // disable i2c so pins can be used for other functions
234    // the following if statements should reconfigure the pins properly
235    disableI2CPins();
236  }
237  if (IS_PIN_DIGITAL(pin) && mode != PIN_MODE_SERVO) {
238    if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) {
239      detachServo(pin);
240    }
241  }
242  if (IS_PIN_ANALOG(pin)) {
243    reportAnalogCallback(PIN_TO_ANALOG(pin), mode == PIN_MODE_ANALOG ? 1 : 0); // turn on/off reporting
244  }
245  if (IS_PIN_DIGITAL(pin)) {
246    if (mode == INPUT || mode == PIN_MODE_PULLUP) {
247      portConfigInputs[pin / 8] |= (1 << (pin & 7));
248    } else {
249      portConfigInputs[pin / 8] &= ~(1 << (pin & 7));
250    }
251  }
252  pinState[pin] = 0;
253  switch (mode) {
254    case PIN_MODE_ANALOG:
255      if (IS_PIN_ANALOG(pin)) {
256        if (IS_PIN_DIGITAL(pin)) {
257          pinMode(PIN_TO_DIGITAL(pin), INPUT);    // disable output driver
258#if ARDUINO <= 100
259          // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.6
260          digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups
261#endif
262        }
263        pinConfig[pin] = PIN_MODE_ANALOG;
264      }
265      break;
266    case INPUT:
267      if (IS_PIN_DIGITAL(pin)) {
268        pinMode(PIN_TO_DIGITAL(pin), INPUT);    // disable output driver
269#if ARDUINO <= 100
270        // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.6
271        digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups
272#endif
273        pinConfig[pin] = INPUT;
274      }
275      break;
276    case PIN_MODE_PULLUP:
277      if (IS_PIN_DIGITAL(pin)) {
278        pinMode(PIN_TO_DIGITAL(pin), INPUT_PULLUP);
279        pinConfig[pin] = PIN_MODE_PULLUP;
280        pinState[pin] = 1;
281      }
282      break;
283    case OUTPUT:
284      if (IS_PIN_DIGITAL(pin)) {
285        digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM
286        pinMode(PIN_TO_DIGITAL(pin), OUTPUT);
287        pinConfig[pin] = OUTPUT;
288      }
289      break;
290    case PIN_MODE_PWM:
291      if (IS_PIN_PWM(pin)) {
292        pinMode(PIN_TO_PWM(pin), OUTPUT);
293        analogWrite(PIN_TO_PWM(pin), 0);
294        pinConfig[pin] = PIN_MODE_PWM;
295      }
296      break;
297    case PIN_MODE_SERVO:
298      if (IS_PIN_DIGITAL(pin)) {
299        pinConfig[pin] = PIN_MODE_SERVO;
300        if (servoPinMap[pin] == 255 || !servos[servoPinMap[pin]].attached()) {
301          // pass -1 for min and max pulse values to use default values set
302          // by Servo library
303          attachServo(pin, -1, -1);
304        }
305      }
306      break;
307    case PIN_MODE_I2C:
308      if (IS_PIN_I2C(pin)) {
309        // mark the pin as i2c
310        // the user must call I2C_CONFIG to enable I2C for a device
311        pinConfig[pin] = PIN_MODE_I2C;
312      }
313      break;
314    default:
315      Firmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM
316  }
317  // TODO: save status to EEPROM here, if changed
318}
319
320/*
321 * Sets the value of an individual pin. Useful if you want to set a pin value but
322 * are not tracking the digital port state.
323 * Can only be used on pins configured as OUTPUT.
324 * Cannot be used to enable pull-ups on Digital INPUT pins.
325 */
326void setPinValueCallback(byte pin, int value)
327{
328  if (pin < TOTAL_PINS && IS_PIN_DIGITAL(pin)) {
329    if (pinConfig[pin] == OUTPUT) {
330      pinState[pin] = value;
331      digitalWrite(PIN_TO_DIGITAL(pin), value);
332    }
333  }
334}
335
336void analogWriteCallback(byte pin, int value)
337{
338  if (pin < TOTAL_PINS) {
339    switch (pinConfig[pin]) {
340      case PIN_MODE_SERVO:
341        if (IS_PIN_DIGITAL(pin))
342          servos[servoPinMap[pin]].write(value);
343        pinState[pin] = value;
344        break;
345      case PIN_MODE_PWM:
346        if (IS_PIN_PWM(pin))
347          analogWrite(PIN_TO_PWM(pin), value);
348        pinState[pin] = value;
349        break;
350    }
351  }
352}
353
354void digitalWriteCallback(byte port, int value)
355{
356  byte pin, lastPin, pinValue, mask = 1, pinWriteMask = 0;
357
358  if (port < TOTAL_PORTS) {
359    // create a mask of the pins on this port that are writable.
360    lastPin = port * 8 + 8;
361    if (lastPin > TOTAL_PINS) lastPin = TOTAL_PINS;
362    for (pin = port * 8; pin < lastPin; pin++) {
363      // do not disturb non-digital pins (eg, Rx & Tx)
364      if (IS_PIN_DIGITAL(pin)) {
365        // do not touch pins in PWM, ANALOG, SERVO or other modes
366        if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) {
367          pinValue = ((byte)value & mask) ? 1 : 0;
368          if (pinConfig[pin] == OUTPUT) {
369            pinWriteMask |= mask;
370          } else if (pinConfig[pin] == INPUT && pinValue == 1 && pinState[pin] != 1) {
371            // only handle INPUT here for backwards compatibility
372#if ARDUINO > 100
373            pinMode(pin, INPUT_PULLUP);
374#else
375            // only write to the INPUT pin to enable pullups if Arduino v1.0.0 or earlier
376            pinWriteMask |= mask;
377#endif
378          }
379          pinState[pin] = pinValue;
380        }
381      }
382      mask = mask << 1;
383    }
384    writePort(port, (byte)value, pinWriteMask);
385  }
386}
387
388
389// -----------------------------------------------------------------------------
390/* sets bits in a bit array (int) to toggle the reporting of the analogIns
391 */
392//void FirmataClass::setAnalogPinReporting(byte pin, byte state) {
393//}
394void reportAnalogCallback(byte analogPin, int value)
395{
396  if (analogPin < TOTAL_ANALOG_PINS) {
397    if (value == 0) {
398      analogInputsToReport = analogInputsToReport & ~ (1 << analogPin);
399    } else {
400      analogInputsToReport = analogInputsToReport | (1 << analogPin);
401      // prevent during system reset or all analog pin values will be reported
402      // which may report noise for unconnected analog pins
403      if (!isResetting) {
404        // Send pin value immediately. This is helpful when connected via
405        // ethernet, wi-fi or bluetooth so pin states can be known upon
406        // reconnecting.
407        Firmata.sendAnalog(analogPin, analogRead(analogPin));
408      }
409    }
410  }
411  // TODO: save status to EEPROM here, if changed
412}
413
414void reportDigitalCallback(byte port, int value)
415{
416  if (port < TOTAL_PORTS) {
417    reportPINs[port] = (byte)value;
418    // Send port value immediately. This is helpful when connected via
419    // ethernet, wi-fi or bluetooth so pin states can be known upon
420    // reconnecting.
421    if (value) outputPort(port, readPort(port, portConfigInputs[port]), true);
422  }
423  // do not disable analog reporting on these 8 pins, to allow some
424  // pins used for digital, others analog.  Instead, allow both types
425  // of reporting to be enabled, but check if the pin is configured
426  // as analog when sampling the analog inputs.  Likewise, while
427  // scanning digital pins, portConfigInputs will mask off values from any
428  // pins configured as analog
429}
430
431/*==============================================================================
432 * SYSEX-BASED commands
433 *============================================================================*/
434
435void sysexCallback(byte command, byte argc, byte *argv)
436{
437  byte mode;
438  byte slaveAddress;
439  byte data;
440  int slaveRegister;
441  unsigned int delayTime;
442
443  switch (command) {
444    case I2C_REQUEST:
445      mode = argv[1] & I2C_READ_WRITE_MODE_MASK;
446      if (argv[1] & I2C_10BIT_ADDRESS_MODE_MASK) {
447        Firmata.sendString("10-bit addressing not supported");
448        return;
449      }
450      else {
451        slaveAddress = argv[0];
452      }
453
454      switch (mode) {
455        case I2C_WRITE:
456          Wire.beginTransmission(slaveAddress);
457          for (byte i = 2; i < argc; i += 2) {
458            data = argv[i] + (argv[i + 1] << 7);
459            wireWrite(data);
460          }
461          Wire.endTransmission();
462          delayMicroseconds(70);
463          break;
464        case I2C_READ:
465          if (argc == 6) {
466            // a slave register is specified
467            slaveRegister = argv[2] + (argv[3] << 7);
468            data = argv[4] + (argv[5] << 7);  // bytes to read
469          }
470          else {
471            // a slave register is NOT specified
472            slaveRegister = I2C_REGISTER_NOT_SPECIFIED;
473            data = argv[2] + (argv[3] << 7);  // bytes to read
474          }
475          readAndReportData(slaveAddress, (int)slaveRegister, data);
476          break;
477        case I2C_READ_CONTINUOUSLY:
478          if ((queryIndex + 1) >= I2C_MAX_QUERIES) {
479            // too many queries, just ignore
480            Firmata.sendString("too many queries");
481            break;
482          }
483          if (argc == 6) {
484            // a slave register is specified
485            slaveRegister = argv[2] + (argv[3] << 7);
486            data = argv[4] + (argv[5] << 7);  // bytes to read
487          }
488          else {
489            // a slave register is NOT specified
490            slaveRegister = (int)I2C_REGISTER_NOT_SPECIFIED;
491            data = argv[2] + (argv[3] << 7);  // bytes to read
492          }
493          queryIndex++;
494          query[queryIndex].addr = slaveAddress;
495          query[queryIndex].reg = slaveRegister;
496          query[queryIndex].bytes = data;
497          break;
498        case I2C_STOP_READING:
499          byte queryIndexToSkip;
500          // if read continuous mode is enabled for only 1 i2c device, disable
501          // read continuous reporting for that device
502          if (queryIndex <= 0) {
503            queryIndex = -1;
504          } else {
505            // if read continuous mode is enabled for multiple devices,
506            // determine which device to stop reading and remove it's data from
507            // the array, shifiting other array data to fill the space
508            for (byte i = 0; i < queryIndex + 1; i++) {
509              if (query[i].addr == slaveAddress) {
510                queryIndexToSkip = i;
511                break;
512              }
513            }
514
515            for (byte i = queryIndexToSkip; i < queryIndex + 1; i++) {
516              if (i < I2C_MAX_QUERIES) {
517                query[i].addr = query[i + 1].addr;
518                query[i].reg = query[i + 1].reg;
519                query[i].bytes = query[i + 1].bytes;
520              }
521            }
522            queryIndex--;
523          }
524          break;
525        default:
526          break;
527      }
528      break;
529    case I2C_CONFIG:
530      delayTime = (argv[0] + (argv[1] << 7));
531
532      if (delayTime > 0) {
533        i2cReadDelayTime = delayTime;
534      }
535
536      if (!isI2CEnabled) {
537        enableI2CPins();
538      }
539
540      break;
541    case SERVO_CONFIG:
542      if (argc > 4) {
543        // these vars are here for clarity, they'll optimized away by the compiler
544        byte pin = argv[0];
545        int minPulse = argv[1] + (argv[2] << 7);
546        int maxPulse = argv[3] + (argv[4] << 7);
547
548        if (IS_PIN_DIGITAL(pin)) {
549          if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) {
550            detachServo(pin);
551          }
552          attachServo(pin, minPulse, maxPulse);
553          setPinModeCallback(pin, PIN_MODE_SERVO);
554        }
555      }
556      break;
557    case SAMPLING_INTERVAL:
558      if (argc > 1) {
559        samplingInterval = argv[0] + (argv[1] << 7);
560        if (samplingInterval < MINIMUM_SAMPLING_INTERVAL) {
561          samplingInterval = MINIMUM_SAMPLING_INTERVAL;
562        }
563      } else {
564        //Firmata.sendString("Not enough data");
565      }
566      break;
567    case EXTENDED_ANALOG:
568      if (argc > 1) {
569        int val = argv[1];
570        if (argc > 2) val |= (argv[2] << 7);
571        if (argc > 3) val |= (argv[3] << 14);
572        analogWriteCallback(argv[0], val);
573      }
574      break;
575    case CAPABILITY_QUERY:
576      Firmata.write(START_SYSEX);
577      Firmata.write(CAPABILITY_RESPONSE);
578      for (byte pin = 0; pin < TOTAL_PINS; pin++) {
579        if (IS_PIN_DIGITAL(pin)) {
580          Firmata.write((byte)INPUT);
581          Firmata.write(1);
582          Firmata.write((byte)PIN_MODE_PULLUP);
583          Firmata.write(1);
584          Firmata.write((byte)OUTPUT);
585          Firmata.write(1);
586        }
587        if (IS_PIN_ANALOG(pin)) {
588          Firmata.write(PIN_MODE_ANALOG);
589          Firmata.write(10); // 10 = 10-bit resolution
590        }
591        if (IS_PIN_PWM(pin)) {
592          Firmata.write(PIN_MODE_PWM);
593          Firmata.write(8); // 8 = 8-bit resolution
594        }
595        if (IS_PIN_DIGITAL(pin)) {
596          Firmata.write(PIN_MODE_SERVO);
597          Firmata.write(14);
598        }
599        if (IS_PIN_I2C(pin)) {
600          Firmata.write(PIN_MODE_I2C);
601          Firmata.write(1);  // TODO: could assign a number to map to SCL or SDA
602        }
603        Firmata.write(127);
604      }
605      Firmata.write(END_SYSEX);
606      break;
607    case PIN_STATE_QUERY:
608      if (argc > 0) {
609        byte pin = argv[0];
610        Firmata.write(START_SYSEX);
611        Firmata.write(PIN_STATE_RESPONSE);
612        Firmata.write(pin);
613        if (pin < TOTAL_PINS) {
614          Firmata.write((byte)pinConfig[pin]);
615          Firmata.write((byte)pinState[pin] & 0x7F);
616          if (pinState[pin] & 0xFF80) Firmata.write((byte)(pinState[pin] >> 7) & 0x7F);
617          if (pinState[pin] & 0xC000) Firmata.write((byte)(pinState[pin] >> 14) & 0x7F);
618        }
619        Firmata.write(END_SYSEX);
620      }
621      break;
622    case ANALOG_MAPPING_QUERY:
623      Firmata.write(START_SYSEX);
624      Firmata.write(ANALOG_MAPPING_RESPONSE);
625      for (byte pin = 0; pin < TOTAL_PINS; pin++) {
626        Firmata.write(IS_PIN_ANALOG(pin) ? PIN_TO_ANALOG(pin) : 127);
627      }
628      Firmata.write(END_SYSEX);
629      break;
630  }
631}
632
633void enableI2CPins()
634{
635  byte i;
636  // is there a faster way to do this? would probaby require importing
637  // Arduino.h to get SCL and SDA pins
638  for (i = 0; i < TOTAL_PINS; i++) {
639    if (IS_PIN_I2C(i)) {
640      // mark pins as i2c so they are ignore in non i2c data requests
641      setPinModeCallback(i, PIN_MODE_I2C);
642    }
643  }
644
645  isI2CEnabled = true;
646
647  Wire.begin();
648}
649
650/* disable the i2c pins so they can be used for other functions */
651void disableI2CPins() {
652  isI2CEnabled = false;
653  // disable read continuous mode for all devices
654  queryIndex = -1;
655}
656
657/*==============================================================================
658 * SETUP()
659 *============================================================================*/
660
661void systemResetCallback()
662{
663  isResetting = true;
664
665  // initialize a defalt state
666  // TODO: option to load config from EEPROM instead of default
667
668  if (isI2CEnabled) {
669    disableI2CPins();
670  }
671
672  for (byte i = 0; i < TOTAL_PORTS; i++) {
673    reportPINs[i] = false;    // by default, reporting off
674    portConfigInputs[i] = 0;  // until activated
675    previousPINs[i] = 0;
676  }
677
678  for (byte i = 0; i < TOTAL_PINS; i++) {
679    // pins with analog capability default to analog input
680    // otherwise, pins default to digital output
681    if (IS_PIN_ANALOG(i)) {
682      // turns off pullup, configures everything
683      setPinModeCallback(i, PIN_MODE_ANALOG);
684    } else if (IS_PIN_DIGITAL(i)) {
685      // sets the output to 0, configures portConfigInputs
686      setPinModeCallback(i, OUTPUT);
687    }
688
689    servoPinMap[i] = 255;
690  }
691  // by default, do not report any analog inputs
692  analogInputsToReport = 0;
693
694  detachedServoCount = 0;
695  servoCount = 0;
696
697  /* send digital inputs to set the initial state on the host computer,
698   * since once in the loop(), this firmware will only send on change */
699  /*
700  TODO: this can never execute, since no pins default to digital input
701        but it will be needed when/if we support EEPROM stored config
702  for (byte i=0; i < TOTAL_PORTS; i++) {
703    outputPort(i, readPort(i, portConfigInputs[i]), true);
704  }
705  */
706  isResetting = false;
707}
708
709void setup()
710{
711  Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION);
712
713  Firmata.attach(ANALOG_MESSAGE, analogWriteCallback);
714  Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback);
715  Firmata.attach(REPORT_ANALOG, reportAnalogCallback);
716  Firmata.attach(REPORT_DIGITAL, reportDigitalCallback);
717  Firmata.attach(SET_PIN_MODE, setPinModeCallback);
718  Firmata.attach(SET_DIGITAL_PIN_VALUE, setPinValueCallback);
719  Firmata.attach(START_SYSEX, sysexCallback);
720  Firmata.attach(SYSTEM_RESET, systemResetCallback);
721
722  // to use a port other than Serial, such as Serial1 on an Arduino Leonardo or Mega,
723  // Call begin(baud) on the alternate serial port and pass it to Firmata to begin like this:
724  // Serial1.begin(57600);
725  // Firmata.begin(Serial1);
726  // then comment out or remove lines 701 - 704 below
727
728  Firmata.begin(57600);
729  while (!Serial) {
730    ; // wait for serial port to connect. Only needed for ATmega32u4-based boards (Leonardo, etc).
731  }
732  systemResetCallback();  // reset to default config
733}
734
735/*==============================================================================
736 * LOOP()
737 *============================================================================*/
738void loop()
739{
740  byte pin, analogPin;
741
742  /* DIGITALREAD - as fast as possible, check for changes and output them to the
743   * FTDI buffer using Serial.print()  */
744  checkDigitalInputs();
745
746  /* STREAMREAD - processing incoming messagse as soon as possible, while still
747   * checking digital inputs.  */
748  while (Firmata.available())
749    Firmata.processInput();
750
751  // TODO - ensure that Stream buffer doesn't go over 60 bytes
752
753  currentMillis = millis();
754  if (currentMillis - previousMillis > samplingInterval) {
755    previousMillis += samplingInterval;
756    /* ANALOGREAD - do all analogReads() at the configured sampling interval */
757    for (pin = 0; pin < TOTAL_PINS; pin++) {
758      if (IS_PIN_ANALOG(pin) && pinConfig[pin] == PIN_MODE_ANALOG) {
759        analogPin = PIN_TO_ANALOG(pin);
760        if (analogInputsToReport & (1 << analogPin)) {
761          Firmata.sendAnalog(analogPin, analogRead(analogPin));
762        }
763      }
764    }
765    // report i2c data for all device with read continuous mode enabled
766    if (queryIndex > -1) {
767      for (byte i = 0; i < queryIndex + 1; i++) {
768        readAndReportData(query[i].addr, query[i].reg, query[i].bytes);
769      }
770    }
771  }
772}
Note: See TracBrowser for help on using the repository browser.