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

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

First release to Xenial

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