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

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

1.7.10のファイルに更新

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