The iPod controller that I submitted for the mbed challenge
Dependencies: mbed Motordriver PID
ipodcontrol.cpp
- Committer:
- networker
- Date:
- 2011-05-04
- Revision:
- 0:371773dd3dd1
File content as of revision 0:371773dd3dd1:
#include "mbed.h" #include "ipodcontrol.h" char* strdup(const char *s) { char *r = new char[strlen(s)+1]; strcpy(r, s); return r; } /* There are 6 different paths through the ipod menu structure, they all start at the toplevel and end at the song level. The longest path has 5 levels and each type has a variable number of entries, except the toplevel which has always 6 entries (paths). When going down the hierarchy, each type starts at entry 0 (the top of the item list). When going up the hierarchy, each type starts at the entry it was at when going down, this is remembered in array 'last'. */ //enum types { top, playlist, artist, album, genre, song, composer, podcast}; const char *ipodControl::toplevel[] = {"Playlist","Artist","Album","Genre","Song","Composer"};//do not change order! const types ipodControl::paths[][maxdepth] = { {top,playlist,song}, {top,artist,album,song}, {top,album,song}, {top,genre,artist,album,song},//path with the maximum depth {top,song}, {top,composer,album,song} }; ipodControl::ipodControl(ipod& p): pod(p) { mode = nav; path = 0; level = 0; items = sizeof(toplevel)/sizeof(char*); current = 0; OnGetNames = 0; OnTrackChange = 0; OnTime = 0; OnTitle = 0; OnAlbum = 0; OnArtist = 0; OnStatus = 0; OnError = 0; wrap = false; pod.SetMode(4); } bool ipodControl::readName() { name = 0; pod.SendAirCmd(get_ipod_name); if (pod.waitForReply()) pod.release(); if (pod.getError()) { if (OnError) OnError(pod.getError(), get_ipod_name); return false; } return true; } //the menu structure currently has no <All> items void ipodControl::OK(unsigned item) {//when the user presses 'OK' (rotary encoder), we move down the menu hierarchy until we reach the 'song' level, we then switch to playback mode if (mode == nav) { if (paths[path][level] != song) { //present level is not yet 'song' last[level] = item; //push the current position if (level>0) //not at the toplevel pod.SendAirCmd(select, paths[path][level], item); //'select' the current item level++; current = 0; //start at beginning (no forward history) pod.SendAirCmd(get_count, paths[path][level]); //get the number of subitems pod.waitForReply(); items = pod.Arg1(); pod.release(); if (items>0) pod.SendAirCmd(get_names, paths[path][level],0U,1U); //display the first subitem printf("new level: %s\n", toplevel[paths[path][level]-1]); //diag. display the new level category } else { //pressed OK at song level mode = playback; pod.SendAirCmd(select, paths[path][level], item); //'select' the current item pod.SendAirCmd(play_list, item); //execute the current item, start playing Update(); } } else //mode>=play { //real ipod will cycle through volume, position(elapsed), cover_art and stars } } void ipodControl::Menu() {//when the user presses 'menu' we move up the menu structure, we enter navigation mode but playback(if active) continues if (mode != nav) { mode = nav; return; } if (level > 0) { level--; if (level > 0) { //still not at top level pod.SendAirCmd(get_count, paths[path][level]); //get number of items at new level pod.waitForReply(); items = pod.Arg1(); pod.release(); if (items>0) { pod.SendAirCmd(get_names, paths[path][level],last[level],1U); //display the item at the pushed position, or... current = last[level];//pop the last position } else { current = 0; } printf("new level: %s\n", toplevel[paths[path][level]-1]); //diag. display the new level category } else { //reached toplevel items = sizeof(toplevel)/sizeof(char*); current = path; printf("new level: Music\n"); //diag. display the new level category pod.SendAirCmd(select, 1U); //'select' all (entire iPod) //pod.SendAirCmd(switch_to_main); //switch to main library } } //else was already at top => do nothing } void ipodControl::Right() { if (mode == nav) { Next(); if (paths[path][level] == top) //top level path = current; else //get name of item at new position pod.SendAirCmd(get_names, paths[path][level],current,1U); } else pod.SendAirCmd(command, next);//skip fwd } void ipodControl::Left() { if (mode == nav) { Prev(); if (paths[path][level] == top) { //top level path = current; } else {//get name of item at new position pod.SendAirCmd(get_names, paths[path][level],current,1U); } } else pod.SendAirCmd(command, prev);//skip back } void ipodControl::MoveTo(float pos) { newpos = pos; switch (mode) { case playback: if (pos < elapsed) { //reverse //newpos = pos; mode = fastr; printf("moving back to %f sec\n", 0.001*pos); pod.SendAirCmd(command, frwd);//assume that polling is active and that the command is accepted } else if (pos > elapsed) { //forward //newpos = pos; mode = fastf; printf("moving fwd to %f sec\n", 0.001*pos); pod.SendAirCmd(command, ffwd); } break; case fastf: //newpos = pos; printf("> moving fwd to %f sec\n", 0.001*pos); break; case fastr: //newpos = pos; printf("< moving back to %f sec\n", 0.001*pos); break; case nav: printf("N"); break; } } void ipodControl::poll() {//this is called as part of the main event loop if (pod.ready()) { pod.parse(); switch (pod.cmd()-1) { case get_count: items = pod.Arg1(); break; case get_names: if (OnGetNames) OnGetNames(pod.Arg1(), pod.text()); break; case get_position: current = pod.Arg1(); break; case polling: if (pod.Arg1()==1) {//track change current = pod.Arg2(); mode = playback; if (OnTrackChange) OnTrackChange(current); } else {//elapsed time elapsed = pod.Arg2(); switch (mode) { case playback: if (OnTime) OnTime(elapsed); break; case fastf: printf(" F "); if (elapsed >= newpos) mode = stopfast; break; case fastr: printf(" R "); if (elapsed <= newpos) mode = stopfast; break; case stopfast: printf(" S "); if (elapsed >= newpos) mode = playback; break; } if (mode == stopfast) { printf("reached position %f sec\n", 0.001*elapsed); pod.SendAirCmd(command, stopf); } } break; case get_ipod_name: if (name) delete[] name; name = strdup(pod.text()); break; case get_title: if (OnTitle) OnTitle(pod.text()); break; case get_artist: if (OnArtist) OnArtist(pod.text()); break; case get_album: if (OnAlbum) OnAlbum(pod.text()); break; case get_time_status: //arg1=tracklength in ms, arg2=elapsed time, arg3=status (0=stop, 1=play, 2=pause) tracklength = pod.Arg1(); elapsed = pod.Arg2(); status = pod.Arg3(); if (OnStatus) OnStatus(tracklength, elapsed, pod.Arg3()); break; case 0: //ack/error if (pod.Arg1()>0 && OnError) OnError(pod.Arg1(), pod.Arg2()); break; default: printf("Unknown reply from iPod %04X\n", pod.cmd()); break; } unsigned reply = pod.cmd(); pod.release();//reset ready flag and delete the receive buffer, meaning that all returned results should be saved or processed updater(reply); } } void ipodControl::updater(unsigned reply) { if (update_state != usIdle) printf("\t\tstate=%d, reply = %02X\n", update_state, reply); switch (update_state) { case usGet_time_status: if (reply==get_time_status+1) { update_state = usGet_title; pod.SendAirCmd(get_title, current); printf("updater: getting title\n"); } else if (reply==polling+1) {//only do this when polling is off pod.SendAirCmd(get_time_status); //reissue the same command and stay in the same state printf("updater: getting status (again)\n"); } break; case usGet_title: if (reply==get_title+1) { update_state = usGet_artist; pod.SendAirCmd(get_artist, current); printf("updater: getting artist\n"); } break; case usGet_artist: if (reply==get_artist+1) { update_state = usIdle; pod.SendAirCmd(polling, 1); printf("updater: going idle\n"); } break; } }