root / arduino-1.0 / libraries / Firmata / Firmata.cpp @ 58d82c77
History | View | Annotate | Download (12.7 KB)
1 | 58d82c77 | Tom Mullins | /*
|
---|---|---|---|
2 | Firmata.cpp - Firmata library
|
||
3 | Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights reserved.
|
||
4 |
|
||
5 | This library is free software; you can redistribute it and/or
|
||
6 | modify it under the terms of the GNU Lesser General Public
|
||
7 | License as published by the Free Software Foundation; either
|
||
8 | version 2.1 of the License, or (at your option) any later version.
|
||
9 | |||
10 | See file LICENSE.txt for further informations on licensing terms.
|
||
11 | */
|
||
12 | |||
13 | //******************************************************************************
|
||
14 | //* Includes
|
||
15 | //******************************************************************************
|
||
16 | |||
17 | #include "Firmata.h" |
||
18 | #include "HardwareSerial.h" |
||
19 | |||
20 | extern "C" { |
||
21 | #include <string.h> |
||
22 | #include <stdlib.h> |
||
23 | } |
||
24 | |||
25 | //******************************************************************************
|
||
26 | //* Support Functions
|
||
27 | //******************************************************************************
|
||
28 | |||
29 | void FirmataClass::sendValueAsTwo7bitBytes(int value) |
||
30 | { |
||
31 | FirmataSerial.write(value & B01111111); // LSB
|
||
32 | FirmataSerial.write(value >> 7 & B01111111); // MSB |
||
33 | } |
||
34 | |||
35 | void FirmataClass::startSysex(void) |
||
36 | { |
||
37 | FirmataSerial.write(START_SYSEX); |
||
38 | } |
||
39 | |||
40 | void FirmataClass::endSysex(void) |
||
41 | { |
||
42 | FirmataSerial.write(END_SYSEX); |
||
43 | } |
||
44 | |||
45 | //******************************************************************************
|
||
46 | //* Constructors
|
||
47 | //******************************************************************************
|
||
48 | |||
49 | FirmataClass::FirmataClass(Stream &s) : FirmataSerial(s) |
||
50 | { |
||
51 | firmwareVersionCount = 0;
|
||
52 | systemReset(); |
||
53 | } |
||
54 | |||
55 | //******************************************************************************
|
||
56 | //* Public Methods
|
||
57 | //******************************************************************************
|
||
58 | |||
59 | /* begin method for overriding default serial bitrate */
|
||
60 | void FirmataClass::begin(void) |
||
61 | { |
||
62 | begin(57600);
|
||
63 | } |
||
64 | |||
65 | /* begin method for overriding default serial bitrate */
|
||
66 | void FirmataClass::begin(long speed) |
||
67 | { |
||
68 | Serial.begin(speed); |
||
69 | FirmataSerial = Serial; |
||
70 | blinkVersion(); |
||
71 | printVersion(); |
||
72 | printFirmwareVersion(); |
||
73 | } |
||
74 | |||
75 | void FirmataClass::begin(Stream &s)
|
||
76 | { |
||
77 | FirmataSerial = s; |
||
78 | systemReset(); |
||
79 | printVersion(); |
||
80 | printFirmwareVersion(); |
||
81 | } |
||
82 | |||
83 | // output the protocol version message to the serial port
|
||
84 | void FirmataClass::printVersion(void) { |
||
85 | FirmataSerial.write(REPORT_VERSION); |
||
86 | FirmataSerial.write(FIRMATA_MAJOR_VERSION); |
||
87 | FirmataSerial.write(FIRMATA_MINOR_VERSION); |
||
88 | } |
||
89 | |||
90 | void FirmataClass::blinkVersion(void) |
||
91 | { |
||
92 | // flash the pin with the protocol version
|
||
93 | pinMode(VERSION_BLINK_PIN,OUTPUT); |
||
94 | pin13strobe(FIRMATA_MAJOR_VERSION, 40, 210); |
||
95 | delay(250);
|
||
96 | pin13strobe(FIRMATA_MINOR_VERSION, 40, 210); |
||
97 | delay(125);
|
||
98 | } |
||
99 | |||
100 | void FirmataClass::printFirmwareVersion(void) |
||
101 | { |
||
102 | byte i; |
||
103 | |||
104 | if(firmwareVersionCount) { // make sure that the name has been set before reporting |
||
105 | startSysex(); |
||
106 | FirmataSerial.write(REPORT_FIRMWARE); |
||
107 | FirmataSerial.write(firmwareVersionVector[0]); // major version number |
||
108 | FirmataSerial.write(firmwareVersionVector[1]); // minor version number |
||
109 | for(i=2; i<firmwareVersionCount; ++i) { |
||
110 | sendValueAsTwo7bitBytes(firmwareVersionVector[i]); |
||
111 | } |
||
112 | endSysex(); |
||
113 | } |
||
114 | } |
||
115 | |||
116 | void FirmataClass::setFirmwareNameAndVersion(const char *name, byte major, byte minor) |
||
117 | { |
||
118 | const char *filename; |
||
119 | char *extension;
|
||
120 | |||
121 | // parse out ".cpp" and "applet/" that comes from using __FILE__
|
||
122 | extension = strstr(name, ".cpp");
|
||
123 | filename = strrchr(name, '/') + 1; //points to slash, +1 gets to start of filename |
||
124 | // add two bytes for version numbers
|
||
125 | if(extension && filename) {
|
||
126 | firmwareVersionCount = extension - filename + 2;
|
||
127 | } else {
|
||
128 | firmwareVersionCount = strlen(name) + 2;
|
||
129 | filename = name; |
||
130 | } |
||
131 | firmwareVersionVector = (byte *) malloc(firmwareVersionCount); |
||
132 | firmwareVersionVector[firmwareVersionCount] = 0;
|
||
133 | firmwareVersionVector[0] = major;
|
||
134 | firmwareVersionVector[1] = minor;
|
||
135 | strncpy((char*)firmwareVersionVector + 2, filename, firmwareVersionCount - 2); |
||
136 | // alas, no snprintf on Arduino
|
||
137 | // snprintf(firmwareVersionVector, MAX_DATA_BYTES, "%c%c%s",
|
||
138 | // (char)major, (char)minor, firmwareVersionVector);
|
||
139 | } |
||
140 | |||
141 | //------------------------------------------------------------------------------
|
||
142 | // Serial Receive Handling
|
||
143 | |||
144 | int FirmataClass::available(void) |
||
145 | { |
||
146 | return FirmataSerial.available();
|
||
147 | } |
||
148 | |||
149 | |||
150 | void FirmataClass::processSysexMessage(void) |
||
151 | { |
||
152 | switch(storedInputData[0]) { //first byte in buffer is command |
||
153 | case REPORT_FIRMWARE:
|
||
154 | printFirmwareVersion(); |
||
155 | break;
|
||
156 | case STRING_DATA:
|
||
157 | if(currentStringCallback) {
|
||
158 | byte bufferLength = (sysexBytesRead - 1) / 2; |
||
159 | char *buffer = (char*)malloc(bufferLength * sizeof(char)); |
||
160 | byte i = 1;
|
||
161 | byte j = 0;
|
||
162 | while(j < bufferLength) {
|
||
163 | buffer[j] = (char)storedInputData[i];
|
||
164 | i++; |
||
165 | buffer[j] += (char)(storedInputData[i] << 7); |
||
166 | i++; |
||
167 | j++; |
||
168 | } |
||
169 | (*currentStringCallback)(buffer); |
||
170 | } |
||
171 | break;
|
||
172 | default:
|
||
173 | if(currentSysexCallback)
|
||
174 | (*currentSysexCallback)(storedInputData[0], sysexBytesRead - 1, storedInputData + 1); |
||
175 | } |
||
176 | } |
||
177 | |||
178 | void FirmataClass::processInput(void) |
||
179 | { |
||
180 | int inputData = FirmataSerial.read(); // this is 'int' to handle -1 when no data |
||
181 | int command;
|
||
182 | |||
183 | // TODO make sure it handles -1 properly
|
||
184 | |||
185 | if (parsingSysex) {
|
||
186 | if(inputData == END_SYSEX) {
|
||
187 | //stop sysex byte
|
||
188 | parsingSysex = false;
|
||
189 | //fire off handler function
|
||
190 | processSysexMessage(); |
||
191 | } else {
|
||
192 | //normal data byte - add to buffer
|
||
193 | storedInputData[sysexBytesRead] = inputData; |
||
194 | sysexBytesRead++; |
||
195 | } |
||
196 | } else if( (waitForData > 0) && (inputData < 128) ) { |
||
197 | waitForData--; |
||
198 | storedInputData[waitForData] = inputData; |
||
199 | if( (waitForData==0) && executeMultiByteCommand ) { // got the whole message |
||
200 | switch(executeMultiByteCommand) {
|
||
201 | case ANALOG_MESSAGE:
|
||
202 | if(currentAnalogCallback) {
|
||
203 | (*currentAnalogCallback)(multiByteChannel, |
||
204 | (storedInputData[0] << 7) |
||
205 | + storedInputData[1]);
|
||
206 | } |
||
207 | break;
|
||
208 | case DIGITAL_MESSAGE:
|
||
209 | if(currentDigitalCallback) {
|
||
210 | (*currentDigitalCallback)(multiByteChannel, |
||
211 | (storedInputData[0] << 7) |
||
212 | + storedInputData[1]);
|
||
213 | } |
||
214 | break;
|
||
215 | case SET_PIN_MODE:
|
||
216 | if(currentPinModeCallback)
|
||
217 | (*currentPinModeCallback)(storedInputData[1], storedInputData[0]); |
||
218 | break;
|
||
219 | case REPORT_ANALOG:
|
||
220 | if(currentReportAnalogCallback)
|
||
221 | (*currentReportAnalogCallback)(multiByteChannel,storedInputData[0]);
|
||
222 | break;
|
||
223 | case REPORT_DIGITAL:
|
||
224 | if(currentReportDigitalCallback)
|
||
225 | (*currentReportDigitalCallback)(multiByteChannel,storedInputData[0]);
|
||
226 | break;
|
||
227 | } |
||
228 | executeMultiByteCommand = 0;
|
||
229 | } |
||
230 | } else {
|
||
231 | // remove channel info from command byte if less than 0xF0
|
||
232 | if(inputData < 0xF0) { |
||
233 | command = inputData & 0xF0;
|
||
234 | multiByteChannel = inputData & 0x0F;
|
||
235 | } else {
|
||
236 | command = inputData; |
||
237 | // commands in the 0xF* range don't use channel data
|
||
238 | } |
||
239 | switch (command) {
|
||
240 | case ANALOG_MESSAGE:
|
||
241 | case DIGITAL_MESSAGE:
|
||
242 | case SET_PIN_MODE:
|
||
243 | waitForData = 2; // two data bytes needed |
||
244 | executeMultiByteCommand = command; |
||
245 | break;
|
||
246 | case REPORT_ANALOG:
|
||
247 | case REPORT_DIGITAL:
|
||
248 | waitForData = 1; // two data bytes needed |
||
249 | executeMultiByteCommand = command; |
||
250 | break;
|
||
251 | case START_SYSEX:
|
||
252 | parsingSysex = true;
|
||
253 | sysexBytesRead = 0;
|
||
254 | break;
|
||
255 | case SYSTEM_RESET:
|
||
256 | systemReset(); |
||
257 | break;
|
||
258 | case REPORT_VERSION:
|
||
259 | Firmata.printVersion(); |
||
260 | break;
|
||
261 | } |
||
262 | } |
||
263 | } |
||
264 | |||
265 | //------------------------------------------------------------------------------
|
||
266 | // Serial Send Handling
|
||
267 | |||
268 | // send an analog message
|
||
269 | void FirmataClass::sendAnalog(byte pin, int value) |
||
270 | { |
||
271 | // pin can only be 0-15, so chop higher bits
|
||
272 | FirmataSerial.write(ANALOG_MESSAGE | (pin & 0xF));
|
||
273 | sendValueAsTwo7bitBytes(value); |
||
274 | } |
||
275 | |||
276 | // send a single digital pin in a digital message
|
||
277 | void FirmataClass::sendDigital(byte pin, int value) |
||
278 | { |
||
279 | /* TODO add single pin digital messages to the protocol, this needs to
|
||
280 | * track the last digital data sent so that it can be sure to change just
|
||
281 | * one bit in the packet. This is complicated by the fact that the
|
||
282 | * numbering of the pins will probably differ on Arduino, Wiring, and
|
||
283 | * other boards. The DIGITAL_MESSAGE sends 14 bits at a time, but it is
|
||
284 | * probably easier to send 8 bit ports for any board with more than 14
|
||
285 | * digital pins.
|
||
286 | */
|
||
287 | |||
288 | // TODO: the digital message should not be sent on the serial port every
|
||
289 | // time sendDigital() is called. Instead, it should add it to an int
|
||
290 | // which will be sent on a schedule. If a pin changes more than once
|
||
291 | // before the digital message is sent on the serial port, it should send a
|
||
292 | // digital message for each change.
|
||
293 | |||
294 | // if(value == 0)
|
||
295 | // sendDigitalPortPair();
|
||
296 | } |
||
297 | |||
298 | |||
299 | // send 14-bits in a single digital message (protocol v1)
|
||
300 | // send an 8-bit port in a single digital message (protocol v2)
|
||
301 | void FirmataClass::sendDigitalPort(byte portNumber, int portData) |
||
302 | { |
||
303 | FirmataSerial.write(DIGITAL_MESSAGE | (portNumber & 0xF));
|
||
304 | FirmataSerial.write((byte)portData % 128); // Tx bits 0-6 |
||
305 | FirmataSerial.write(portData >> 7); // Tx bits 7-13 |
||
306 | } |
||
307 | |||
308 | |||
309 | void FirmataClass::sendSysex(byte command, byte bytec, byte* bytev)
|
||
310 | { |
||
311 | byte i; |
||
312 | startSysex(); |
||
313 | FirmataSerial.write(command); |
||
314 | for(i=0; i<bytec; i++) { |
||
315 | sendValueAsTwo7bitBytes(bytev[i]); |
||
316 | } |
||
317 | endSysex(); |
||
318 | } |
||
319 | |||
320 | void FirmataClass::sendString(byte command, const char* string) |
||
321 | { |
||
322 | sendSysex(command, strlen(string), (byte *)string); |
||
323 | } |
||
324 | |||
325 | |||
326 | // send a string as the protocol string type
|
||
327 | void FirmataClass::sendString(const char* string) |
||
328 | { |
||
329 | sendString(STRING_DATA, string);
|
||
330 | } |
||
331 | |||
332 | |||
333 | // Internal Actions/////////////////////////////////////////////////////////////
|
||
334 | |||
335 | // generic callbacks
|
||
336 | void FirmataClass::attach(byte command, callbackFunction newFunction)
|
||
337 | { |
||
338 | switch(command) {
|
||
339 | case ANALOG_MESSAGE: currentAnalogCallback = newFunction; break; |
||
340 | case DIGITAL_MESSAGE: currentDigitalCallback = newFunction; break; |
||
341 | case REPORT_ANALOG: currentReportAnalogCallback = newFunction; break; |
||
342 | case REPORT_DIGITAL: currentReportDigitalCallback = newFunction; break; |
||
343 | case SET_PIN_MODE: currentPinModeCallback = newFunction; break; |
||
344 | } |
||
345 | } |
||
346 | |||
347 | void FirmataClass::attach(byte command, systemResetCallbackFunction newFunction)
|
||
348 | { |
||
349 | switch(command) {
|
||
350 | case SYSTEM_RESET: currentSystemResetCallback = newFunction; break; |
||
351 | } |
||
352 | } |
||
353 | |||
354 | void FirmataClass::attach(byte command, stringCallbackFunction newFunction)
|
||
355 | { |
||
356 | switch(command) {
|
||
357 | case STRING_DATA: currentStringCallback = newFunction; break; |
||
358 | } |
||
359 | } |
||
360 | |||
361 | void FirmataClass::attach(byte command, sysexCallbackFunction newFunction)
|
||
362 | { |
||
363 | currentSysexCallback = newFunction; |
||
364 | } |
||
365 | |||
366 | void FirmataClass::detach(byte command)
|
||
367 | { |
||
368 | switch(command) {
|
||
369 | case SYSTEM_RESET: currentSystemResetCallback = NULL; break; |
||
370 | case STRING_DATA: currentStringCallback = NULL; break; |
||
371 | case START_SYSEX: currentSysexCallback = NULL; break; |
||
372 | default:
|
||
373 | attach(command, (callbackFunction)NULL);
|
||
374 | } |
||
375 | } |
||
376 | |||
377 | // sysex callbacks
|
||
378 | /*
|
||
379 | * this is too complicated for analogReceive, but maybe for Sysex?
|
||
380 | void FirmataClass::attachSysex(sysexFunction newFunction)
|
||
381 | {
|
||
382 | byte i;
|
||
383 | byte tmpCount = analogReceiveFunctionCount;
|
||
384 | analogReceiveFunction* tmpArray = analogReceiveFunctionArray;
|
||
385 | analogReceiveFunctionCount++;
|
||
386 | analogReceiveFunctionArray = (analogReceiveFunction*) calloc(analogReceiveFunctionCount, sizeof(analogReceiveFunction));
|
||
387 | for(i = 0; i < tmpCount; i++) {
|
||
388 | analogReceiveFunctionArray[i] = tmpArray[i];
|
||
389 | }
|
||
390 | analogReceiveFunctionArray[tmpCount] = newFunction;
|
||
391 | free(tmpArray);
|
||
392 | }
|
||
393 | */
|
||
394 | |||
395 | //******************************************************************************
|
||
396 | //* Private Methods
|
||
397 | //******************************************************************************
|
||
398 | |||
399 | |||
400 | |||
401 | // resets the system state upon a SYSTEM_RESET message from the host software
|
||
402 | void FirmataClass::systemReset(void) |
||
403 | { |
||
404 | byte i; |
||
405 | |||
406 | waitForData = 0; // this flag says the next serial input will be data |
||
407 | executeMultiByteCommand = 0; // execute this after getting multi-byte data |
||
408 | multiByteChannel = 0; // channel data for multiByteCommands |
||
409 | |||
410 | |||
411 | for(i=0; i<MAX_DATA_BYTES; i++) { |
||
412 | storedInputData[i] = 0;
|
||
413 | } |
||
414 | |||
415 | parsingSysex = false;
|
||
416 | sysexBytesRead = 0;
|
||
417 | |||
418 | if(currentSystemResetCallback)
|
||
419 | (*currentSystemResetCallback)(); |
||
420 | |||
421 | //flush(); //TODO uncomment when Firmata is a subclass of HardwareSerial
|
||
422 | } |
||
423 | |||
424 | |||
425 | |||
426 | // =============================================================================
|
||
427 | // used for flashing the pin for the version number
|
||
428 | void FirmataClass::pin13strobe(int count, int onInterval, int offInterval) |
||
429 | { |
||
430 | byte i; |
||
431 | pinMode(VERSION_BLINK_PIN, OUTPUT); |
||
432 | for(i=0; i<count; i++) { |
||
433 | delay(offInterval); |
||
434 | digitalWrite(VERSION_BLINK_PIN, HIGH); |
||
435 | delay(onInterval); |
||
436 | digitalWrite(VERSION_BLINK_PIN, LOW); |
||
437 | } |
||
438 | } |
||
439 | |||
440 | |||
441 | // make one instance for the user to use
|
||
442 | FirmataClass Firmata(Serial); |
||
443 |