Search wiring.org.co:

This example is for Wiring version 1.0 build 0100+. If you have a previous version, use the examples included with your software. If you see any errors or have comments, please let us know.

Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights reserved.
This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See file LICENSE.txt for further informations on licensing terms.

    /*
     * This is an old version of StandardFirmata (v2.0).  It is kept here because
     * its the last version that works on an ATMEGA8 chip.  Also, it can be used
     * for host software that has not been updated to a newer version of the
     * protocol.  It also uses the old baud rate of 115200 rather than 57600.
     * USE ONLY FOR Wiring boards v1.x
     */

    #include <Firmata.h>

    /*==============================================================================
     * GLOBAL VARIABLES
     *============================================================================*/

    /* analog inputs */
    int analogInputsToReport = 0; // bitwise array to store pin reporting
    int analogPin = 0; // counter for reading analog pins

    /* digital pins */
    byte reportPINs[TOTAL_PORTS];   // PIN == input port
    byte previousPINs[TOTAL_PORTS]; // PIN == input port
    byte pinStatus[TOTAL_PINS]; // store pin status, default OUTPUT
    byte portStatus[TOTAL_PORTS];

    /* timer variables */
    unsigned long currentMillis;     // store the current value from millis()
    unsigned long nextExecuteMillis; // for comparison with currentMillis

    /*==============================================================================
     * FUNCTIONS
     *============================================================================*/

    void outputPort(byte portNumber, byte portValue)
    {
      portValue = portValue &~ portStatus[portNumber];
      if (previousPINs[portNumber] != portValue) {
        Firmata.sendDigitalPort(portNumber, portValue);
        previousPINs[portNumber] = portValue;
        Firmata.sendDigitalPort(portNumber, portValue);
      }
    }

    /* -----------------------------------------------------------------------------
     * check all the active digital inputs for change of state, then add any events
     * to the Serial output queue using Serial.print() */
    void checkDigitalInputs(void)
    {
      byte i, tmp;
      for (i=0; i < TOTAL_PORTS; i++) {
        if (reportPINs[i]) {
          switch (i) {
          case 0:
            outputPort(0, PIND);
            break;
          case 1:
            outputPort(1, PINC);
            break;
          case 2:
            outputPort(2, PINA);
            break;
          case 3:
            outputPort(3, PINB);
            break;
          case 4:
            outputPort(4, PINE &~ B00000011);
            break; // ignore Rx/Tx 0/1
          case 5:
            outputPort(5, PINF);
            break;
          case 6:
            outputPort(6, PING);
            break;
          }
        }
      }
    }

    // -----------------------------------------------------------------------------
    /* sets the pin mode to the correct state and sets the relevant bits in the
     * two bit-arrays that track Digital I/O and PWM status
     */
    void setPinModeCallback(byte pin, int mode) {
      byte port = 0;
      byte offset = 0;

      if (pin < 8) {
        port = 0;
        offset = 0;
      }
      else if (pin < 16) {
        port = 1;
        offset = 8;
      }
      else if (pin < 24) {
        port = 2;
        offset = 16;
      }
      else if (pin < 32) {
        port = 3;
        offset = 24;
      }
      else if (pin < 40) {
        port = 4;
        offset = 32;
      }
      else if (pin < 48) {
        port = 5;
        offset = 40;
      }
      else if (pin < 54) {
        port = 6;
        offset = 48;
      }

      if ((pin<32)&&(pin > 33)) { // ignore RxTx (pins 32 and 33)
        pinStatus[pin] = mode;
        switch (mode) {
        case INPUT:
          pinMode(pin, INPUT);
          portStatus[port] = portStatus[port] &~ (1 << (pin - offset));
          break;
        case OUTPUT:
          digitalWrite(pin, LOW); // disable PWM
        case PWM:
          pinMode(pin, OUTPUT);
          portStatus[port] = portStatus[port] | (1 << (pin - offset));
          break;
          //case ANALOG: // TODO figure this out
        default:
          Firmata.sendString("");
        }
        // TODO: save status to EEPROM here, if changed
      }
    }

    void analogWriteCallback(byte pin, int value)
    {
      setPinModeCallback(pin,PWM);
      analogWrite(pin, value);
    }

    void digitalWriteCallback(byte port, int value)
    {
      switch (port) {
      case 0: // pins 0-7
        PORTD = (byte)value;
        break;
      case 1: // pins 8-15
        PORTC = (byte)value;
        break;
      case 2: // pins 16-23
        PORTA = (byte)value;
        break;
      case 3: // pins 24-31
        PORTB = (byte)value;
        break;
      case 4: // pins 34-39 (don't change Rx/Tx, pins 32 and 33)
        // 0xFF03 == B1111111100000011    0x03 == B00000011
        PORTE = (value &~ 0xFF03) | (PORTE & 0x03);
        break;
      case 5: // pins 40-47
        PORTF = (byte)value;
        break;
      case 6: // pins 48-53
        PORTG = (byte)value;
        break;
      }
    }

    // -----------------------------------------------------------------------------
    /* sets bits in a bit array (int) to toggle the reporting of the analogIns
     */
    //void FirmataClass::setAnalogPinReporting(byte pin, byte state) {
    //}
    void reportAnalogCallback(byte pin, int value)
    {
      if (value == 0) {
        analogInputsToReport = analogInputsToReport &~ (1 << pin);
      }
      else { // everything but 0 enables reporting of that pin
        analogInputsToReport = analogInputsToReport | (1 << pin);
      }
      // TODO: save status to EEPROM here, if changed
    }

    void reportDigitalCallback(byte port, int value)
    {
      reportPINs[port] = (byte)value;
      if (port == 5) // turn off analog reporting when used as digital
        analogInputsToReport = 0;
    }

    /*==============================================================================
     * SETUP()
     *============================================================================*/
    void setup()
    {
      byte i;

      Firmata.setFirmwareVersion(2, 0);

      Firmata.attach(ANALOG_MESSAGE, analogWriteCallback);
      Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback);
      Firmata.attach(REPORT_ANALOG, reportAnalogCallback);
      Firmata.attach(REPORT_DIGITAL, reportDigitalCallback);
      Firmata.attach(SET_PIN_MODE, setPinModeCallback);

      portStatus[0] = B00000000;
      portStatus[1] = B00000000;
      portStatus[2] = B00000000;
      portStatus[3] = B00000000;
      portStatus[4] = B00000011;  // ignore Tx/RX pins
      portStatus[5] = B00000000;
      portStatus[6] = B00000000;

      //    for (i=0; i<TOTAL_DIGITAL_PINS; ++i) { // TODO make this work with analogs
      for (i=0; i<40; ++i) {
        setPinModeCallback(i,OUTPUT);
      }
      // set all outputs to 0 to make sure internal pull-up resistors are off
      PORTD = 0; // pins 0-7
      PORTC = 0; // pins 8-15
      PORTA = 0; // pins 16-23
      PORTB = 0; // pins 24-31
      PORTE = 0; // pins 32-39
      PORTF = 0; // analog port
      PORTG = 0; // pins 48-53

      // TODO rethink the init, perhaps it should report analog on default
      for (i=0; i<TOTAL_PORTS; ++i) {
        reportPINs[i] = false;
      }
      // TODO: load state from EEPROM here

      /* send digital inputs here, if enabled, to set the initial state on the
       * host computer, since once in the loop(), this firmware will only send
       * digital data on change. */
      if (reportPINs[0]) outputPort(0, PIND);
      if (reportPINs[1]) outputPort(1, PINC);
      if (reportPINs[2]) outputPort(2, PINA);
      if (reportPINs[3]) outputPort(3, PINB);
      if (reportPINs[4]) outputPort(4, PINE &~ B00000011); // ignore Rx/Tx 0/1
      if (reportPINs[5]) outputPort(5, PINF);
      if (reportPINs[6]) outputPort(6, PING);

      Firmata.begin(115200);
    }

    /*==============================================================================
     * LOOP()
     *============================================================================*/
    void loop()
    {
      /* DIGITALREAD - as fast as possible, check for changes and output them to the
       * FTDI buffer using Serial.print()  */
      checkDigitalInputs();
      currentMillis = millis();
      if (currentMillis > nextExecuteMillis) {
        nextExecuteMillis = currentMillis + 19; // run this every 20ms
        /* SERIALREAD - Serial.read() uses a 128 byte circular buffer, so handle
         * all serialReads at once, i.e. empty the buffer */
        while(Firmata.available())
          Firmata.processInput();
        /* SEND FTDI WRITE BUFFER - make sure that the FTDI buffer doesn't go over
         * 60 bytes. use a timer to sending an event character every 4 ms to
         * trigger the buffer to dump. */

        /* ANALOGREAD - right after the event character, do all of the
         * analogReads().  These only need to be done every 4ms. */
        for (analogPin=0;analogPin<TOTAL_ANALOG_PINS;analogPin++) {
          if ( analogInputsToReport & (1 << analogPin) ) {
            Firmata.sendAnalog(analogPin, analogRead(analogPin));
          }
        }
      }
    }