~ubuntu-branches/debian/experimental/arduino/experimental

« back to all changes in this revision

Viewing changes to libraries/Firmata/examples/StandardFirmata_2_2_forUNO_0_3/StandardFirmata_2_2_forUNO_0_3.pde

  • Committer: Package Import Robot
  • Author(s): Scott Howard
  • Date: 2012-03-11 18:19:42 UTC
  • mfrom: (1.1.5) (5.1.14 sid)
  • Revision ID: package-import@ubuntu.com-20120311181942-be2clnbz1gcehixb
Tags: 1:1.0.1~rc1+dfsg-1
New upstream release, experimental.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
  This introduces modifications on the normal Firmata made for Arduino so that the LED 
3
 
  blinks until receiving the first command over serial.
4
 
 
5
 
  Copyright (C) 2010 David Cuartielles.  All rights reserved.
6
 
  
7
 
  based at 99.9% on Firmata by HC Steiner according to the following license terms:
8
 
  
9
 
  Copyright (C) 2006-2008 Hans-Christoph Steiner.  All rights reserved.
10
 
  
11
 
  This library is free software; you can redistribute it and/or
12
 
  modify it under the terms of the GNU Lesser General Public
13
 
  License as published by the Free Software Foundation; either
14
 
  version 2.1 of the License, or (at your option) any later version.
15
 
 
16
 
  See file LICENSE.txt for further informations on licensing terms.
17
 
 
18
 
  formatted using the GNU C formatting and indenting
19
 
*/
20
 
 
21
 
/* 
22
 
 * TODO: use Program Control to load stored profiles from EEPROM
23
 
 */
24
 
 
25
 
#include <Servo.h>
26
 
#include <Firmata.h>
27
 
 
28
 
/*==============================================================================
29
 
 * GLOBAL VARIABLES
30
 
 *============================================================================*/
31
 
 
32
 
/* has the command arrived? */
33
 
boolean firstCommand = false;
34
 
int dataOnSerial = 0;
35
 
boolean statusLed = false;
36
 
 
37
 
/* analog inputs */
38
 
int analogInputsToReport = 0; // bitwise array to store pin reporting
39
 
 
40
 
/* digital input ports */
41
 
byte reportPINs[TOTAL_PORTS];       // 1 = report this port, 0 = silence
42
 
byte previousPINs[TOTAL_PORTS];     // previous 8 bits sent
43
 
 
44
 
/* pins configuration */
45
 
byte pinConfig[TOTAL_PINS];         // configuration of every pin
46
 
byte portConfigInputs[TOTAL_PORTS]; // each bit: 1 = pin in INPUT, 0 = anything else
47
 
int pinState[TOTAL_PINS];           // any value that has been written
48
 
 
49
 
/* timer variables */
50
 
unsigned long currentMillis;        // store the current value from millis()
51
 
unsigned long previousMillis;       // for comparison with currentMillis
52
 
int samplingInterval = 19;          // how often to run the main loop (in ms)
53
 
unsigned long toggleMillis;
54
 
 
55
 
Servo servos[MAX_SERVOS];
56
 
 
57
 
/*==============================================================================
58
 
 * FUNCTIONS
59
 
 *============================================================================*/
60
 
 
61
 
void toggleLed() 
62
 
{
63
 
  if (millis() - toggleMillis > 500) {
64
 
    statusLed = !statusLed;
65
 
    digitalWrite(13, statusLed);
66
 
    toggleMillis = millis();
67
 
  }
68
 
}
69
 
 
70
 
void outputPort(byte portNumber, byte portValue, byte forceSend)
71
 
{
72
 
  // pins not configured as INPUT are cleared to zeros
73
 
  portValue = portValue & portConfigInputs[portNumber];
74
 
  // only send if the value is different than previously sent
75
 
  if(forceSend || previousPINs[portNumber] != portValue) {
76
 
    Firmata.sendDigitalPort(portNumber, portValue);
77
 
    previousPINs[portNumber] = portValue;
78
 
  }
79
 
}
80
 
 
81
 
/* -----------------------------------------------------------------------------
82
 
 * check all the active digital inputs for change of state, then add any events
83
 
 * to the Serial output queue using Serial.print() */
84
 
void checkDigitalInputs(void)
85
 
{
86
 
  /* Using non-looping code allows constants to be given to readPort().
87
 
   * The compiler will apply substantial optimizations if the inputs
88
 
   * to readPort() are compile-time constants. */
89
 
  if (TOTAL_PORTS > 0 && reportPINs[0]) outputPort(0, readPort(0, portConfigInputs[0]), false);
90
 
  if (TOTAL_PORTS > 1 && reportPINs[1]) outputPort(1, readPort(1, portConfigInputs[1]), false);
91
 
  if (TOTAL_PORTS > 2 && reportPINs[2]) outputPort(2, readPort(2, portConfigInputs[2]), false);
92
 
  if (TOTAL_PORTS > 3 && reportPINs[3]) outputPort(3, readPort(3, portConfigInputs[3]), false);
93
 
  if (TOTAL_PORTS > 4 && reportPINs[4]) outputPort(4, readPort(4, portConfigInputs[4]), false);
94
 
  if (TOTAL_PORTS > 5 && reportPINs[5]) outputPort(5, readPort(5, portConfigInputs[5]), false);
95
 
  if (TOTAL_PORTS > 6 && reportPINs[6]) outputPort(6, readPort(6, portConfigInputs[6]), false);
96
 
  if (TOTAL_PORTS > 7 && reportPINs[7]) outputPort(7, readPort(7, portConfigInputs[7]), false);
97
 
  if (TOTAL_PORTS > 8 && reportPINs[8]) outputPort(8, readPort(8, portConfigInputs[8]), false);
98
 
  if (TOTAL_PORTS > 9 && reportPINs[9]) outputPort(9, readPort(9, portConfigInputs[9]), false);
99
 
  if (TOTAL_PORTS > 10 && reportPINs[10]) outputPort(10, readPort(10, portConfigInputs[10]), false);
100
 
  if (TOTAL_PORTS > 11 && reportPINs[11]) outputPort(11, readPort(11, portConfigInputs[11]), false);
101
 
  if (TOTAL_PORTS > 12 && reportPINs[12]) outputPort(12, readPort(12, portConfigInputs[12]), false);
102
 
  if (TOTAL_PORTS > 13 && reportPINs[13]) outputPort(13, readPort(13, portConfigInputs[13]), false);
103
 
  if (TOTAL_PORTS > 14 && reportPINs[14]) outputPort(14, readPort(14, portConfigInputs[14]), false);
104
 
  if (TOTAL_PORTS > 15 && reportPINs[15]) outputPort(15, readPort(15, portConfigInputs[15]), false);
105
 
}
106
 
 
107
 
// -----------------------------------------------------------------------------
108
 
/* sets the pin mode to the correct state and sets the relevant bits in the
109
 
 * two bit-arrays that track Digital I/O and PWM status
110
 
 */
111
 
void setPinModeCallback(byte pin, int mode)
112
 
{
113
 
  if (IS_PIN_SERVO(pin) && mode != SERVO && servos[PIN_TO_SERVO(pin)].attached()) {
114
 
    servos[PIN_TO_SERVO(pin)].detach();
115
 
  }
116
 
  if (IS_PIN_ANALOG(pin)) {
117
 
    reportAnalogCallback(PIN_TO_ANALOG(pin), mode == ANALOG ? 1 : 0); // turn on/off reporting
118
 
  }
119
 
  if (IS_PIN_DIGITAL(pin)) {
120
 
    if (mode == INPUT) {
121
 
      portConfigInputs[pin/8] |= (1 << (pin & 7));
122
 
    } else {
123
 
      portConfigInputs[pin/8] &= ~(1 << (pin & 7));
124
 
    }
125
 
  }
126
 
  pinState[pin] = 0;
127
 
  switch(mode) {
128
 
  case ANALOG:
129
 
    if (IS_PIN_ANALOG(pin)) {
130
 
      if (IS_PIN_DIGITAL(pin)) {
131
 
        pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver
132
 
        digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups
133
 
      }
134
 
      pinConfig[pin] = ANALOG;
135
 
    }
136
 
    break;
137
 
  case INPUT:
138
 
    if (IS_PIN_DIGITAL(pin)) {
139
 
      pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver
140
 
      digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups
141
 
      pinConfig[pin] = INPUT;
142
 
    }
143
 
    break;
144
 
  case OUTPUT:
145
 
    if (IS_PIN_DIGITAL(pin)) {
146
 
      digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM
147
 
      pinMode(PIN_TO_DIGITAL(pin), OUTPUT);
148
 
      pinConfig[pin] = OUTPUT;
149
 
    }
150
 
    break;
151
 
  case PWM:
152
 
    if (IS_PIN_PWM(pin)) {
153
 
      pinMode(PIN_TO_PWM(pin), OUTPUT);
154
 
      analogWrite(PIN_TO_PWM(pin), 0);
155
 
      pinConfig[pin] = PWM;
156
 
    }
157
 
    break;
158
 
  case SERVO:
159
 
    if (IS_PIN_SERVO(pin)) {
160
 
      pinConfig[pin] = SERVO;
161
 
      if (!servos[PIN_TO_SERVO(pin)].attached()) {
162
 
          servos[PIN_TO_SERVO(pin)].attach(PIN_TO_DIGITAL(pin));
163
 
      } else {
164
 
        Firmata.sendString("Servo only on pins from 2 to 13");
165
 
      }
166
 
    }
167
 
    break;
168
 
  case I2C:
169
 
    pinConfig[pin] = mode;
170
 
    Firmata.sendString("I2C mode not yet supported");
171
 
    break;
172
 
  default:
173
 
    Firmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM
174
 
  }
175
 
  // TODO: save status to EEPROM here, if changed
176
 
}
177
 
 
178
 
void analogWriteCallback(byte pin, int value)
179
 
{
180
 
  if (pin < TOTAL_PINS) {
181
 
    switch(pinConfig[pin]) {
182
 
    case SERVO:
183
 
      if (IS_PIN_SERVO(pin))
184
 
        servos[PIN_TO_SERVO(pin)].write(value);
185
 
        pinState[pin] = value;
186
 
      break;
187
 
    case PWM:
188
 
      if (IS_PIN_PWM(pin))
189
 
        analogWrite(PIN_TO_PWM(pin), value);
190
 
        pinState[pin] = value;
191
 
      break;
192
 
    }
193
 
  }
194
 
}
195
 
 
196
 
void digitalWriteCallback(byte port, int value)
197
 
{
198
 
  byte pin, lastPin, mask=1, pinWriteMask=0;
199
 
 
200
 
  if (port < TOTAL_PORTS) {
201
 
    // create a mask of the pins on this port that are writable.
202
 
    lastPin = port*8+8;
203
 
    if (lastPin > TOTAL_PINS) lastPin = TOTAL_PINS;
204
 
    for (pin=port*8; pin < lastPin; pin++) {
205
 
      // do not disturb non-digital pins (eg, Rx & Tx)
206
 
      if (IS_PIN_DIGITAL(pin)) {
207
 
        // only write to OUTPUT and INPUT (enables pullup)
208
 
        // do not touch pins in PWM, ANALOG, SERVO or other modes
209
 
        if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) {
210
 
          pinWriteMask |= mask;
211
 
          pinState[pin] = ((byte)value & mask) ? 1 : 0;
212
 
        }
213
 
      }
214
 
      mask = mask << 1;
215
 
    }
216
 
    writePort(port, (byte)value, pinWriteMask);
217
 
  }
218
 
}
219
 
 
220
 
 
221
 
// -----------------------------------------------------------------------------
222
 
/* sets bits in a bit array (int) to toggle the reporting of the analogIns
223
 
 */
224
 
//void FirmataClass::setAnalogPinReporting(byte pin, byte state) {
225
 
//}
226
 
void reportAnalogCallback(byte analogPin, int value)
227
 
{
228
 
  if (analogPin < TOTAL_ANALOG_PINS) {
229
 
    if(value == 0) {
230
 
      analogInputsToReport = analogInputsToReport &~ (1 << analogPin);
231
 
    } else {
232
 
      analogInputsToReport = analogInputsToReport | (1 << analogPin);
233
 
    }
234
 
  }
235
 
  // TODO: save status to EEPROM here, if changed
236
 
}
237
 
 
238
 
void reportDigitalCallback(byte port, int value)
239
 
{
240
 
  if (port < TOTAL_PORTS) {
241
 
    reportPINs[port] = (byte)value;
242
 
  }
243
 
  // do not disable analog reporting on these 8 pins, to allow some
244
 
  // pins used for digital, others analog.  Instead, allow both types
245
 
  // of reporting to be enabled, but check if the pin is configured
246
 
  // as analog when sampling the analog inputs.  Likewise, while
247
 
  // scanning digital pins, portConfigInputs will mask off values from any
248
 
  // pins configured as analog
249
 
}
250
 
 
251
 
/*==============================================================================
252
 
 * SYSEX-BASED commands
253
 
 *============================================================================*/
254
 
 
255
 
void sysexCallback(byte command, byte argc, byte *argv)
256
 
{
257
 
  switch(command) {
258
 
  case SERVO_CONFIG:
259
 
    if(argc > 4) {
260
 
      // these vars are here for clarity, they'll optimized away by the compiler
261
 
      byte pin = argv[0];
262
 
      int minPulse = argv[1] + (argv[2] << 7);
263
 
      int maxPulse = argv[3] + (argv[4] << 7);
264
 
 
265
 
      if (IS_PIN_SERVO(pin)) {
266
 
        // servos are pins from 2 to 13, so offset for array
267
 
        if (servos[PIN_TO_SERVO(pin)].attached())
268
 
          servos[PIN_TO_SERVO(pin)].detach();
269
 
        servos[PIN_TO_SERVO(pin)].attach(PIN_TO_DIGITAL(pin), minPulse, maxPulse);
270
 
        setPinModeCallback(pin, SERVO);
271
 
      }
272
 
    }
273
 
    break;
274
 
  case SAMPLING_INTERVAL:
275
 
    if (argc > 1)
276
 
      samplingInterval = argv[0] + (argv[1] << 7);
277
 
    else
278
 
      Firmata.sendString("Not enough data");
279
 
    break;
280
 
  case EXTENDED_ANALOG:
281
 
    if (argc > 1) {
282
 
      int val = argv[1];
283
 
      if (argc > 2) val |= (argv[2] << 7);
284
 
      if (argc > 3) val |= (argv[3] << 14);
285
 
      analogWriteCallback(argv[0], val);
286
 
    }
287
 
    break;
288
 
  case CAPABILITY_QUERY:
289
 
    Serial.write(START_SYSEX);
290
 
    Serial.write(CAPABILITY_RESPONSE);
291
 
    for (byte pin=0; pin < TOTAL_PINS; pin++) {
292
 
      if (IS_PIN_DIGITAL(pin)) {
293
 
        Serial.write((byte)INPUT);
294
 
        Serial.write(1);
295
 
        Serial.write((byte)OUTPUT);
296
 
        Serial.write(1);
297
 
      }
298
 
      if (IS_PIN_ANALOG(pin)) {
299
 
        Serial.write(ANALOG);
300
 
        Serial.write(10);
301
 
      }
302
 
      if (IS_PIN_PWM(pin)) {
303
 
        Serial.write(PWM);
304
 
        Serial.write(8);
305
 
      }
306
 
      if (IS_PIN_SERVO(pin)) {
307
 
        Serial.write(SERVO);
308
 
        Serial.write(14);
309
 
      }
310
 
      Serial.write(127);
311
 
    }
312
 
    Serial.write(END_SYSEX);
313
 
    break;
314
 
  case PIN_STATE_QUERY:
315
 
    if (argc > 0) {
316
 
      byte pin=argv[0];
317
 
      Serial.write(START_SYSEX);
318
 
      Serial.write(PIN_STATE_RESPONSE);
319
 
      Serial.write(pin);
320
 
      if (pin < TOTAL_PINS) {
321
 
        Serial.write((byte)pinConfig[pin]);
322
 
        Serial.write((byte)pinState[pin] & 0x7F);
323
 
        if (pinState[pin] & 0xFF80) Serial.write((byte)(pinState[pin] >> 7) & 0x7F);
324
 
        if (pinState[pin] & 0xC000) Serial.write((byte)(pinState[pin] >> 14) & 0x7F);
325
 
      }
326
 
      Serial.write(END_SYSEX);
327
 
    }
328
 
    break;
329
 
  case ANALOG_MAPPING_QUERY:
330
 
    Serial.write(START_SYSEX);
331
 
    Serial.write(ANALOG_MAPPING_RESPONSE);
332
 
    for (byte pin=0; pin < TOTAL_PINS; pin++) {
333
 
      Serial.write(IS_PIN_ANALOG(pin) ? PIN_TO_ANALOG(pin) : 127);
334
 
    }
335
 
    Serial.write(END_SYSEX);
336
 
    break;
337
 
  }
338
 
}
339
 
 
340
 
/*==============================================================================
341
 
 * SETUP()
342
 
 *============================================================================*/
343
 
void setup() 
344
 
{
345
 
  byte i;
346
 
 
347
 
  Firmata.setFirmwareVersion(2, 2);
348
 
 
349
 
  Firmata.attach(ANALOG_MESSAGE, analogWriteCallback);
350
 
  Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback);
351
 
  Firmata.attach(REPORT_ANALOG, reportAnalogCallback);
352
 
  Firmata.attach(REPORT_DIGITAL, reportDigitalCallback);
353
 
  Firmata.attach(SET_PIN_MODE, setPinModeCallback);
354
 
  Firmata.attach(START_SYSEX, sysexCallback);
355
 
 
356
 
  // TODO: load state from EEPROM here
357
 
 
358
 
  /* these are initialized to zero by the compiler startup code
359
 
  for (i=0; i < TOTAL_PORTS; i++) {
360
 
    reportPINs[i] = false;
361
 
    portConfigInputs[i] = 0;
362
 
    previousPINs[i] = 0;
363
 
  }
364
 
  */
365
 
  for (i=0; i < TOTAL_PINS; i++) {
366
 
    if (IS_PIN_ANALOG(i)) {
367
 
      // turns off pullup, configures everything
368
 
      setPinModeCallback(i, ANALOG);
369
 
    } else {
370
 
      // sets the output to 0, configures portConfigInputs
371
 
      setPinModeCallback(i, OUTPUT);
372
 
    }
373
 
  }
374
 
  // by defult, do not report any analog inputs
375
 
  analogInputsToReport = 0;
376
 
 
377
 
  Firmata.begin(57600);
378
 
 
379
 
  /* send digital inputs to set the initial state on the host computer,
380
 
   * since once in the loop(), this firmware will only send on change */
381
 
  for (i=0; i < TOTAL_PORTS; i++) {
382
 
    outputPort(i, readPort(i, portConfigInputs[i]), true);
383
 
  }
384
 
  
385
 
  /* init the toggleLed counter */
386
 
  toggleMillis = millis();
387
 
  pinMode(13, OUTPUT);
388
 
}
389
 
 
390
 
/*==============================================================================
391
 
 * LOOP()
392
 
 *============================================================================*/
393
 
void loop() 
394
 
{
395
 
  byte pin, analogPin;
396
 
 
397
 
  /* DIGITALREAD - as fast as possible, check for changes and output them to the
398
 
   * FTDI buffer using Serial.print()  */
399
 
  checkDigitalInputs();  
400
 
 
401
 
  //XXX: hack Firmata to blink until serial command arrives 
402
 
  dataOnSerial = Firmata.available();
403
 
  if (dataOnSerial > 0 && !firstCommand) {
404
 
    firstCommand = true;
405
 
  }
406
 
  //XXX: do the blink if the first command hasn't arrived yet
407
 
  //     configures pin 13 as output and then back as input
408
 
  if (!firstCommand) {
409
 
    toggleLed();
410
 
  }
411
 
  
412
 
  /* SERIALREAD - processing incoming messagse as soon as possible, while still
413
 
   * checking digital inputs.  */
414
 
  while(dataOnSerial) {
415
 
    Firmata.processInput();
416
 
    dataOnSerial = Firmata.available();
417
 
  }
418
 
  
419
 
  /* SEND FTDI WRITE BUFFER - make sure that the FTDI buffer doesn't go over
420
 
   * 60 bytes. use a timer to sending an event character every 4 ms to
421
 
   * trigger the buffer to dump. */
422
 
 
423
 
  currentMillis = millis();
424
 
  if (currentMillis - previousMillis > samplingInterval) {
425
 
    previousMillis += samplingInterval;
426
 
    /* ANALOGREAD - do all analogReads() at the configured sampling interval */
427
 
    for(pin=0; pin<TOTAL_PINS; pin++) {
428
 
      if (IS_PIN_ANALOG(pin) && pinConfig[pin] == ANALOG) {
429
 
        analogPin = PIN_TO_ANALOG(pin);
430
 
        if (analogInputsToReport & (1 << analogPin)) {
431
 
          Firmata.sendAnalog(analogPin, analogRead(analogPin));
432
 
        }
433
 
      }
434
 
    }
435
 
  }
436
 
}