Success!
I've managed to get the Arduino and iPod communicating and can play/pause, skip forward and back, move forward and back through tacks and change the volume (iPod mode 2),
This is the code I'm using, a bit scruffy, sorry!
/*---------------------------------------------------
Controls an iPod through the dock connector's serial interface.
-----------------------------------------------------
Tx (output 1) ---[1k]-------------iPod pin13 Rx
| -----iPod pin21 Accessory
| |
| |
--- ---
2k 1m
--- ---
| |
| |
Gnd-------------------------------iPod pin11 Ground
+5v
|
|
---
2k2
---
|
|
analog inputs 0-4 --------------/switch/--- 0v
-----------------------------------------------------
v0.3 - Added switches code
-----------------------------------------------------
v0.2 - Added DEBUG mode
Added the DEBUG switch to be able to read the output without having an iPod connected.
-----------------------------------------------------
v0.1 - Initial code
iPod mode 2 (simple iPod remote) only.
-----------------------------------------------------
Resources used:
http://www.rosiedaniel.com/search/label/ipod
http://stud3.tuwien.ac.at/~e0026607/ipod_remote/ipod_ap.html
http://instruct1.cit.cornell.edu/courses/ee476/FinalProjects/s2007/awr8_asl45/awr8_asl45/index.html
http://ipodlinux.org/wiki/Apple_Accessory_Protocol
http://pinouts.ru/Devices/ipod_pinout.shtml
-----------------------------------------------------
Mode 2 Commands
Command |Purpose
-----------------------------------------------------
0x00 0x00 |Button Released
0x00 0x01 |Play
0x00 0x02 |Vol+
0x00 0x04 |Vol-
0x00 0x08 |Skip>
0x00 0x10 |Skip<
0x00 0x20 |Next Album
0x00 0x40 |Previous Album
0x00 0x80 |Stop
-----------------------------------------------------
*/
//Debug switch
//boolean DEBUG = true; //Send serial output in HEX with other formatting
boolean DEBUG = false; //Send serial output in BYTE for iPod connection
//Variables for the buttons
int buttonPins[] = {14, 15, 16, 17, 18}; //Array containing the pins the buttons are connected to
int numberOfButtons = 5; //The number of buttons connected
boolean buttonStates[]={false,false,false,false,false}; //Arrays for storing button information in
int buttonPresent[]={HIGH,HIGH,HIGH,HIGH,HIGH}; //Arrays for storing buttons states in
int buttonPrevious[]={HIGH,HIGH,HIGH,HIGH,HIGH}; // "
long time; //To keep track of the time for debouncing
int debounce = 200; //The debounce delay (from the last button push to the next)
//Define commands for iPod mode 2
byte switchMode2[] = {0xFF, 0x55, 0x03, 0x00, 0x01, 0x02, 0xFA};
byte buttonRelease = 0x00;
byte PlayPause2 = 0x01;
byte VolUp2 = 0x02;
byte VolDown2 = 0x04;
byte SkipForward2 = 0x08;
byte SkipBack2 = 0x10;
byte NextAlbum2 = 0x20;
byte PreviousAlbum2 = 0x40;
byte Stop2 = 0x80;
void setup ()
{
//Start the serial connection
beginSerial(19200);
//Setup the buttons
for (int i=0; i<numberOfButtons; i++)
{
pinMode(buttonPins[i], INPUT);
}
//Switch to mode 2 (simple ipod remote mode)
if (DEBUG){Serial.print("Mode 2: ");}
for (int i = 0; i < 7; i++) {
if (DEBUG)
{
Serial.print(switchMode2[i],HEX);
Serial.print(" ");
}else{
Serial.print(switchMode2[i],BYTE);
}
}
if (DEBUG){Serial.println();}
}
void loop ()
{
//Loop through the amount of buttons
for (int button=0; button<numberOfButtons; button++)
{
//Update the present state of the button
buttonPresent[button] = digitalRead(buttonPins[button]);
//If the button state has changed and the debounce duration has passed
//The debounce period will work for all buttons. This means it will stop different buttons being pressed
// within the debounce period but this shouldn't be too much of an issue.
if (buttonPresent[button] != buttonPrevious[button] && millis() - time > debounce)
{
//If the button is pressed...
if (buttonPresent[button] == LOW)
{
//Update the button's state in the array
buttonStates[button] = true;
if (DEBUG){Serial.print("Button: ");Serial.print(button);Serial.print(" Pressed ");}
//Update the time the last button was pressed
time = millis();
//Depending on what buttons been pressed send a command
switch (button)
{
case 0:
sendCommand(VolDown2);
break;
case 1:
sendCommand(VolUp2);
break;
case 2:
sendCommand(SkipBack2);
break;
case 3:
sendCommand(PlayPause2);
break;
case 4:
sendCommand(SkipForward2);
break;
}
//If the button is not pressed...
}else{
//Update the button's state in the array
buttonStates[button] = false;
if (DEBUG){Serial.print("Button: ");Serial.print(button);Serial.print(" Released ");}
//Send the button release command
sendCommand(buttonRelease);
}
//Update the button's previous state in the array
buttonPrevious[button] = buttonPresent[button];
}
}
}
void sendCommand(byte cmd)
{
//Create a checksum for the command
byte cs = checkSum(0x03, 0x02, 0x00, cmd, 0x00);
//Create a bytes to be sent array
byte bytes[] = {0xFF, 0x55, 0x03, 0x02, 0x00, cmd, cs};
if (DEBUG){Serial.print("Command: ");Serial.print(cmd, HEX);Serial.print(" ");}
//Send the bytes
for (int i = 0; i < 7; i++)
{
if (DEBUG)
{
Serial.print(bytes[i], HEX);
Serial.print(" ");
}else{
Serial.print(bytes[i], BYTE);
}
}
if (DEBUG){Serial.println("");}
}
int checkSum(byte len, byte mode, byte command1, byte command2, byte parameter)
{
byte checksum = 0x100 - ((len + mode + command1 + command2 + parameter) & 0xFF);
return checksum;
}
I've made some advances with Advanced iPod Remote mode (mode 4) as well but no luck in getting text returned as yet. There's also no volume control that I can find in mode 4 which would mean I'd need some more circuitry...