From b170c73f922e3457b923b4e7fcbec794a8885c77 Mon Sep 17 00:00:00 2001 From: Ralf Ertzinger Date: Sat, 22 Jun 2013 10:08:23 +0100 Subject: Updated IAP commands. Originally written and uploaded by Lalufu (Ralf Ertzinger) in Feb 2012. They have been condensed into a single patch and some further additions by Andy Potter. Currently includes Authentication V2 support from iPod to Accessory, RF/BlueTooth transmitter support, selecting a playlist and selecting a track from the current playlist. Does not support uploading Album Art or podcasts. Has been tested on the following iPods, 4th Gen Grayscale, 4th Gen Color/Photo, Mini 2nd Gen, Nano 1st Gen and Video 5.5Gen. Change-Id: Ie8fc098361844132f0228ecbe3c48da948726f5e Co-Authored by: Andy Potter Reviewed-on: http://gerrit.rockbox.org/533 Reviewed-by: Frank Gevaerts --- apps/iap.c | 1110 ------------------------------------------------------------ 1 file changed, 1110 deletions(-) delete mode 100644 apps/iap.c (limited to 'apps/iap.c') diff --git a/apps/iap.c b/apps/iap.c deleted file mode 100644 index 6fe0a03281..0000000000 --- a/apps/iap.c +++ /dev/null @@ -1,1110 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2002 by Alan Korr & Nick Robinson - * - * All files in this archive are subject to the GNU General Public License. - * See the file COPYING in the source tree root for full license agreement. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include -#include -#include -#include - -#include "panic.h" -#include "iap.h" -#include "button.h" -#include "config.h" -#include "cpu.h" -#include "system.h" -#include "kernel.h" -#include "serial.h" -#include "appevents.h" - -#include "playlist.h" -#include "playback.h" -#include "audio.h" -#include "settings.h" -#include "metadata.h" -#include "wps.h" -#include "sound.h" -#include "action.h" -#include "powermgmt.h" - -#include "tuner.h" -#include "ipod_remote_tuner.h" - -#include "filetree.h" -#include "dir.h" - -static volatile int iap_pollspeed = 0; -static volatile bool iap_remotetick = true; -static bool iap_setupflag = false, iap_updateflag = false; -static int iap_changedctr = 0; - -static unsigned long iap_remotebtn = 0; -static int iap_repeatbtn = 0; -static bool iap_btnrepeat = false, iap_btnshuffle = false; - -static unsigned char serbuf[RX_BUFLEN]; - -static unsigned char response[TX_BUFLEN]; - -static char cur_dbrecord[5] = {0}; - -/* states of the iap de-framing state machine */ -enum fsm_state { - ST_SYNC, /* wait for 0xFF sync byte */ - ST_SOF, /* wait for 0x55 start-of-frame byte */ - ST_LEN, /* receive length byte (small packet) */ - ST_LENH, /* receive length high byte (large packet) */ - ST_LENL, /* receive length low byte (large packet) */ - ST_DATA, /* receive data */ - ST_CHECK /* verify checksum */ -}; - -static struct state_t { - enum fsm_state state; /* current fsm state */ - unsigned int len; /* payload data length */ - unsigned char *payload; /* payload data pointer */ - unsigned int check; /* running checksum over [len,payload,check] */ - unsigned int count; /* playload bytes counter */ -} frame_state = { - .state = ST_SYNC -}; - -static void put_u32(unsigned char *buf, uint32_t data) -{ - buf[0] = (data >> 24) & 0xFF; - buf[1] = (data >> 16) & 0xFF; - buf[2] = (data >> 8) & 0xFF; - buf[3] = (data >> 0) & 0xFF; -} - -static uint32_t get_u32(const unsigned char *buf) -{ - return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; -} - -static void iap_task(void) -{ - static int count = 0; - - count += iap_pollspeed; - if (count < (500/10)) return; - - /* exec every 500ms if pollspeed == 1 */ - count = 0; - queue_post(&button_queue, SYS_IAP_PERIODIC, 0); -} - -/* called by playback when the next track starts */ -static void iap_track_changed(void *ignored) -{ - (void)ignored; - iap_changedctr = 1; -} - -void iap_setup(int ratenum) -{ - iap_bitrate_set(ratenum); - iap_pollspeed = 0; - iap_remotetick = true; - iap_updateflag = false; - iap_changedctr = 0; - iap_setupflag = true; - iap_remotebtn = BUTTON_NONE; - tick_add_task(iap_task); - add_event(PLAYBACK_EVENT_TRACK_CHANGE, false, iap_track_changed); -} - -void iap_bitrate_set(int ratenum) -{ - switch(ratenum) - { - case 0: - serial_bitrate(0); - break; - case 1: - serial_bitrate(9600); - break; - case 2: - serial_bitrate(19200); - break; - case 3: - serial_bitrate(38400); - break; - case 4: - serial_bitrate(57600); - break; - } -} - -/* Message format: - 0xff - 0x55 - length - mode - command (2 bytes) - parameters (0-n bytes) - checksum (length+mode+parameters+checksum == 0) -*/ - -void iap_send_pkt(const unsigned char * data, int len) -{ - int i, chksum, responselen; - - if(len > TX_BUFLEN-4) len = TX_BUFLEN-4; - responselen = len + 4; - - response[0] = 0xFF; - response[1] = 0x55; - - chksum = response[2] = len; - for(i = 0; i < len; i ++) - { - chksum += data[i]; - response[i+3] = data[i]; - } - - response[i+3] = 0x100 - (chksum & 0xFF); - - for(i = 0; i < responselen; i ++) - { - while (!tx_rdy()) ; - tx_writec(response[i]); - } -} - -bool iap_getc(unsigned char x) -{ - struct state_t *s = &frame_state; - - /* run state machine to detect and extract a valid frame */ - switch (s->state) { - case ST_SYNC: - if (x == 0xFF) { - s->state = ST_SOF; - } - break; - case ST_SOF: - if (x == 0x55) { - /* received a valid sync/SOF pair */ - s->state = ST_LEN; - } else { - s->state = ST_SYNC; - return iap_getc(x); - } - break; - case ST_LEN: - s->check = x; - s->count = 0; - s->payload = serbuf; - if (x == 0) { - /* large packet */ - s->state = ST_LENH; - } else { - /* small packet */ - s->len = x; - s->state = ST_DATA; - } - break; - case ST_LENH: - s->check += x; - s->len = x << 8; - s->state = ST_LENL; - break; - case ST_LENL: - s->check += x; - s->len += x; - if ((s->len == 0) || (s->len > RX_BUFLEN)) { - /* invalid length */ - s->state = ST_SYNC; - return iap_getc(x); - } else { - s->state = ST_DATA; - } - break; - case ST_DATA: - s->check += x; - s->payload[s->count++] = x; - if (s->count == s->len) { - s->state = ST_CHECK; - } - break; - case ST_CHECK: - s->check += x; - if ((s->check & 0xFF) == 0) { - /* done, received a valid frame */ - queue_post(&button_queue, SYS_IAP_HANDLEPKT, 0); - } - s->state = ST_SYNC; - break; - default: - panicf("Unhandled iap state %d", (int) s->state); - break; - } - - /* return true while still hunting for the sync and start-of-frame byte */ - return (s->state == ST_SYNC) || (s->state == ST_SOF); -} - -void iap_periodic(void) -{ - if(!iap_setupflag) return; - if(!iap_pollspeed) return; - - /* PlayStatusChangeNotification */ - unsigned char data[] = {0x04, 0x00, 0x27, 0x04, 0x00, 0x00, 0x00, 0x00}; - unsigned long time_elapsed = audio_current_track()->elapsed; - - time_elapsed += wps_get_ff_rewind_count(); - - data[3] = 0x04; /* playing */ - - /* If info has changed, don't flag it right away */ - if(iap_changedctr && iap_changedctr++ >= iap_pollspeed * 2) - { - /* track info has changed */ - iap_changedctr = 0; - data[3] = 0x01; /* 0x02 has same effect? */ - iap_updateflag = true; - } - - put_u32(&data[4], time_elapsed); - iap_send_pkt(data, sizeof(data)); -} - -static void iap_set_remote_volume(void) -{ - unsigned char data[] = {0x03, 0x0D, 0x04, 0x00, 0x00}; - data[4] = (char)((global_settings.volume+58) * 4); - iap_send_pkt(data, sizeof(data)); -} - -static void cmd_ok_mode0(unsigned char cmd) -{ - unsigned char data[] = {0x00, 0x02, 0x00, 0x00}; - data[3] = cmd; /* respond with cmd */ - iap_send_pkt(data, sizeof(data)); -} - -static void iap_handlepkt_mode0(unsigned int len, const unsigned char *buf) -{ - (void)len; /* len currently unused */ - - unsigned int cmd = buf[1]; - switch (cmd) { - /* Identify */ - case 0x01: - { - /* FM transmitter sends this: */ - /* FF 55 06 00 01 05 00 02 01 F1 (mode switch) */ - if(buf[2] == 0x05) - { - sleep(HZ/3); - /* RF Transmitter: Begin transmission */ - unsigned char data[] = {0x05, 0x02}; - iap_send_pkt(data, sizeof(data)); - } - /* FM remote sends this: */ - /* FF 55 03 00 01 02 FA (1st thing sent) */ - else if (buf[2] == 0x02) - { - /* useful only for apple firmware */ - } - break; - } - - /* EnterRemoteUIMode, FM transmitter sends FF 55 02 00 05 F9 */ - case 0x05: - { - /* ACK Pending (3000 ms) */ - unsigned char data[] = {0x00, 0x02, 0x06, - 0x05, 0x00, 0x00, 0x0B, 0xB8}; - iap_send_pkt(data, sizeof(data)); - cmd_ok_mode0(cmd); - break; - } - - /* ExitRemoteUIMode */ - case 0x06: - { - audio_stop(); - cmd_ok_mode0(cmd); - break; - } - - /* RequestiPodSoftwareVersion, Ipod FM remote sends FF 55 02 00 09 F5 */ - case 0x09: - { - /* ReturniPodSoftwareVersion, ipod5G firmware version */ - unsigned char data[] = {0x00, 0x0A, 0x01, 0x02, 0x01}; - iap_send_pkt(data, sizeof(data)); - break; - } - - /* RequestiPodModelNum */ - case 0x0D: - { - /* ipod is supposed to work only with 5G and nano 2G */ - /*{0x00, 0x0E, 0x00, 0x0B, 0x00, 0x05, 0x50, 0x41, 0x31, 0x34, - 0x37, 0x4C, 0x4C, 0x00}; PA147LL (IPOD 5G 60 GO) */ - /* ReturniPodModelNum */ - unsigned char data[] = {0x00, 0x0E, 0x00, 0x0B, 0x00, 0x10, - 'R', 'O', 'C', 'K', 'B', 'O', 'X', 0x00}; - iap_send_pkt(data, sizeof(data)); - break; - } - - /* RequestLingoProtocolVersion */ - case 0x0F: - { - /* ReturnLingoProtocolVersion */ - unsigned char data[] = {0x00, 0x10, 0x00, 0x01, 0x05}; - data[2] = buf[2]; - iap_send_pkt(data, sizeof(data)); - break; - } - - /* IdentifyDeviceLingoes */ - case 0x13: - { - cmd_ok_mode0(cmd); - - uint32_t lingoes = get_u32(&buf[2]); - - if (lingoes == 0x35) - /* FM transmitter sends this: */ - /* FF 55 0E 00 13 00 00 00 35 00 00 00 04 00 00 00 00 A6 (??)*/ - { - /* GetAccessoryInfo */ - unsigned char data2[] = {0x00, 0x27, 0x00}; - iap_send_pkt(data2, sizeof(data2)); - /* RF Transmitter: Begin transmission */ - unsigned char data3[] = {0x05, 0x02}; - iap_send_pkt(data3, sizeof(data3)); - } - else - { - /* ipod fm remote sends this: */ - /* FF 55 0E 00 13 00 00 00 8D 00 00 00 0E 00 00 00 03 41 */ - if (lingoes & (1 << 7)) /* bit 7 = RF tuner lingo */ - radio_present = 1; - /* GetDevAuthenticationInfo */ - unsigned char data4[] = {0x00, 0x14}; - iap_send_pkt(data4, sizeof(data4)); - } - break; - } - - /* RetDevAuthenticationInfo */ - case 0x15: - { - /* AckDevAuthenticationInfo */ - unsigned char data0[] = {0x00, 0x16, 0x00}; - iap_send_pkt(data0, sizeof(data0)); - /* GetAccessoryInfo */ - unsigned char data1[] = {0x00, 0x27, 0x00}; - iap_send_pkt(data1, sizeof(data1)); - /* AckDevAuthenticationStatus, mandatory to enable some hardware */ - unsigned char data2[] = {0x00, 0x19, 0x00}; - iap_send_pkt(data2, sizeof(data2)); - if (radio_present == 1) - { - /* GetTunerCaps */ - unsigned char data3[] = {0x07, 0x01}; - iap_send_pkt(data3, sizeof(data3)); - } - iap_set_remote_volume(); - break; - } - - /* RetDevAuthenticationSignature */ - case 0x18: - { - /* Isn't used since we don't send the 0x00 0x17 command */ - break; - } - - /* GetIpodOptions */ - case 0x24: - { - /* RetIpodOptions (ipod video send this) */ - unsigned char data[] = {0x00, 0x25, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01}; - iap_send_pkt(data, sizeof(data)); - break; - } - - /* default response is with cmd ok packet */ - default: - { - cmd_ok_mode0(cmd); - break; - } - } -} - -static void iap_handlepkt_mode2(unsigned int len, const unsigned char *buf) -{ - if(buf[1] != 0) return; - iap_remotebtn = BUTTON_NONE; - iap_remotetick = false; - - if(len >= 3 && buf[2] != 0) - { - if(buf[2] & 1) - iap_remotebtn |= BUTTON_RC_PLAY; - if(buf[2] & 2) - iap_remotebtn |= BUTTON_RC_VOL_UP; - if(buf[2] & 4) - iap_remotebtn |= BUTTON_RC_VOL_DOWN; - if(buf[2] & 8) - iap_remotebtn |= BUTTON_RC_RIGHT; - if(buf[2] & 16) - iap_remotebtn |= BUTTON_RC_LEFT; - } - else if(len >= 4 && buf[3] != 0) - { - if(buf[3] & 1) /* play */ - { - if (audio_status() != AUDIO_STATUS_PLAY) - { - iap_remotebtn |= BUTTON_RC_PLAY; - iap_repeatbtn = 2; - iap_remotetick = false; - iap_changedctr = 1; - } - } - if(buf[3] & 2) /* pause */ - { - if (audio_status() == AUDIO_STATUS_PLAY) - { - iap_remotebtn |= BUTTON_RC_PLAY; - iap_repeatbtn = 2; - iap_remotetick = false; - iap_changedctr = 1; - } - } - if((buf[3] & 128) && !iap_btnshuffle) /* shuffle */ - { - iap_btnshuffle = true; - if(!global_settings.playlist_shuffle) - { - global_settings.playlist_shuffle = 1; - settings_save(); - if (audio_status() & AUDIO_STATUS_PLAY) - playlist_randomise(NULL, current_tick, true); - } - else if(global_settings.playlist_shuffle) - { - global_settings.playlist_shuffle = 0; - settings_save(); - if (audio_status() & AUDIO_STATUS_PLAY) - playlist_sort(NULL, true); - } - } - else - iap_btnshuffle = false; - } - else if(len >= 5 && buf[4] != 0) - { - if((buf[4] & 1) && !iap_btnrepeat) /* repeat */ - { - int oldmode = global_settings.repeat_mode; - iap_btnrepeat = true; - - if (oldmode == REPEAT_ONE) - global_settings.repeat_mode = REPEAT_OFF; - else if (oldmode == REPEAT_ALL) - global_settings.repeat_mode = REPEAT_ONE; - else if (oldmode == REPEAT_OFF) - global_settings.repeat_mode = REPEAT_ALL; - - settings_save(); - if (audio_status() & AUDIO_STATUS_PLAY) - audio_flush_and_reload_tracks(); - } - else - iap_btnrepeat = false; - - if(buf[4] & 16) /* ffwd */ - { - iap_remotebtn |= BUTTON_RC_RIGHT; - } - if(buf[4] & 32) /* frwd */ - { - iap_remotebtn |= BUTTON_RC_LEFT; - } - } -} - -static void iap_handlepkt_mode3(unsigned int len, const unsigned char *buf) -{ - (void)len; /* len currently unused */ - - unsigned int cmd = buf[1]; - switch (cmd) - { - /* GetCurrentEQProfileIndex */ - case 0x01: - { - /* RetCurrentEQProfileIndex */ - unsigned char data[] = {0x03, 0x02, 0x00, 0x00, 0x00, 0x00}; - iap_send_pkt(data, sizeof(data)); - break; - } - - /* SetRemoteEventNotification */ - case 0x08: - { - /* ACK */ - unsigned char data[] = {0x03, 0x00, 0x00, 0x08}; - iap_send_pkt(data, sizeof(data)); - break; - } - - /* GetiPodStateInfo */ - case 0x0C: - { - /* request ipod volume */ - if (buf[2] == 0x04) - { - iap_set_remote_volume(); - } - break; - } - - /* SetiPodStateInfo */ - case 0x0E: - { - if (buf[2] == 0x04) - global_settings.volume = (-58)+((int)buf[4]+1)/4; - sound_set_volume(global_settings.volume); /* indent BUG? */ - break; - } - } -} - -static void cmd_ok_mode4(unsigned int cmd) -{ - unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x00}; - data[4] = (cmd >> 8) & 0xFF; - data[5] = (cmd >> 0) & 0xFF; - iap_send_pkt(data, sizeof(data)); -} - -static void get_playlist_name(unsigned char *dest, - unsigned long item_offset, - size_t max_length) -{ - if (item_offset == 0) return; - DIR* dp; - struct dirent* playlist_file = NULL; - - dp = opendir(global_settings.playlist_catalog_dir); - - char *extension; - unsigned long nbr = 0; - while ((nbr < item_offset) && ((playlist_file = readdir(dp)) != NULL)) - { - /*Increment only if there is a playlist extension*/ - if ((extension=strrchr(playlist_file->d_name, '.')) != NULL){ - if ((strcmp(extension, ".m3u") == 0 || - strcmp(extension, ".m3u8") == 0)) - nbr++; - } - } - if (playlist_file != NULL) { - strlcpy(dest, playlist_file->d_name, max_length); - } - closedir(dp); -} - -static void iap_handlepkt_mode4(unsigned int len, const unsigned char *buf) -{ - (void)len; /* len currently unused */ - - unsigned int cmd = (buf[1] << 8) | buf[2]; - switch (cmd) - { - /* GetAudioBookSpeed */ - case 0x0009: - { - /* ReturnAudioBookSpeed */ - unsigned char data[] = {0x04, 0x00, 0x0A, 0x00}; - data[3] = iap_updateflag ? 0 : 1; - iap_send_pkt(data, sizeof(data)); - break; - } - - /* SetAudioBookSpeed */ - case 0x000B: - { - iap_updateflag = buf[3] ? 0 : 1; - /* respond with cmd ok packet */ - cmd_ok_mode4(cmd); - break; - } - - /* RequestProtocolVersion */ - case 0x0012: - { - /* ReturnProtocolVersion */ - unsigned char data[] = {0x04, 0x00, 0x13, 0x01, 0x0B}; - iap_send_pkt(data, sizeof(data)); - break; - } - - /* SelectDBRecord */ - case 0x0017: - { - memcpy(cur_dbrecord, buf + 3, 5); - cmd_ok_mode4(cmd); - break; - } - - /* GetNumberCategorizedDBRecords */ - case 0x0018: - { - /* ReturnNumberCategorizedDBRecords */ - unsigned char data[] = {0x04, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00}; - unsigned long num = 0; - - DIR* dp; - unsigned long nbr_total_playlists = 0; - struct dirent* playlist_file = NULL; - char *extension; - - switch(buf[3]) /* type number */ - { - case 0x01: /* total number of playlists */ - dp = opendir(global_settings.playlist_catalog_dir); - while ((playlist_file = readdir(dp)) != NULL) - { - /*Increment only if there is a playlist extension*/ - if ((extension=strrchr(playlist_file->d_name, '.')) - != NULL) { - if ((strcmp(extension, ".m3u") == 0 || - strcmp(extension, ".m3u8") == 0)) - nbr_total_playlists++; - } - } - closedir(dp); - /*Add 1 for the main playlist*/ - num = nbr_total_playlists + 1; - break; - case 0x05: /* total number of songs */ - num = 1; - break; - } - put_u32(&data[3], num); - iap_send_pkt(data, sizeof(data)); - break; - } - - /* RetrieveCategorizedDatabaseRecords */ - case 0x001A: - { - /* ReturnCategorizedDatabaseRecord */ - unsigned char data[7 + MAX_PATH] = - {0x04, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, - 'R', 'O', 'C', 'K', 'B', 'O', 'X', '\0'}; - - unsigned long item_offset = get_u32(&buf[4]); - - get_playlist_name(data + 7, item_offset, MAX_PATH); - /*Remove file extension*/ - char *dot=NULL; - dot = (strrchr(data+7, '.')); - if (dot != NULL) - *dot = '\0'; - iap_send_pkt(data, 7 + strlen(data+7) + 1); - break; - } - - /* GetPlayStatus */ - case 0x001C: - { - /* ReturnPlayStatus */ - unsigned char data[] = {0x04, 0x00, 0x1D, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - struct mp3entry *id3 = audio_current_track(); - unsigned long time_total = id3->length; - unsigned long time_elapsed = id3->elapsed; - int status = audio_status(); - put_u32(&data[3], time_total); - put_u32(&data[7], time_elapsed); - if (status == AUDIO_STATUS_PLAY) - data[11] = 0x01; /* play */ - else if (status & AUDIO_STATUS_PAUSE) - data[11] = 0x02; /* pause */ - iap_send_pkt(data, sizeof(data)); - break; - } - - /* GetCurrentPlayingTrackIndex */ - case 0x001E: - { - /* ReturnCurrentPlayingTrackIndex */ - unsigned char data[] = {0x04, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00}; - long playlist_pos = playlist_next(0); - playlist_pos -= playlist_get_first_index(NULL); - if(playlist_pos < 0) - playlist_pos += playlist_amount(); - put_u32(&data[3], playlist_pos); - iap_send_pkt(data, sizeof(data)); - break; - } - - /* GetIndexedPlayingTrackTitle */ - case 0x0020: - /* GetIndexedPlayingTrackArtistName */ - case 0x0022: - /* GetIndexedPlayingTrackAlbumName */ - case 0x0024: - { - unsigned char data[70] = {0x04, 0x00, 0xFF}; - struct mp3entry id3; - int fd; - size_t len; - long tracknum = get_u32(&buf[3]); - - data[2] = cmd + 1; - memcpy(&id3, audio_current_track(), sizeof(id3)); - tracknum += playlist_get_first_index(NULL); - if(tracknum >= playlist_amount()) - tracknum -= playlist_amount(); - - /* If the tracknumber is not the current one, - read id3 from disk */ - if(playlist_next(0) != tracknum) - { - struct playlist_track_info info; - playlist_get_track_info(NULL, tracknum, &info); - fd = open(info.filename, O_RDONLY); - memset(&id3, 0, sizeof(struct mp3entry)); - get_metadata(&id3, fd, info.filename); - close(fd); - } - - /* Return the requested track data */ - switch(cmd) - { - case 0x20: - len = strlcpy((char *)&data[3], id3.title, 64); - iap_send_pkt(data, 4+len); - break; - case 0x22: - len = strlcpy((char *)&data[3], id3.artist, 64); - iap_send_pkt(data, 4+len); - break; - case 0x24: - len = strlcpy((char *)&data[3], id3.album, 64); - iap_send_pkt(data, 4+len); - break; - } - break; - } - - /* SetPlayStatusChangeNotification */ - case 0x0026: - { - iap_pollspeed = buf[3] ? 1 : 0; - /* respond with cmd ok packet */ - cmd_ok_mode4(cmd); - break; - } - - /* PlayCurrentSelection */ - case 0x0028: - { - switch (cur_dbrecord[0]) - { - case 0x01: - {/*Playlist*/ - unsigned long item_offset = get_u32(&cur_dbrecord[1]); - - unsigned char selected_playlist - [sizeof(global_settings.playlist_catalog_dir) - + 1 - + MAX_PATH] = {0}; - - strcpy(selected_playlist, - global_settings.playlist_catalog_dir); - int len = strlen(selected_playlist); - selected_playlist[len] = '/'; - get_playlist_name (selected_playlist + len + 1, - item_offset, - MAX_PATH); - ft_play_playlist(selected_playlist, - global_settings.playlist_catalog_dir, - strrchr(selected_playlist, '/') + 1); - break; - } - } - cmd_ok_mode4(cmd); - break; - } - - /* PlayControl */ - case 0x0029: - { - switch(buf[3]) - { - case 0x01: /* play/pause */ - iap_remotebtn = BUTTON_RC_PLAY; - iap_repeatbtn = 2; - iap_remotetick = false; - iap_changedctr = 1; - break; - case 0x02: /* stop */ - iap_remotebtn = BUTTON_RC_PLAY|BUTTON_REPEAT; - iap_repeatbtn = 2; - iap_remotetick = false; - iap_changedctr = 1; - break; - case 0x03: /* skip++ */ - iap_remotebtn = BUTTON_RC_RIGHT; - iap_repeatbtn = 2; - iap_remotetick = false; - break; - case 0x04: /* skip-- */ - iap_remotebtn = BUTTON_RC_LEFT; - iap_repeatbtn = 2; - iap_remotetick = false; - break; - case 0x05: /* ffwd */ - iap_remotebtn = BUTTON_RC_RIGHT; - iap_remotetick = false; - if(iap_pollspeed) iap_pollspeed = 5; - break; - case 0x06: /* frwd */ - iap_remotebtn = BUTTON_RC_LEFT; - iap_remotetick = false; - if(iap_pollspeed) iap_pollspeed = 5; - break; - case 0x07: /* end ffwd/frwd */ - iap_remotebtn = BUTTON_NONE; - iap_remotetick = false; - if(iap_pollspeed) iap_pollspeed = 1; - break; - } - /* respond with cmd ok packet */ - cmd_ok_mode4(cmd); - break; - } - - /* GetShuffle */ - case 0x002C: - { - /* ReturnShuffle */ - unsigned char data[] = {0x04, 0x00, 0x2D, 0x00}; - data[3] = global_settings.playlist_shuffle ? 1 : 0; - iap_send_pkt(data, sizeof(data)); - break; - } - - /* SetShuffle */ - case 0x002E: - { - if(buf[3] && !global_settings.playlist_shuffle) - { - global_settings.playlist_shuffle = 1; - settings_save(); - if (audio_status() & AUDIO_STATUS_PLAY) - playlist_randomise(NULL, current_tick, true); - } - else if(!buf[3] && global_settings.playlist_shuffle) - { - global_settings.playlist_shuffle = 0; - settings_save(); - if (audio_status() & AUDIO_STATUS_PLAY) - playlist_sort(NULL, true); - } - - /* respond with cmd ok packet */ - cmd_ok_mode4(cmd); - break; - } - - /* GetRepeat */ - case 0x002F: - { - /* ReturnRepeat */ - unsigned char data[] = {0x04, 0x00, 0x30, 0x00}; - if(global_settings.repeat_mode == REPEAT_OFF) - data[3] = 0; - else if(global_settings.repeat_mode == REPEAT_ONE) - data[3] = 1; - else - data[3] = 2; - iap_send_pkt(data, sizeof(data)); - break; - } - - /* SetRepeat */ - case 0x0031: - { - int oldmode = global_settings.repeat_mode; - if (buf[3] == 0) - global_settings.repeat_mode = REPEAT_OFF; - else if (buf[3] == 1) - global_settings.repeat_mode = REPEAT_ONE; - else if (buf[3] == 2) - global_settings.repeat_mode = REPEAT_ALL; - - if (oldmode != global_settings.repeat_mode) - { - settings_save(); - if (audio_status() & AUDIO_STATUS_PLAY) - audio_flush_and_reload_tracks(); - } - - /* respond with cmd ok packet */ - cmd_ok_mode4(cmd); - break; - } - - /* GetMonoDisplayImageLimits */ - case 0x0033: - { - /* ReturnMonoDisplayImageLimits */ - unsigned char data[] = {0x04, 0x00, 0x34, - LCD_WIDTH >> 8, LCD_WIDTH & 0xff, - LCD_HEIGHT >> 8, LCD_HEIGHT & 0xff, - 0x01}; - iap_send_pkt(data, sizeof(data)); - break; - } - - /* GetNumPlayingTracks */ - case 0x0035: - { - /* ReturnNumPlayingTracks */ - unsigned char data[] = {0x04, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00}; - unsigned long playlist_amt = playlist_amount(); - put_u32(&data[3], playlist_amt); - iap_send_pkt(data, sizeof(data)); - break; - } - - /* SetCurrentPlayingTrack */ - case 0x0037: - { - int paused = (is_wps_fading() || (audio_status() & AUDIO_STATUS_PAUSE)); - long tracknum = get_u32(&buf[3]); - - audio_pause(); - audio_skip(tracknum - playlist_next(0)); - if (!paused) - audio_resume(); - - /* respond with cmd ok packet */ - cmd_ok_mode4(cmd); - break; - } - - default: - { - /* default response is with cmd ok packet */ - cmd_ok_mode4(cmd); - break; - } - } -} - -static void iap_handlepkt_mode7(unsigned int len, const unsigned char *buf) -{ - unsigned int cmd = buf[1]; - switch (cmd) - { - /* RetTunerCaps */ - case 0x02: - { - /* do nothing */ - - /* GetAccessoryInfo */ - unsigned char data[] = {0x00, 0x27, 0x00}; - iap_send_pkt(data, sizeof(data)); - break; - } - - /* RetTunerFreq */ - case 0x0A: - /* fall through */ - /* TunerSeekDone */ - case 0x13: - { - rmt_tuner_freq(len, buf); - break; - } - - /* RdsReadyNotify, RDS station name 0x21 1E 00 + ASCII text*/ - case 0x21: - { - rmt_tuner_rds_data(len, buf); - break; - } - } -} - -void iap_handlepkt(void) -{ - struct state_t *s = &frame_state; - - if(!iap_setupflag) return; - - /* if we are waiting for a remote button to go out, - delay the handling of the new packet */ - if(!iap_remotetick) - { - queue_post(&button_queue, SYS_IAP_HANDLEPKT, 0); - return; - } - - /* handle command by mode */ - unsigned char mode = s->payload[0]; - switch (mode) { - case 0: iap_handlepkt_mode0(s->len, s->payload); break; - case 2: iap_handlepkt_mode2(s->len, s->payload); break; - case 3: iap_handlepkt_mode3(s->len, s->payload); break; - case 4: iap_handlepkt_mode4(s->len, s->payload); break; - case 7: iap_handlepkt_mode7(s->len, s->payload); break; - } -} - -int remote_control_rx(void) -{ - int btn = iap_remotebtn; - if(iap_repeatbtn) - { - iap_repeatbtn--; - if(!iap_repeatbtn) - { - iap_remotebtn = BUTTON_NONE; - iap_remotetick = true; - } - } - else - iap_remotetick = true; - - return btn; -} - -const unsigned char *iap_get_serbuf(void) -{ - return serbuf; -} - -- cgit v1.2.3