Project

General

Profile

Statistics
| Branch: | Revision:

root / arduino-1.0 / libraries / Firmata / examples / I2CFirmata / I2CFirmata.ino @ 58d82c77

History | View | Annotate | Download (6.09 KB)

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) 2009 Jeff Hoefs.  All rights reserved.
14
 Copyright (C) 2009 Shigeru Kobayashi.  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

    
24
#include <Wire.h>
25
#include <Firmata.h>
26

    
27

    
28
#define I2C_WRITE B00000000
29
#define I2C_READ B00001000
30
#define I2C_READ_CONTINUOUSLY B00010000
31
#define I2C_STOP_READING B00011000
32
#define I2C_READ_WRITE_MODE_MASK B00011000
33

    
34
#define MAX_QUERIES 8
35

    
36
unsigned long currentMillis;     // store the current value from millis()
37
unsigned long previousMillis;    // for comparison with currentMillis
38
unsigned int samplingInterval = 32;  // default sampling interval is 33ms
39
unsigned int i2cReadDelayTime = 0;  // default delay time between i2c read request and Wire.requestFrom()
40
unsigned int powerPinsEnabled = 0;  // use as boolean to prevent enablePowerPins from being called more than once
41

    
42
#define MINIMUM_SAMPLING_INTERVAL 10
43

    
44
#define REGISTER_NOT_SPECIFIED -1
45

    
46
struct i2c_device_info {
47
  byte addr;
48
  byte reg;
49
  byte bytes;
50
};
51

    
52
i2c_device_info query[MAX_QUERIES];
53

    
54
byte i2cRxData[32];
55
boolean readingContinuously = false;
56
byte queryIndex = 0;
57

    
58
void readAndReportData(byte address, int theRegister, byte numBytes)
59
{
60
  if (theRegister != REGISTER_NOT_SPECIFIED) {
61
    Wire.beginTransmission(address);
62
    Wire.write((byte)theRegister);
63
    Wire.endTransmission();
64
    delayMicroseconds(i2cReadDelayTime);  // delay is necessary for some devices such as WiiNunchuck
65
  } 
66
  else {
67
    theRegister = 0;  // fill the register with a dummy value
68
  }
69

    
70
  Wire.requestFrom(address, numBytes);
71

    
72
  // check to be sure correct number of bytes were returned by slave
73
  if(numBytes == Wire.available()) {
74
    i2cRxData[0] = address;
75
    i2cRxData[1] = theRegister;
76
    for (int i = 0; i < numBytes; i++) {
77
      i2cRxData[2 + i] = Wire.read();
78
    }
79
    // send slave address, register and received bytes
80
    Firmata.sendSysex(I2C_REPLY, numBytes + 2, i2cRxData);
81
  }
82
  else {
83
    if(numBytes > Wire.available()) {
84
      Firmata.sendString("I2C Read Error: Too many bytes received");
85
    } else {
86
      Firmata.sendString("I2C Read Error: Too few bytes received"); 
87
    }
88
  }
89
  
90
}
91

    
92
void sysexCallback(byte command, byte argc, byte *argv)
93
{
94
  byte mode;
95
  byte slaveAddress;
96
  byte slaveRegister;
97
  byte data;
98
  int  delayTime;
99

    
100
  if (command == I2C_REQUEST) {
101
    mode = argv[1] & I2C_READ_WRITE_MODE_MASK;
102
    slaveAddress = argv[0];
103

    
104
    switch(mode) {
105
    case I2C_WRITE:
106
      Wire.beginTransmission(slaveAddress);
107
      for (byte i = 2; i < argc; i += 2) {
108
        data = argv[i] + (argv[i + 1] << 7);
109
        Wire.write(data);
110
      }
111
      Wire.endTransmission();
112
      delayMicroseconds(70); // TODO is this needed?
113
      break;
114
    case I2C_READ:
115
      if (argc == 6) {
116
        // a slave register is specified
117
        slaveRegister = argv[2] + (argv[3] << 7);
118
        data = argv[4] + (argv[5] << 7);  // bytes to read
119
        readAndReportData(slaveAddress, (int)slaveRegister, data);
120
      } 
121
      else {
122
        // a slave register is NOT specified
123
        data = argv[2] + (argv[3] << 7);  // bytes to read
124
        readAndReportData(slaveAddress, (int)REGISTER_NOT_SPECIFIED, data);
125
      }
126
      break;
127
    case I2C_READ_CONTINUOUSLY:
128
      if ((queryIndex + 1) >= MAX_QUERIES) {
129
        // too many queries, just ignore
130
        Firmata.sendString("too many queries");
131
        break;
132
      }
133
      query[queryIndex].addr = slaveAddress;
134
      query[queryIndex].reg = argv[2] + (argv[3] << 7);
135
      query[queryIndex].bytes = argv[4] + (argv[5] << 7);
136
      readingContinuously = true;
137
      queryIndex++;
138
      break;
139
    case I2C_STOP_READING:
140
      readingContinuously = false;
141
      queryIndex = 0;
142
      break;
143
    default:
144
      break;
145
    }
146
  }
147
  else if (command == SAMPLING_INTERVAL) {
148
    samplingInterval = argv[0] + (argv[1] << 7);
149

    
150
    if (samplingInterval < MINIMUM_SAMPLING_INTERVAL) {
151
      samplingInterval = MINIMUM_SAMPLING_INTERVAL;
152
    }
153

    
154
    samplingInterval -= 1;
155
    Firmata.sendString("sampling interval");
156
  }
157

    
158
  else if (command == I2C_CONFIG) {
159
    delayTime = (argv[4] + (argv[5] << 7));                        // MSB
160
    delayTime = (delayTime << 8) + (argv[2] + (argv[3] << 7));     // add LSB
161

    
162
    if((argv[0] + (argv[1] << 7)) > 0) {
163
      enablePowerPins(PORTC3, PORTC2);
164
    }
165

    
166
    if(delayTime > 0) {
167
      i2cReadDelayTime = delayTime;
168
    }
169

    
170
    if(argc > 6) {
171
      // If you extend I2C_Config, handle your data here
172
    }
173

    
174
  }
175
}
176

    
177
void systemResetCallback()
178
{
179
  readingContinuously = false;
180
  queryIndex = 0;
181
}
182

    
183
/* reference: BlinkM_funcs.h by Tod E. Kurt, ThingM, http://thingm.com/ */
184
// Enables Pins A2 and A3 to be used as GND and Power
185
// so that I2C devices can be plugged directly
186
// into Arduino header (pins A2 - A5)
187
static void enablePowerPins(byte pwrpin, byte gndpin)
188
{
189
  if(powerPinsEnabled == 0) {
190
    DDRC |= _BV(pwrpin) | _BV(gndpin);
191
    PORTC &=~ _BV(gndpin);
192
    PORTC |=  _BV(pwrpin);
193
    powerPinsEnabled = 1;
194
    Firmata.sendString("Power pins enabled");
195
    delay(100);
196
  }
197
}
198

    
199
void setup()
200
{
201
  Firmata.setFirmwareVersion(2, 0);
202

    
203
  Firmata.attach(START_SYSEX, sysexCallback);
204
  Firmata.attach(SYSTEM_RESET, systemResetCallback);
205

    
206
  for (int i = 0; i < TOTAL_PINS; ++i) {
207
    pinMode(i, OUTPUT);
208
  }
209

    
210
  Firmata.begin(57600);  
211
  Wire.begin();
212
}
213

    
214
void loop()
215
{
216
  while (Firmata.available()) {
217
    Firmata.processInput();
218
  }
219

    
220
  currentMillis = millis();
221
  if (currentMillis - previousMillis > samplingInterval) {
222
    previousMillis += samplingInterval;
223

    
224
    for (byte i = 0; i < queryIndex; i++) {
225
      readAndReportData(query[i].addr, query[i].reg, query[i].bytes);
226
    }
227
  }
228
}