The iPod controller that I submitted for the mbed challenge
Dependencies: mbed Motordriver PID
ipod.cpp
- Committer:
- networker
- Date:
- 2011-05-04
- Revision:
- 0:371773dd3dd1
File content as of revision 0:371773dd3dd1:
#include "mbed.h" #include "ipod.h" ipod::ipod(PinName tx, PinName rx): led(*new DigitalOut(DEBUGPIN)) { com = new Serial(tx, rx); com->baud(19200);//should work upto 57600 rx_ready = false; tx_ready = true; state = 0; tx_buffer[0] = 0xff; tx_buffer[1] = 0x55; com->attach(this, &ipod::handlerx); #ifdef TX_IRQ com->attach(this, &ipod::handletx, Serial::TxIrq); #endif lastcommand = -1; error = err_success; replies = 0; } void ipod::handlerx() {//Serial port interrupt handler led = 1; unsigned short c = com->getc(); // printf("%d: %02X; ", state, chk); switch (state) { case 0: if (c==0xff) state++; break; case 1: if (c==0x55) state++; else state = 0; break; case 2: if (rx_ready) { state = 0; break;//buffer not free, ignore the message } length = c; chk = c; rx_buffer = new char[length]; state++; break; case 3: if (c > 4) { state = 0; break;//mode not known or not supported } mode = c; chk += c; state++; break; case 4: command = c<<8; chk += c; state++; break; case 5: command += c; chk += c; state++; break; default: chk += c; if (state < length+3) { rx_buffer[state-6] = c; state++; } else { if (chk==0) { rx_ready = true; replies--; if (command-1 == lastcommand) {//it is a reply to lastcommand //printf("reply to %02X\n", lastcommand); lastcommand = -1; } //printf("ready %02X\n", command); } else printf("checksum error %02x state=%d\n", chk, state); state = 0; break; } } led = 0; } void ipod::handletx() { if (tx_index < tx_size) com->putc(tx_buffer[tx_index++]); else tx_ready = true; } bool ipod::waitForReply() {//busy waits for a reply to the last issued command, all other replies are ignored for (int i = 0; i < 10000000; i++) { if (ready()) { if (lastcommand == -1) {//indicates that a reply to the last issued command has been received parse();//parse the last reply return true;//return to caller for further processing } release();//release the buffer and hence ignore the message } } printf("timeout: last received %02X(%d, %d, %d, \"%s\")\n", command, arg1, arg2, arg3, string); error = err_timeout; return false; } #define BIGENDIAN void ipod::copy(char *b, union conv p) {//copy an UINT32 argument bytewise to the buffer #ifdef BIGENDIAN for (int i = 0; i < 4; i++) *(b+3-i) = p.asBytes[i]; #else for (int i = 0; i < 4; i++) *(b+i) = p.asBytes[i]; #endif } void ipod::SendAirCmd(unsigned cmd, unsigned arg1, unsigned arg2, unsigned arg3) {//send an advanced ipod remote command, unused arguments are optional union conv par1, par2, par3; par1.asInt = arg1; par2.asInt = arg2; par3.asInt = arg3; tx_buffer[3] = 4; //AiR mode tx_buffer[4] = 0; tx_buffer[5] = cmd & 0xff; unsigned expect = 1; //typically expect 1 reply per request switch (cmd) { case 0x12: //get ipod type tx_buffer[2] = 3; //expect 2 bytes return break; case 0x14: //get iPod name tx_buffer[2] = 3; //expect string return break; case 0x16: //main lib tx_buffer[2] = 3; expect = 0; break; case 0x17: //goto item tx_buffer[6] = arg1; tx_buffer[2] = 8; copy(tx_buffer+7, par2); expect = 0; break; case 0x18: //get count tx_buffer[6] = arg1; tx_buffer[2] = 4; //expect integer return break; case 0x1A: //get names tx_buffer[6] = arg1; tx_buffer[2] = 12; copy(tx_buffer+7, par2); copy(tx_buffer+11, par3); //expect many offset,string pairs expect = arg3; break; case 0x1C: //get time/stat tx_buffer[2] = 3; //expect int,int,byte break; case 0x1E: //get position tx_buffer[2] = 3; //expect int break; case 0x20: //get title tx_buffer[2] = 7; copy(tx_buffer+6, par1); //expect string break; case 0x22: //get artist tx_buffer[2] = 7; copy(tx_buffer+6, par1); //expect string break; case 0x24: //get album tx_buffer[2] = 7; copy(tx_buffer+6, par1); //expect string break; case 0x26: //poll mode tx_buffer[6] = arg1; tx_buffer[2] = 4; //expect many byte,int pairs expect = 0; //the number to expect is unknown here, so either stop polling or just insert command anyway break; case 0x28: //run PL tx_buffer[2] = 7; copy(tx_buffer+6, par1); expect = 0; break; case 0x29: //command tx_buffer[6] = arg1; tx_buffer[2] = 4; expect = 0; break; case 0x2C: //get shuffle tx_buffer[2] = 3; //expect byte break; case 0x2E: //set shuffle tx_buffer[6] = arg1; tx_buffer[2] = 4; expect = 0; break; case 0x2F: //get repeat tx_buffer[2] = 3; //expect byte break; case 0x31: //set repeat tx_buffer[6] = arg1; tx_buffer[2] = 4; expect = 0; break; case 0x35: //get nr in PL tx_buffer[2] = 3; //expect int break; case 0x37: //goto song tx_buffer[2] = 7; copy(tx_buffer+6, par1); expect = 0; break; case 0x38: //select tx_buffer[6] = arg1; tx_buffer[2] = 9; copy(tx_buffer+7, par2); tx_buffer[11] = 0;//unknown break; default: return; } tx_size = tx_buffer[2] + 4; tx_buffer[tx_size-1] = 0; for (int i = 2; i < tx_size-1; i++) tx_buffer[tx_size-1] -= tx_buffer[i];//compute checksum tx_index = 1; replies = expect; #ifdef TX_IRQ while (!tx_ready) /* wait */; tx_ready = false; com->putc(tx_buffer[0]);//kick-off writing buffer #else write(); #endif lastcommand = cmd; printf("%02X (%d, %d, %d)\n", cmd, arg1, arg2, arg3); } void ipod::guarded_SendAirCmd(unsigned cmd, unsigned arg1, unsigned arg2, unsigned arg3) {//same as SendAirCmd but waits until all previous expected replies have been received for (int i = 0; i<1000000; i++) if (replies==0) { SendAirCmd(cmd, arg1, arg2, arg3); return; } printf("Timeout while waiting for reply to %02X, command %02X cannot be send\n", lastcommand, cmd); } void ipod::SetMode(int m) { //char buf[] = {0xff, 0x55, 0x03, 0x00, 0x01, 0x00, 0x00}; tx_buffer[2] = 3; //length tx_buffer[3] = 0; //mode 0, mode switching tx_buffer[4] = 1; //cmd high byte tx_buffer[5] = m; //cmd low byte tx_buffer[6] = 0x100 - 3 - 1 - m;//checksum tx_index = 1; tx_size = 7; #ifdef TX_IRQ while (!tx_ready) /* wait */; tx_ready = false; com->putc(tx_buffer[0]); #else write(); #endif } unsigned ipod::copy(char* s) {//return a bytewise argument from the buffer as a UINT32 union conv p; #ifdef BIGENDIAN for (int i = 0; i < 4; i++) p.asBytes[3-i] = s[i]; #else for (int i = 0; i < 4; i++) p.asBytes[i] = s[i]; #endif return p.asInt; } void ipod::parse() { error = err_success; switch (mode) { case 0: //mode 0 reply if (command & 0xFF == 4) {//reply to mode status request printf("mode 0 reply = %04X\n", command); } else printf( "unexpected mode 0 reply\n"); break; //assume s.c_str()[4] == 0 case 4://reply to AiR command switch (command) { case 0: if (rx_buffer[0]==0x04) { error = err_unknown; printf("command %04X is not understood\n", *(unsigned short*)&rx_buffer[1]); } break; case 1: error = (errors)rx_buffer[0]; switch (error) { case err_success: //printf("command %04X succeeded\n",*(unsigned short*)&rx_buffer[1]); break; case err_failure: printf("command %04X failed\n",*(unsigned short*)&rx_buffer[1]); break; case err_limit: printf("command %04X had wrong parameter(s)\n",*(unsigned short*)&rx_buffer[1]); break; case err_answer: printf("command %04X is an answer\n",*(unsigned short*)&rx_buffer[1]); break; default: printf("unknown error\n"); break; } break; //2 bytes case get_ipod_size+1: //ipod type break; //single string case get_ipod_name+1: case get_title+1: case get_artist+1: case get_album+1: string = rx_buffer; printf("%04X: %s\n", command, string); break; //number+string case get_names+1: string = rx_buffer + 4; arg1 = copy(rx_buffer); printf("%04X: %d %s\n", command, arg1, string); break; //number+number+byte case get_time_status+1: arg1 = copy(rx_buffer); arg2 = copy(rx_buffer+4); arg3 = rx_buffer[8]; printf("%04X: %d %d %02X\n", command, arg1, arg2, arg3); break; //number case get_count+1: case get_position+1: case get_nr_in_playlist+1: arg1 = copy(rx_buffer); printf("%04X: %d\n", command, arg1); break; //byte + number case polling+1: arg1 = rx_buffer[0]; arg2 = copy(rx_buffer+1); break; //byte case get_shuffle+1: case get_repeat+1: arg1 = rx_buffer[0]; printf("%04X: %02X\n", command, arg1); break; //10 bytes case select+1: //select break; default: printf("unsupported reply"); break; } break; default: printf("unsupported mode\n"); break; } }