The iPod controller that I submitted for the mbed challenge
Dependencies: mbed Motordriver PID
main.cpp@0:371773dd3dd1, 2011-05-04 (annotated)
- Committer:
- networker
- Date:
- Wed May 04 15:41:13 2011 +0000
- Revision:
- 0:371773dd3dd1
first publication
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
networker | 0:371773dd3dd1 | 1 | #include "mbed.h" |
networker | 0:371773dd3dd1 | 2 | #include "fader.h" |
networker | 0:371773dd3dd1 | 3 | #include "MCP23017.h" |
networker | 0:371773dd3dd1 | 4 | #include "TextLCD23017.h" |
networker | 0:371773dd3dd1 | 5 | #include "keybrd.h" |
networker | 0:371773dd3dd1 | 6 | #include "ipod.h" |
networker | 0:371773dd3dd1 | 7 | #include "ipodcontrol.h" |
networker | 0:371773dd3dd1 | 8 | |
networker | 0:371773dd3dd1 | 9 | fader trackbar(p21,p22,p23,p20); |
networker | 0:371773dd3dd1 | 10 | I2C iic(p28, p27); |
networker | 0:371773dd3dd1 | 11 | MCP23017 ui(iic, 0x40); |
networker | 0:371773dd3dd1 | 12 | TextLCD23017 lcd(ui); |
networker | 0:371773dd3dd1 | 13 | keybrd kb(ui, p12);//second argument is the interrupt pin, although only used by keyboard it logically belongs to the MCP23017 |
networker | 0:371773dd3dd1 | 14 | ipod pod(p9, p10);//serial pins for the ipod |
networker | 0:371773dd3dd1 | 15 | ipodControl cntrl(pod); |
networker | 0:371773dd3dd1 | 16 | |
networker | 0:371773dd3dd1 | 17 | DigitalOut led(LED1);//for debug only |
networker | 0:371773dd3dd1 | 18 | |
networker | 0:371773dd3dd1 | 19 | const float beyondEnd = 2.0; //any number > 1.0 |
networker | 0:371773dd3dd1 | 20 | float inmark=0, outmark=beyondEnd; |
networker | 0:371773dd3dd1 | 21 | |
networker | 0:371773dd3dd1 | 22 | void show(const char* s) { //write to LCD bottom line |
networker | 0:371773dd3dd1 | 23 | lcd.locate(0, 1); |
networker | 0:371773dd3dd1 | 24 | lcd.printf("%-16s", s); |
networker | 0:371773dd3dd1 | 25 | } |
networker | 0:371773dd3dd1 | 26 | |
networker | 0:371773dd3dd1 | 27 | void showtop(const char* s) { //write to LCD top line |
networker | 0:371773dd3dd1 | 28 | lcd.locate(0, 0); |
networker | 0:371773dd3dd1 | 29 | lcd.printf("%-16s", s); |
networker | 0:371773dd3dd1 | 30 | } |
networker | 0:371773dd3dd1 | 31 | |
networker | 0:371773dd3dd1 | 32 | void show(unsigned, const char* s) { |
networker | 0:371773dd3dd1 | 33 | lcd.locate(0, 1); |
networker | 0:371773dd3dd1 | 34 | if (cntrl.getItems()>0) |
networker | 0:371773dd3dd1 | 35 | lcd.printf("%-16s", s); |
networker | 0:371773dd3dd1 | 36 | else |
networker | 0:371773dd3dd1 | 37 | lcd.printf(" <Empty> ");//placeholder |
networker | 0:371773dd3dd1 | 38 | } |
networker | 0:371773dd3dd1 | 39 | |
networker | 0:371773dd3dd1 | 40 | void time(unsigned t) { //OnTime, iPod polling command |
networker | 0:371773dd3dd1 | 41 | float pos = t; |
networker | 0:371773dd3dd1 | 42 | unsigned length = cntrl.getTrackLength(); |
networker | 0:371773dd3dd1 | 43 | if (length == 0) |
networker | 0:371773dd3dd1 | 44 | return;//valid length not available (yet) |
networker | 0:371773dd3dd1 | 45 | pos /= length; |
networker | 0:371773dd3dd1 | 46 | if (pos >= outmark) { |
networker | 0:371773dd3dd1 | 47 | cntrl.MoveTo(inmark * cntrl.getTrackLength()); |
networker | 0:371773dd3dd1 | 48 | trackbar.set(inmark); |
networker | 0:371773dd3dd1 | 49 | } else |
networker | 0:371773dd3dd1 | 50 | trackbar.set(pos);//when fader is 'holding' or 'tracking moveto new position |
networker | 0:371773dd3dd1 | 51 | } |
networker | 0:371773dd3dd1 | 52 | |
networker | 0:371773dd3dd1 | 53 | void changeTrack(unsigned t) { //OnTrackChange, iPod polling command |
networker | 0:371773dd3dd1 | 54 | printf("Track %u\n", t); |
networker | 0:371773dd3dd1 | 55 | //the track changed so we need new artist/song/tracklength |
networker | 0:371773dd3dd1 | 56 | //must not call guarded_SendAirCmd here because the rx_buffer will not be released before reply arrives |
networker | 0:371773dd3dd1 | 57 | //calling a sequence of normal SendAirCmds is also dangerous because they may not be properly queued |
networker | 0:371773dd3dd1 | 58 | cntrl.Update(); //sends the first SendAirCmd and starts the 'updater' state-machine to send the rest |
networker | 0:371773dd3dd1 | 59 | } |
networker | 0:371773dd3dd1 | 60 | |
networker | 0:371773dd3dd1 | 61 | void OnMove(float newpos) { //fader move command, called after manual movement of wiper |
networker | 0:371773dd3dd1 | 62 | cntrl.MoveTo(newpos * cntrl.getTrackLength()); //new wiper position in ms |
networker | 0:371773dd3dd1 | 63 | } |
networker | 0:371773dd3dd1 | 64 | |
networker | 0:371773dd3dd1 | 65 | void errHandler(unsigned e, unsigned cmd) { //ipodcontrol::OnError |
networker | 0:371773dd3dd1 | 66 | if (e==1 && cmd==get_ipod_name) |
networker | 0:371773dd3dd1 | 67 | lcd.printf("iPod connected??"); |
networker | 0:371773dd3dd1 | 68 | } |
networker | 0:371773dd3dd1 | 69 | |
networker | 0:371773dd3dd1 | 70 | void handleKey(char c) { //handles the keys of the user interface |
networker | 0:371773dd3dd1 | 71 | switch (c) { |
networker | 0:371773dd3dd1 | 72 | case 1://OK |
networker | 0:371773dd3dd1 | 73 | if (cntrl.getMode() == nav) |
networker | 0:371773dd3dd1 | 74 | cntrl.OK(); |
networker | 0:371773dd3dd1 | 75 | else { //mode==play |
networker | 0:371773dd3dd1 | 76 | outmark = beyondEnd;//stop repeating marked section |
networker | 0:371773dd3dd1 | 77 | inmark = 0; |
networker | 0:371773dd3dd1 | 78 | } |
networker | 0:371773dd3dd1 | 79 | break; |
networker | 0:371773dd3dd1 | 80 | case 2://>>/out |
networker | 0:371773dd3dd1 | 81 | if (cntrl.getMode()==nav) |
networker | 0:371773dd3dd1 | 82 | cntrl.Fwd(); |
networker | 0:371773dd3dd1 | 83 | else //'out' command |
networker | 0:371773dd3dd1 | 84 | if (cntrl.getPos() > inmark) |
networker | 0:371773dd3dd1 | 85 | outmark = cntrl.getPos(); |
networker | 0:371773dd3dd1 | 86 | break; |
networker | 0:371773dd3dd1 | 87 | case 3://<</in |
networker | 0:371773dd3dd1 | 88 | if (cntrl.getMode()==nav) |
networker | 0:371773dd3dd1 | 89 | cntrl.Rev(); |
networker | 0:371773dd3dd1 | 90 | else //'in' command |
networker | 0:371773dd3dd1 | 91 | if (cntrl.getPos() < outmark) |
networker | 0:371773dd3dd1 | 92 | inmark = cntrl.getPos(); |
networker | 0:371773dd3dd1 | 93 | break; |
networker | 0:371773dd3dd1 | 94 | case 4://>|| |
networker | 0:371773dd3dd1 | 95 | cntrl.PlayPause(); |
networker | 0:371773dd3dd1 | 96 | break; |
networker | 0:371773dd3dd1 | 97 | case 5://menu |
networker | 0:371773dd3dd1 | 98 | cntrl.Menu(); |
networker | 0:371773dd3dd1 | 99 | if (cntrl.getType() == top) |
networker | 0:371773dd3dd1 | 100 | show(""); |
networker | 0:371773dd3dd1 | 101 | break; |
networker | 0:371773dd3dd1 | 102 | case 6://rec |
networker | 0:371773dd3dd1 | 103 | case 7://replay |
networker | 0:371773dd3dd1 | 104 | default: |
networker | 0:371773dd3dd1 | 105 | break; |
networker | 0:371773dd3dd1 | 106 | } |
networker | 0:371773dd3dd1 | 107 | } |
networker | 0:371773dd3dd1 | 108 | |
networker | 0:371773dd3dd1 | 109 | /* On a real iPod, the wheel has multiple functions, depending on the mode: |
networker | 0:371773dd3dd1 | 110 | navigation: moves up and down the current list |
networker | 0:371773dd3dd1 | 111 | play: changes volume (not implemented here and afaik not possible) |
networker | 0:371773dd3dd1 | 112 | but it has submodes |
networker | 0:371773dd3dd1 | 113 | fast: moves quickly through a song (here implemented by fader movement) |
networker | 0:371773dd3dd1 | 114 | stars: rates the song (not implemented) |
networker | 0:371773dd3dd1 | 115 | */ |
networker | 0:371773dd3dd1 | 116 | int main() { |
networker | 0:371773dd3dd1 | 117 | int count = 0; |
networker | 0:371773dd3dd1 | 118 | iic.frequency(400000);//does not work, stays at 100kHz |
networker | 0:371773dd3dd1 | 119 | cntrl.OnGetNames = show; |
networker | 0:371773dd3dd1 | 120 | cntrl.OnTitle = show; |
networker | 0:371773dd3dd1 | 121 | cntrl.OnArtist = showtop; |
networker | 0:371773dd3dd1 | 122 | cntrl.OnAlbum = show; |
networker | 0:371773dd3dd1 | 123 | cntrl.OnTime = time; |
networker | 0:371773dd3dd1 | 124 | cntrl.OnTrackChange = changeTrack; |
networker | 0:371773dd3dd1 | 125 | cntrl.OnError = errHandler; |
networker | 0:371773dd3dd1 | 126 | trackbar.setOnMove(OnMove); |
networker | 0:371773dd3dd1 | 127 | if (!cntrl.readName()) //calls errHandler if no reply |
networker | 0:371773dd3dd1 | 128 | ; |
networker | 0:371773dd3dd1 | 129 | wait(1.0); |
networker | 0:371773dd3dd1 | 130 | cntrl.StartPolling(); |
networker | 0:371773dd3dd1 | 131 | lcd.printf("%-16s", cntrl.getPathStr());//display "Playlist" on topline, bottomline empty |
networker | 0:371773dd3dd1 | 132 | printf("entering main loop\n"); |
networker | 0:371773dd3dd1 | 133 | for (;;) { |
networker | 0:371773dd3dd1 | 134 | count = (count+1)%0x20000; |
networker | 0:371773dd3dd1 | 135 | if (count==0) led = !led;//just to see if the main loop keeps running |
networker | 0:371773dd3dd1 | 136 | |
networker | 0:371773dd3dd1 | 137 | lcd.locate(0, 0);//col, row |
networker | 0:371773dd3dd1 | 138 | |
networker | 0:371773dd3dd1 | 139 | switch (kb.getevent(true)) { |
networker | 0:371773dd3dd1 | 140 | case keybrd::keydown: |
networker | 0:371773dd3dd1 | 141 | printf("Key %01d\n", kb.getc()); |
networker | 0:371773dd3dd1 | 142 | handleKey(kb.getc()); |
networker | 0:371773dd3dd1 | 143 | goto update; |
networker | 0:371773dd3dd1 | 144 | case keybrd::keyup: |
networker | 0:371773dd3dd1 | 145 | break; |
networker | 0:371773dd3dd1 | 146 | case keybrd::posup://rotary encoder turns right |
networker | 0:371773dd3dd1 | 147 | printf("Pos %d\n", kb.getpos()); |
networker | 0:371773dd3dd1 | 148 | cntrl.Right(); |
networker | 0:371773dd3dd1 | 149 | outmark = beyondEnd; //stop repeating |
networker | 0:371773dd3dd1 | 150 | inmark = 0; |
networker | 0:371773dd3dd1 | 151 | goto update; |
networker | 0:371773dd3dd1 | 152 | case keybrd::posdown: |
networker | 0:371773dd3dd1 | 153 | printf("Pos %d\n", kb.getpos()); |
networker | 0:371773dd3dd1 | 154 | cntrl.Left(); |
networker | 0:371773dd3dd1 | 155 | outmark = beyondEnd; //stop repeating |
networker | 0:371773dd3dd1 | 156 | inmark = 0; |
networker | 0:371773dd3dd1 | 157 | update: |
networker | 0:371773dd3dd1 | 158 | if (cntrl.getType() == top) |
networker | 0:371773dd3dd1 | 159 | lcd.printf("%-16s", cntrl.getPathStr());//toplevel name from array |
networker | 0:371773dd3dd1 | 160 | else |
networker | 0:371773dd3dd1 | 161 | lcd.printf("%-16s", cntrl.getTypeStr());//item name from iPod |
networker | 0:371773dd3dd1 | 162 | break; |
networker | 0:371773dd3dd1 | 163 | case keybrd::none: |
networker | 0:371773dd3dd1 | 164 | break; |
networker | 0:371773dd3dd1 | 165 | default: |
networker | 0:371773dd3dd1 | 166 | printf("Unknown keyboard event\n"); |
networker | 0:371773dd3dd1 | 167 | } |
networker | 0:371773dd3dd1 | 168 | cntrl.poll();//handle the ipodcontrol events in the event loop |
networker | 0:371773dd3dd1 | 169 | } |
networker | 0:371773dd3dd1 | 170 | } |