source: rtos_arduino/trunk/arduino_lib/libraries/Firmata/examples/StandardFirmata/StandardFirmata.ino@ 224

Last change on this file since 224 was 224, checked in by ertl-honda, 8 years ago

1.7.10のファイルに更新

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