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.
6 * To download a host software package, please click on the following link
7 * to open the list of Firmata client libraries in your default browser.
9 * https://github.com/firmata/arduino#firmata-client-libraries
13 Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights reserved.
15 This library is free software; you can redistribute it and/or
16 modify it under the terms of the GNU Lesser General Public
17 License as published by the Free Software Foundation; either
18 version 2.1 of the License, or (at your option) any later version.
20 See file LICENSE.txt for further informations on licensing terms.
24 * This is an old version of StandardFirmata (v2.0). It is kept here because
25 * its the last version that works on an ATMEGA8 chip. Also, it can be used
26 * for host software that has not been updated to a newer version of the
27 * protocol. It also uses the old baud rate of 115200 rather than 57600.
33 /*==============================================================================
35 *============================================================================*/
38 int analogInputsToReport = 0; // bitwise array to store pin reporting
39 int analogPin = 0; // counter for reading analog pins
42 byte reportPINs[TOTAL_PORTS]; // PIN == input port
43 byte previousPINs[TOTAL_PORTS]; // PIN == input port
44 byte pinStatus[TOTAL_PINS]; // store pin status, default OUTPUT
45 byte portStatus[TOTAL_PORTS];
48 unsigned long currentMillis; // store the current value from millis()
49 unsigned long previousMillis; // for comparison with currentMillis
52 /*==============================================================================
54 *============================================================================*/
56 void outputPort(byte portNumber, byte portValue)
58 portValue = portValue & ~ portStatus[portNumber];
59 if (previousPINs[portNumber] != portValue) {
60 Firmata.sendDigitalPort(portNumber, portValue);
61 previousPINs[portNumber] = portValue;
62 Firmata.sendDigitalPort(portNumber, portValue);
66 /* -----------------------------------------------------------------------------
67 * check all the active digital inputs for change of state, then add any events
68 * to the Serial output queue using Serial.print() */
69 void checkDigitalInputs(void)
72 for (i = 0; i < TOTAL_PORTS; i++) {
75 case 0: outputPort(0, PIND & ~ B00000011); break; // ignore Rx/Tx 0/1
76 case 1: outputPort(1, PINB); break;
77 case 2: outputPort(2, PINC); break;
83 // -----------------------------------------------------------------------------
84 /* sets the pin mode to the correct state and sets the relevant bits in the
85 * two bit-arrays that track Digital I/O and PWM status
87 void setPinModeCallback(byte pin, int mode) {
94 } else if (pin < 14) {
97 } else if (pin < 22) {
102 if (pin > 1) { // ignore RxTx (pins 0 and 1)
103 pinStatus[pin] = mode;
107 portStatus[port] = portStatus[port] & ~ (1 << (pin - offset));
110 digitalWrite(pin, LOW); // disable PWM
112 pinMode(pin, OUTPUT);
113 portStatus[port] = portStatus[port] | (1 << (pin - offset));
115 //case ANALOG: // TODO figure this out
117 Firmata.sendString("");
119 // TODO: save status to EEPROM here, if changed
123 void analogWriteCallback(byte pin, int value)
125 setPinModeCallback(pin, PIN_MODE_PWM);
126 analogWrite(pin, value);
129 void digitalWriteCallback(byte port, int value)
132 case 0: // pins 2-7 (don't change Rx/Tx, pins 0 and 1)
133 // 0xFF03 == B1111111100000011 0x03 == B00000011
134 PORTD = (value & ~ 0xFF03) | (PORTD & 0x03);
136 case 1: // pins 8-13 (14,15 are disabled for the crystal)
139 case 2: // analog pins used as digital
145 // -----------------------------------------------------------------------------
146 /* sets bits in a bit array (int) to toggle the reporting of the analogIns
148 //void FirmataClass::setAnalogPinReporting(byte pin, byte state) {
150 void reportAnalogCallback(byte pin, int value)
153 analogInputsToReport = analogInputsToReport & ~ (1 << pin);
155 else { // everything but 0 enables reporting of that pin
156 analogInputsToReport = analogInputsToReport | (1 << pin);
158 // TODO: save status to EEPROM here, if changed
161 void reportDigitalCallback(byte port, int value)
163 reportPINs[port] = (byte)value;
164 if (port == 2) // turn off analog reporting when used as digital
165 analogInputsToReport = 0;
168 /*==============================================================================
170 *============================================================================*/
175 Firmata.setFirmwareVersion(2, 0);
177 Firmata.attach(ANALOG_MESSAGE, analogWriteCallback);
178 Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback);
179 Firmata.attach(REPORT_ANALOG, reportAnalogCallback);
180 Firmata.attach(REPORT_DIGITAL, reportDigitalCallback);
181 Firmata.attach(SET_PIN_MODE, setPinModeCallback);
183 portStatus[0] = B00000011; // ignore Tx/RX pins
184 portStatus[1] = B11000000; // ignore 14/15 pins
185 portStatus[2] = B00000000;
187 // for(i=0; i<TOTAL_PINS; ++i) { // TODO make this work with analogs
188 for (i = 0; i < 14; ++i) {
189 setPinModeCallback(i, OUTPUT);
191 // set all outputs to 0 to make sure internal pull-up resistors are off
192 PORTB = 0; // pins 8-15
193 PORTC = 0; // analog port
194 PORTD = 0; // pins 0-7
196 // TODO rethink the init, perhaps it should report analog on default
197 for (i = 0; i < TOTAL_PORTS; ++i) {
198 reportPINs[i] = false;
200 // TODO: load state from EEPROM here
202 /* send digital inputs here, if enabled, to set the initial state on the
203 * host computer, since once in the loop(), this firmware will only send
204 * digital data on change. */
205 if (reportPINs[0]) outputPort(0, PIND & ~ B00000011); // ignore Rx/Tx 0/1
206 if (reportPINs[1]) outputPort(1, PINB);
207 if (reportPINs[2]) outputPort(2, PINC);
209 Firmata.begin(115200);
212 /*==============================================================================
214 *============================================================================*/
217 /* DIGITALREAD - as fast as possible, check for changes and output them to the
218 * FTDI buffer using Serial.print() */
219 checkDigitalInputs();
220 currentMillis = millis();
221 if (currentMillis - previousMillis > 20) {
222 previousMillis += 20; // run this every 20ms
223 /* SERIALREAD - Serial.read() uses a 128 byte circular buffer, so handle
224 * all serialReads at once, i.e. empty the buffer */
225 while (Firmata.available())
226 Firmata.processInput();
227 /* SEND FTDI WRITE BUFFER - make sure that the FTDI buffer doesn't go over
228 * 60 bytes. use a timer to sending an event character every 4 ms to
229 * trigger the buffer to dump. */
231 /* ANALOGREAD - right after the event character, do all of the
232 * analogReads(). These only need to be done every 4ms. */
233 for (analogPin = 0; analogPin < TOTAL_ANALOG_PINS; analogPin++) {
234 if ( analogInputsToReport & (1 << analogPin) ) {
235 Firmata.sendAnalog(analogPin, analogRead(analogPin));