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 download page in your default browser.
|
---|
8 | *
|
---|
9 | * http://firmata.org/wiki/Download
|
---|
10 | */
|
---|
11 |
|
---|
12 | /*
|
---|
13 | Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights reserved.
|
---|
14 |
|
---|
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.
|
---|
19 |
|
---|
20 | See file LICENSE.txt for further informations on licensing terms.
|
---|
21 | */
|
---|
22 |
|
---|
23 | /*
|
---|
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.
|
---|
28 | */
|
---|
29 |
|
---|
30 | #include <EEPROM.h>
|
---|
31 | #include <Firmata.h>
|
---|
32 |
|
---|
33 | /*==============================================================================
|
---|
34 | * GLOBAL VARIABLES
|
---|
35 | *============================================================================*/
|
---|
36 |
|
---|
37 | /* analog inputs */
|
---|
38 | int analogInputsToReport = 0; // bitwise array to store pin reporting
|
---|
39 | int analogPin = 0; // counter for reading analog pins
|
---|
40 |
|
---|
41 | /* digital 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];
|
---|
46 |
|
---|
47 | /* timer variables */
|
---|
48 | unsigned long currentMillis; // store the current value from millis()
|
---|
49 | unsigned long previousMillis; // for comparison with currentMillis
|
---|
50 |
|
---|
51 |
|
---|
52 | /*==============================================================================
|
---|
53 | * FUNCTIONS
|
---|
54 | *============================================================================*/
|
---|
55 |
|
---|
56 | void outputPort(byte portNumber, byte portValue)
|
---|
57 | {
|
---|
58 | portValue = portValue & ~ portStatus[portNumber];
|
---|
59 | if (previousPINs[portNumber] != portValue) {
|
---|
60 | Firmata.sendDigitalPort(portNumber, portValue);
|
---|
61 | previousPINs[portNumber] = portValue;
|
---|
62 | Firmata.sendDigitalPort(portNumber, portValue);
|
---|
63 | }
|
---|
64 | }
|
---|
65 |
|
---|
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)
|
---|
70 | {
|
---|
71 | byte i, tmp;
|
---|
72 | for (i = 0; i < TOTAL_PORTS; i++) {
|
---|
73 | if (reportPINs[i]) {
|
---|
74 | switch (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;
|
---|
78 | }
|
---|
79 | }
|
---|
80 | }
|
---|
81 | }
|
---|
82 |
|
---|
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
|
---|
86 | */
|
---|
87 | void setPinModeCallback(byte pin, int mode) {
|
---|
88 | byte port = 0;
|
---|
89 | byte offset = 0;
|
---|
90 |
|
---|
91 | if (pin < 8) {
|
---|
92 | port = 0;
|
---|
93 | offset = 0;
|
---|
94 | } else if (pin < 14) {
|
---|
95 | port = 1;
|
---|
96 | offset = 8;
|
---|
97 | } else if (pin < 22) {
|
---|
98 | port = 2;
|
---|
99 | offset = 14;
|
---|
100 | }
|
---|
101 |
|
---|
102 | if (pin > 1) { // ignore RxTx (pins 0 and 1)
|
---|
103 | pinStatus[pin] = mode;
|
---|
104 | switch (mode) {
|
---|
105 | case INPUT:
|
---|
106 | pinMode(pin, INPUT);
|
---|
107 | portStatus[port] = portStatus[port] & ~ (1 << (pin - offset));
|
---|
108 | break;
|
---|
109 | case OUTPUT:
|
---|
110 | digitalWrite(pin, LOW); // disable PWM
|
---|
111 | case PWM:
|
---|
112 | pinMode(pin, OUTPUT);
|
---|
113 | portStatus[port] = portStatus[port] | (1 << (pin - offset));
|
---|
114 | break;
|
---|
115 | //case ANALOG: // TODO figure this out
|
---|
116 | default:
|
---|
117 | Firmata.sendString("");
|
---|
118 | }
|
---|
119 | // TODO: save status to EEPROM here, if changed
|
---|
120 | }
|
---|
121 | }
|
---|
122 |
|
---|
123 | void analogWriteCallback(byte pin, int value)
|
---|
124 | {
|
---|
125 | setPinModeCallback(pin, PIN_MODE_PWM);
|
---|
126 | analogWrite(pin, value);
|
---|
127 | }
|
---|
128 |
|
---|
129 | void digitalWriteCallback(byte port, int value)
|
---|
130 | {
|
---|
131 | switch (port) {
|
---|
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);
|
---|
135 | break;
|
---|
136 | case 1: // pins 8-13 (14,15 are disabled for the crystal)
|
---|
137 | PORTB = (byte)value;
|
---|
138 | break;
|
---|
139 | case 2: // analog pins used as digital
|
---|
140 | PORTC = (byte)value;
|
---|
141 | break;
|
---|
142 | }
|
---|
143 | }
|
---|
144 |
|
---|
145 | // -----------------------------------------------------------------------------
|
---|
146 | /* sets bits in a bit array (int) to toggle the reporting of the analogIns
|
---|
147 | */
|
---|
148 | //void FirmataClass::setAnalogPinReporting(byte pin, byte state) {
|
---|
149 | //}
|
---|
150 | void reportAnalogCallback(byte pin, int value)
|
---|
151 | {
|
---|
152 | if (value == 0) {
|
---|
153 | analogInputsToReport = analogInputsToReport & ~ (1 << pin);
|
---|
154 | }
|
---|
155 | else { // everything but 0 enables reporting of that pin
|
---|
156 | analogInputsToReport = analogInputsToReport | (1 << pin);
|
---|
157 | }
|
---|
158 | // TODO: save status to EEPROM here, if changed
|
---|
159 | }
|
---|
160 |
|
---|
161 | void reportDigitalCallback(byte port, int value)
|
---|
162 | {
|
---|
163 | reportPINs[port] = (byte)value;
|
---|
164 | if (port == 2) // turn off analog reporting when used as digital
|
---|
165 | analogInputsToReport = 0;
|
---|
166 | }
|
---|
167 |
|
---|
168 | /*==============================================================================
|
---|
169 | * SETUP()
|
---|
170 | *============================================================================*/
|
---|
171 | void setup()
|
---|
172 | {
|
---|
173 | byte i;
|
---|
174 |
|
---|
175 | Firmata.setFirmwareVersion(2, 0);
|
---|
176 |
|
---|
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);
|
---|
182 |
|
---|
183 | portStatus[0] = B00000011; // ignore Tx/RX pins
|
---|
184 | portStatus[1] = B11000000; // ignore 14/15 pins
|
---|
185 | portStatus[2] = B00000000;
|
---|
186 |
|
---|
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);
|
---|
190 | }
|
---|
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
|
---|
195 |
|
---|
196 | // TODO rethink the init, perhaps it should report analog on default
|
---|
197 | for (i = 0; i < TOTAL_PORTS; ++i) {
|
---|
198 | reportPINs[i] = false;
|
---|
199 | }
|
---|
200 | // TODO: load state from EEPROM here
|
---|
201 |
|
---|
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);
|
---|
208 |
|
---|
209 | Firmata.begin(115200);
|
---|
210 | }
|
---|
211 |
|
---|
212 | /*==============================================================================
|
---|
213 | * LOOP()
|
---|
214 | *============================================================================*/
|
---|
215 | void loop()
|
---|
216 | {
|
---|
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. */
|
---|
230 |
|
---|
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));
|
---|
236 | }
|
---|
237 | }
|
---|
238 | }
|
---|
239 | }
|
---|