I finally got the arduino dock 2 working under O2+ 0.1.9 b149 and I built up a commented example for using the I2C interface between the Omega and the dock. For the example ideally you would have an external LED w/ resistor attached between ground and digital pin 12 of the arduino headers. But if you don't have that you can simply change the code right at the beginning to use digital pin 13 which is effectively the blue led on the dock:
#include <Wire.h> // for i2c communications
int EXTLED = 12; // use any arduino digital pin between 2 and 12, or 13 if no external led
int REGISTER[8]; // can range in size from 1 to 255
int INDEX = 0; // current index into the register
int STATE = 0; // current state
void setup() {
pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, LOW); // blue led on the arduino dock 2
pinMode(EXTLED, OUTPUT); digitalWrite(EXTLED, LOW); // my selected external led
Wire.begin(0x08); // 0x08 is the arduino dock 2 i2c port
Wire.onReceive(i2c_on_receive_handler);
Wire.onRequest(i2c_on_request_handler);
Serial.begin(9600); // serial output to /dev/ttyS1 on the omega2
}
void loop() {
// the first byte of the register controls blinking for the external led
// to start the blinking: i2cset -y 0 0x08 0x02 0x00 0x01 i # the third byte sets index 0
// to stop the blinking: i2cset -y 0 0x08 0x02 0x00 0x00 i # the last byte is the value
if (REGISTER[0] != 0) {
digitalWrite(EXTLED, HIGH);
delay(1000);
digitalWrite(EXTLED, LOW);
delay(1000);
}
}
// called when a transmission is received via the i2c port
void i2c_on_receive_handler(int bytes_received) {
int cmd = Wire.read();
int v = 0;
Serial.print("received command/data, value: "); Serial.print(cmd, HEX); Serial.print("\n");
switch (cmd) {
case 0: // toggle the blue led once - ex: i2cset -y 0 0x08 0x00
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
Serial.print("toggled led\n");
STATE = 0;
break;
case 1: // turn the blue led on or off - ex: i2cset -y 0 0x08 0x01 0x01 i # for on, last byte 0x00 for off
v = Wire.read();
digitalWrite(LED_BUILTIN, v ? HIGH : LOW);
Serial.print("led value set to: "); Serial.print(v); Serial.print("\n");
STATE = 0;
break;
case 2: // write value to the register at index - ex: i2cset -y 0 0x08 0x02 0x00 0x01 i # 3rd byte is the index, 4th byte is the value
INDEX = Wire.read(); v = Wire.read(); // note: should check valid range for INDEX, in our case 0-7
REGISTER[INDEX] = v;
STATE = 0;
Serial.print("wrote value: "); Serial.print(v, HEX); Serial.print(" to register at index: "); Serial.print(INDEX, HEX); Serial.print("\n");
break;
case 3: // prepare to read a value from the register at index - ex: i2cset -y 0 0x08 0x03 0x00 i # 3rd byte is the index
INDEX = Wire.read();
STATE = 3; // register value at index can now be read - ex: i2cget -y 0 0x08
Serial.print("set register index to: "); Serial.print(INDEX); Serial.print(", and state to 3\n");
break;
default:
Serial.print("error, unexpected command value!\n");
}
}
// called when data is requested via the i2c port
void i2c_on_request_handler() {
byte v = 0;
switch (STATE) {
case 0: // default - reads and returns the current state of the blue led - ex: i2cget -y 0 0x08
v = digitalRead(LED_BUILTIN);
break;
case 3: // read and return register value at index - must be set up for read using command 0x03 from above
v = REGISTER[INDEX];
STATE = 0;
break;
default:
;
}
// note: any attempt to print causes the Wire.write() to fail - don't know why
// Serial.print("received request, returned: "); Serial.print(v, HEX); Serial.print("\n");
Wire.write(v);
}
Basically you use i2cset and i2cget to send commands and data to the arduino and possibly retrieve data back. For example to simply toggle the blue LED:
i2cset -y 0 0x08 0x00
This sends a command byte of 0x00 to the arduino via I2C port 0x08. The blue LED will toggle on or off. These use command byte 0x01 with some data to explicitly turn the blue LED on or off (vs toggling):
i2cset -y 0 0x08 0x01 0x01 i # turns blue led on
i2cset -y 0 0x08 0x01 0x00 i # turns blue led off
Notice the addition of the 'i' at the end of the command line because now we are sending an array of bytes vs a single byte. The example also has a data register that can be used to store values or to control something. In the example I am using the first byte of the register to control whether the external LED is blinking or not. Command byte 0x02 is used to write to the register at a specified index:
i2cset -y 0 0x08 0x02 0x00 0x01 i # writes value 0x01 at index 0x00 of the register - external LED blinks
i2cset -y 0 0x08 0x02 0x00 0x00 i # writes 0x00 to the register stopping the external LED blinking
It's possible to request data from the arduino also. This reads the current state of the blue LED:
i2cget -y 0 0x08 # that's it - no other bytes - will return 0x00 or 0x01
To request data from the register you first have to tell the arduino where to read from. First we'll write some data to the register at index 0x07:
i2cset -y 0 0x08 0x02 0x07 0x99 i # write 0x99 to register at index 0x07
And now request the data back but first you have to say from where using command byte 0x03:
i2cset -y 0 0x08 0x03 0x07 i # pre-set index to 0x07 for subsequent request
i2cget -y 0 0x08 # should return 0x99
These sequences can be packaged into scripts also to make life simple. For example, to continuously blink the blue LED, this script could be called i2c-blink:
while true
do
i2cset -y 0 0x08 0x00
sleep 1
done
You can define an alias when you start getting tired of typing (or forgetting) the -y 0 all the time:
alias i2cset='i2cset -y 0'
Then use a simpler:
i2cset 0x08 0x00 # toggles the blue led
So anyway, that's my slightly non-trivial I2C example for the arduino dock 2. Hopefully there are no typos in my sample commands above. Enjoy!