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

Circuit diagram
Circuit for project
Circuit diagram

Comments
Only logged in users can leave comments