From 77f8c9c9f12f1a520467868047574fe0af7a1556 Mon Sep 17 00:00:00 2001 From: LiveboxAndy Date: Sat, 4 Aug 2018 18:02:21 +0100 Subject: Update to allow the Apple Radio Remote to function on iPod Video 5G. This was broken when the major update to iap was comitted. ia-lingo7.c created and various iap related files modified. On 4G, 6G and Nano 1/2Gen iPods the remote will function even though the radio won't. Tested on 4G Greyscale, 4G Color, 4G Photo, 4G Mini 1st Gen, 4G Mini 2Gen, Nano 1G, Nano 2G, Video 5G, Video 5.5G Change-Id: Ia74e3d07d9ab5edc6da8eafa96801ede722be331 --- apps/SOURCES | 4 +- apps/iap/iap-core.c | 115 ++++++------ apps/iap/iap-core.h | 19 +- apps/iap/iap-lingo.h | 3 + apps/iap/iap-lingo0.c | 263 ++++++++++++++++++--------- apps/iap/iap-lingo1.c | 1 + apps/iap/iap-lingo2.c | 34 +++- apps/iap/iap-lingo3.c | 75 +++++--- apps/iap/iap-lingo4.c | 11 +- apps/iap/iap-lingo7.c | 491 ++++++++++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 837 insertions(+), 179 deletions(-) create mode 100644 apps/iap/iap-lingo7.c (limited to 'apps') diff --git a/apps/SOURCES b/apps/SOURCES index 99b0832286..107431d464 100644 --- a/apps/SOURCES +++ b/apps/SOURCES @@ -70,8 +70,10 @@ iap/iap-lingo1.c iap/iap-lingo2.c iap/iap-lingo3.c iap/iap-lingo4.c +#if CONFIG_TUNER +iap/iap-lingo7.c +#endif #endif - screen_access.c #ifdef HAVE_BUTTONBAR gui/buttonbar.c diff --git a/apps/iap/iap-core.c b/apps/iap/iap-core.c index f8373bab83..885ba2c188 100644 --- a/apps/iap/iap-core.c +++ b/apps/iap/iap-core.c @@ -45,7 +45,9 @@ #include "usb.h" #include "tuner.h" +#if CONFIG_TUNER #include "ipod_remote_tuner.h" +#endif /* MS_TO_TICKS converts a milisecond time period into the @@ -164,7 +166,13 @@ unsigned char lingo_versions[32][2] = { {1, 5}, /* Display remote lingo, 0x03 */ {1, 12}, /* Extended Interface lingo, 0x04 */ {1, 1}, /* RF/BT Transmitter lingo, 0x05 */ - {} /* All others are unsupported */ + {0, 0}, /* USB Host lingo, 0x06, disabled */ +#if CONFIG_TUNER + {1, 0}, /* RF Receiver lingo, 0x07 */ +#else + {0, 0}, /* RF Receiver lingo, 0x07 disabled */ +#endif + {} /* every other lingo, disabled */ }; /* states of the iap de-framing state machine */ @@ -308,6 +316,17 @@ static int iap_task(struct timeout *tmo) return MS_TO_TICKS(100); } + +void iap_set_remote_volume(void) +{ + IAP_TX_INIT(0x03, 0x0D); + IAP_TX_PUT(0x04); + IAP_TX_PUT(0x00); + IAP_TX_PUT(0xFF & (int)((global_settings.volume + 90) * 2.65625)); + iap_send_tx(); +} + + /* This thread is waiting for events posted to iap_queue and calls * the appropriate subroutines in response */ @@ -859,11 +878,15 @@ void iap_periodic(void) /* Volume change notifications are sent every 100ms */ if (device.notifications & (BIT_N(4) | BIT_N(16))) { - /* Currently we do not track volume changes, so this is - * never sent. + /* Currently we do not track volume changes for BIT_N(16), * - * TODO: Fix volume tracking */ + IAP_TX_INIT(0x03, 0x09); + IAP_TX_PUT(0x04); + IAP_TX_PUT(0x00); + IAP_TX_PUT(0xFF &(int)((global_settings.volume + 90) * 2.65625)); + device.changed_notifications |= BIT_N(4); + iap_send_tx(); } /* All other events are sent every 500ms */ @@ -972,9 +995,15 @@ void iap_periodic(void) unsigned char play_status; play_status = audio_status(); - if (device.play_status != play_status) { + /* If play_status = PAUSE/STOP we should mute else + * we should unmute + * 0 = Stopped + * 1 = Playing + * 2 = Pause + * 3 = Play/Pause + */ IAP_TX_INIT(0x03, 0x09); IAP_TX_PUT(0x03); if (play_status & AUDIO_STATUS_PLAY) { @@ -994,6 +1023,23 @@ void iap_periodic(void) iap_send_tx(); device.play_status = play_status; + if (play_status != 1) { + /* Not Playing */ + audio_pause(); +#if CONFIG_TUNER + if (radio_present==1) { + tuner_set(RADIO_MUTE,1); + } +#endif + } else { + /* Playing */ + audio_resume(); +#if CONFIG_TUNER + if (radio_present==1) { + tuner_set(RADIO_MUTE,0); + } +#endif + } } } @@ -1212,43 +1258,6 @@ static void iap_handlepkt_mode5(const unsigned int len, const unsigned char *buf } } -#if 0 -static void iap_handlepkt_mode7(const 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; - } - } -} -#endif - void iap_handlepkt(void) { int level; @@ -1271,17 +1280,21 @@ void iap_handlepkt(void) logf("R: %s", hexstring(iap_rxstart+2, (length))); #endif - unsigned char mode = *(iap_rxstart+2); - switch (mode) { - case 0: iap_handlepkt_mode0(length, iap_rxstart+2); break; + if (length != 0) { + unsigned char mode = *(iap_rxstart+2); + switch (mode) { + case 0: iap_handlepkt_mode0(length, iap_rxstart+2); break; #ifdef HAVE_LINE_REC - case 1: iap_handlepkt_mode1(length, iap_rxstart+2); break; + case 1: iap_handlepkt_mode1(length, iap_rxstart+2); break; #endif - case 2: iap_handlepkt_mode2(length, iap_rxstart+2); break; - case 3: iap_handlepkt_mode3(length, iap_rxstart+2); break; - case 4: iap_handlepkt_mode4(length, iap_rxstart+2); break; - case 5: iap_handlepkt_mode5(length, iap_rxstart+2); break; - /* case 7: iap_handlepkt_mode7(length, iap_rxstart+2); break; */ + case 2: iap_handlepkt_mode2(length, iap_rxstart+2); break; + case 3: iap_handlepkt_mode3(length, iap_rxstart+2); break; + case 4: iap_handlepkt_mode4(length, iap_rxstart+2); break; + case 5: iap_handlepkt_mode5(length, iap_rxstart+2); break; +#if CONFIG_TUNER + case 7: iap_handlepkt_mode7(length, iap_rxstart+2); break; +#endif + } } /* Remove the handled packet from the RX buffer diff --git a/apps/iap/iap-core.h b/apps/iap/iap-core.h index 61b72d4ca2..b558e1cc0f 100644 --- a/apps/iap/iap-core.h +++ b/apps/iap/iap-core.h @@ -34,6 +34,7 @@ /* The Model ID of the iPod we emulate. Currently a 160GB classic */ #define IAP_IPOD_MODEL (0x00130200U) +#define IAP_IPOD_VARIANT "MC293" /* The firmware version we emulate. Currently 2.0.3 */ #define IAP_IPOD_FIRMWARE_MAJOR (2) @@ -73,14 +74,15 @@ enum interface_state { /* States of the authentication state machine */ enum authen_state { - AUST_NONE, /* Initial state, no message sent */ - AUST_INIT, /* Remote side has requested authentication */ - AUST_CERTREQ, /* Remote certificate requested */ - AUST_CERTBEG, /* Certificate is being received */ - AUST_CERTDONE, /* Certificate received */ - AUST_CHASENT, /* Challenge sent */ - AUST_CHADONE, /* Challenge response received */ - AUST_AUTH, /* Authentication complete */ + AUST_NONE, /* Initial state, no message sent */ + AUST_INIT, /* Remote side has requested authentication */ + AUST_CERTREQ, /* Remote certificate requested */ + AUST_CERTBEG, /* Certificate is being received */ + AUST_CERTALLRECEIVED, /* Certificate all Received */ + AUST_CERTDONE, /* Certificate all Done */ + AUST_CHASENT, /* Challenge sent */ + AUST_CHADONE, /* Challenge response received */ + AUST_AUTH, /* Authentication complete */ }; /* State of authentication */ @@ -237,6 +239,7 @@ void iap_repeat_next(void); void iap_fill_power_state(void); void iap_send_tx(void); +void iap_set_remote_volume(void); extern enum interface_state interface_state; void iap_interface_state_change(const enum interface_state new); diff --git a/apps/iap/iap-lingo.h b/apps/iap/iap-lingo.h index 888490c26a..982a62173f 100644 --- a/apps/iap/iap-lingo.h +++ b/apps/iap/iap-lingo.h @@ -24,3 +24,6 @@ void iap_handlepkt_mode1(const unsigned int len, const unsigned char *buf); void iap_handlepkt_mode2(const unsigned int len, const unsigned char *buf); void iap_handlepkt_mode3(const unsigned int len, const unsigned char *buf); void iap_handlepkt_mode4(const unsigned int len, const unsigned char *buf); +#if CONFIG_TUNER +void iap_handlepkt_mode7(const unsigned int len, const unsigned char *buf); +#endif diff --git a/apps/iap/iap-lingo0.c b/apps/iap/iap-lingo0.c index e69b42beae..a0c74ce053 100644 --- a/apps/iap/iap-lingo0.c +++ b/apps/iap/iap-lingo0.c @@ -21,6 +21,10 @@ #include "iap-lingo.h" #include "kernel.h" #include "system.h" +#include "tuner.h" +#if CONFIG_TUNER +#include "ipod_remote_tuner.h" +#endif /* * This macro is meant to be used inside an IAP mode message handler. @@ -45,10 +49,13 @@ static void cmd_ack(const unsigned char cmd, const unsigned char status) { - IAP_TX_INIT(0x00, 0x02); - IAP_TX_PUT(status); - IAP_TX_PUT(cmd); - iap_send_tx(); + if (cmd != 0){ + IAP_TX_INIT(0x00, 0x02); + IAP_TX_PUT(status); + IAP_TX_PUT(cmd); + + iap_send_tx(); + } } #define cmd_ok(cmd) cmd_ack((cmd), IAP_ACK_OK) @@ -59,6 +66,7 @@ static void cmd_pending(const unsigned char cmd, const uint32_t msdelay) IAP_TX_PUT(0x06); IAP_TX_PUT(cmd); IAP_TX_PUT_U32(msdelay); + iap_send_tx(); } @@ -387,7 +395,7 @@ void iap_handlepkt_mode0(const unsigned int len, const unsigned char *buf) { IAP_TX_INIT(0x00, 0x0E); IAP_TX_PUT_U32(IAP_IPOD_MODEL); - IAP_TX_PUT_STRING("ROCKBOX"); + IAP_TX_PUT_STRING(IAP_IPOD_VARIANT); iap_send_tx(); break; @@ -476,6 +484,59 @@ void iap_handlepkt_mode0(const unsigned int len, const unsigned char *buf) /* Issuing this command exits any extended interface states */ iap_interface_state_change(IST_STANDARD); + /* + * Actions by remote listed Apple Firmware Rockbox Firmware + * Apple remote on Radio pause/play - Mutes Mutes + * vol up/down - Vol Up/Dn Vol Up/Dn + * FF/FR - Station Up/Dn Station Up/Dn + * iPod Pause/Play - Mutes Mutes + * Vol up/down - Vol Up/Dn Vol Up/Dn + * FF/FR - Station Up/Dn Station Up/Dn + * Remote pause/play - Pause/Play Pause/Play + * vol up/down - Vol Up/Dn Vol Up/Dn + * FF/FR - Next/Prev Track Next/Prev Track + * iPod Pause/Play - Pause/Play Pause/Play + * Vol up/down - Vol Up/Dn Vol Up/Dn + * FF/FR - Next/Prev Track Next/Prev Track + * + * The following bytes are returned by the accessories listed + * FF 55 0E 00 13 00 00 00 3D 00 00 00 04 00 00 00 00 9E robi DAB Radio Remote + * FF 55 0E 00 13 00 00 00 35 00 00 00 04 00 00 00 00 A6 (??) FM Transmitter + * FF 55 0E 00 13 00 00 00 8D 00 00 00 0E 00 00 00 03 41 Apple Radio Remote + * + * Bytes 9-12 = Options 11111100 0000 00 00 + * 54321098 7654 32 10 + * 00000004 = 00000000 00000000 00000000 0000 01 00 Bits 2 + * 00000004 = 00000000 00000000 00000000 0000 01 00 Bits 2 + * 0000000E = 00000000 00000000 00000000 0000 01 10 Bits 12 + * + * Bit 0: Authentication 00 = No Authentication + * 01 = Defer Auth until required (V1) + * Bit 1: 10 = Authenticate Immediately (V2) + * 11 = Reserved + * Bit 2: Power Requirements 00 = Low Power Only 10 = Reserved + * Bit 3: 01 = Int High Power 11 = Reserved + * + * Bytes 13-16 = Device ID + * 00000000 + * 00000000 + * 00000003 + * + * Bytes 5-8 = lingoes spoken 11111100 00000000 + * 54321098 76543210 + * 0000003D = 00000000 00000000 00000000 00111101 Bits 2345 + * 00000035 = 00000000 00000000 00000000 00110101 Bits 245 + * 0000008D = 00000000 00000000 00000000 10001101 Bits 237 + * + * + * Bit 0: Must be set by all devices. See above + * Bit 1: Microphone Lingo + * Bit 2: Simple Remote + * Bit 3: Display Remote + * Bit 4: Extended Remote + * Bit 5: RF Transmitter lingo + */ + /* Loop through the lingoes advertised by the device. * If it tries to use a lingo we do not support, return * a Command Failed ACK. @@ -531,33 +592,49 @@ void iap_handlepkt_mode0(const unsigned int len, const unsigned char *buf) cmd_ok(cmd); + /* Bit 0: Must be set by all devices. See above*/ + /* Bit 1: Microphone Lingo */ + /* Bit 2: Simple Remote */ + /* Bit 3: Display Remote */ + /* Bit 4: Extended Remote */ /* Bit 5: RF Transmitter lingo */ if (lingoes & (1 << 5)) { /* FM transmitter sends this: */ /* FF 55 0E 00 13 00 00 00 35 00 00 00 04 00 00 00 00 A6 (??)*/ - + /* 0x00000035 = 00000000 00000000 00000000 00110101 */ + /* 1<<5 1 */ /* 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)); - } + IAP_TX_INIT(0x00, 0x27); + IAP_TX_PUT(0x00); + iap_send_tx(); -#if 0 + /* RF Transmitter: Begin transmission */ + IAP_TX_INIT(0x05, 0x02); + + iap_send_tx(); + } + /* Bit 6: USB Host Control */ /* Bit 7: RF Tuner lingo */ +#if CONFIG_TUNER if (lingoes & (1 << 7)) { - /* ipod fm remote sends this: */ - /* FF 55 0E 00 13 00 00 00 8D 00 00 00 0E 00 00 00 03 41 */ + /* ipod fm radio remote sends this: */ + /* FF 55 0E 00 13 00 00 00 8D 00 00 00 0E 00 00 00 03 */ + /* 0x0000008D = 00000000 00000000 00000000 00011101 */ + /* 1<<7 */ radio_present = 1; - /* GetDevAuthenticationInfo */ - unsigned char data4[] = {0x00, 0x14}; - iap_send_pkt(data4, sizeof(data4)); } #endif + /* Bit 8: Accessory Equalizer Lingo */ + /* Bit 9: Reserved */ + /* Bit 10: Digial Audio Lingo */ + /* Bit 11: Reserved */ + /* Bit 12: Storage Lingo */ + /* Bit 13: Reserved */ + /* .................*/ + /* Bit 31: Reserved */ break; } @@ -594,7 +671,8 @@ void iap_handlepkt_mode0(const unsigned int len, const unsigned char *buf) { /* There are two formats of this packet. One with only * the version information bytes (for Auth version 1.0) - * and the long form shown above + * and the long form shown above but it must be at least 4 + * bytes long */ CHECKLEN(4); @@ -605,25 +683,8 @@ void iap_handlepkt_mode0(const unsigned int len, const unsigned char *buf) device.auth.version = (buf[2] << 8) | buf[3]; - /* We support authentication versions 1.0 and 2.0 */ - if (device.auth.version == 0x100) { - /* If we could really do authentication we'd have to - * check the certificate here. Since we can't, just acknowledge - * the packet with an "everything OK" AckDevAuthenticationInfo - * - * Skip GetAccessoryInfo process, this command together with - * authentication level 2 were added in iAP release 24, it is - * not be supported by devices authenticating at level 1. - */ - IAP_TX_INIT(0x00, 0x16); - IAP_TX_PUT(0x00); - - iap_send_tx(); - device.auth.state = AUST_CERTDONE; - break; - } - - if (device.auth.version != 0x200) { + /* We only support authentication versions 1.0 and 2.0 */ + if ((device.auth.version != 0x100) && (device.auth.version != 0x200)) { /* Version mismatches are signalled by AckDevAuthenticationInfo * with the status set to Authentication Information unsupported */ @@ -635,61 +696,77 @@ void iap_handlepkt_mode0(const unsigned int len, const unsigned char *buf) iap_send_tx(); break; } - - /* There must be at least one byte of certificate data - * in the packet - */ - CHECKLEN(7); - - switch (device.auth.state) - { - /* This is the first packet. Note the maximum section number - * so we can check it later. + if (device.auth.version == 0x100) { + /* If we could really do authentication we'd have to + * check the certificate here. Since we can't, just acknowledge + * the packet later with an "everything OK" AckDevAuthenticationInfo + * and change device.auth.state to AuthenticateState_CertificateDone */ - case AUST_CERTREQ: + device.auth.state = AUST_CERTALLRECEIVED; + } else { + /* Version 2.00 requires at least one byte of certificate data + * in the packet + */ + CHECKLEN(7); + switch (device.auth.state) { - device.auth.max_section = buf[5]; - device.auth.state = AUST_CERTBEG; + /* This is the first packet. Note the maximum section number + * so we can check it later. + */ + case AUST_CERTREQ: + { + device.auth.max_section = buf[5]; + device.auth.state = AUST_CERTBEG; - /* Intentional fall-through */ - } - /* All following packets */ - case AUST_CERTBEG: - { - /* Check if this is the expected section */ - if (buf[4] != device.auth.next_section) { - cmd_ack(cmd, IAP_ACK_BAD_PARAM); + /* Intentional fall-through */ + } + /* All following packets */ + case AUST_CERTBEG: + { + /* Check if this is the expected section */ + if (buf[4] != device.auth.next_section) { + cmd_ack(cmd, IAP_ACK_BAD_PARAM); + break; + } + + /* Is this the last section? */ + if (device.auth.next_section == device.auth.max_section) { + /* If we could really do authentication we'd have to + * check the certificate here. Since we can't, just acknowledge + * the packet later with an "everything OK" AckDevAuthenticationInfo + * and change device.auth.state to AuthenticateState_CertificateDone + */ + device.auth.state = AUST_CERTALLRECEIVED; + } else { + device.auth.next_section++; + cmd_ok(cmd); + } break; } - - /* Is this the last section? */ - if (device.auth.next_section == device.auth.max_section) { - /* If we could really do authentication we'd have to - * check the certificate here. Since we can't, just acknowledge - * the packet with an "everything OK" AckDevAuthenticationInfo - * - * Also, start GetAccessoryInfo process - */ - IAP_TX_INIT(0x00, 0x16); - IAP_TX_PUT(0x00); - - iap_send_tx(); - device.auth.state = AUST_CERTDONE; - device.accinfo = ACCST_INIT; - } else { - device.auth.next_section++; - cmd_ok(cmd); + default: + { + cmd_ack(cmd, IAP_ACK_BAD_PARAM); + break; } - break; - } - - default: - { - cmd_ack(cmd, IAP_ACK_BAD_PARAM); - break; } } + if (device.auth.state == AUST_CERTALLRECEIVED) { + /* We've received all the certificate data so just + *Acknowledge everything OK + */ + IAP_TX_INIT(0x00, 0x16); + IAP_TX_PUT(0x00); + + iap_send_tx(); + + /* GetAccessoryInfo*/ + IAP_TX_INIT(0x00, 0x27); + IAP_TX_PUT(0x00); + + iap_send_tx(); + device.auth.state = AUST_CERTDONE; + } break; } @@ -744,6 +821,17 @@ void iap_handlepkt_mode0(const unsigned int len, const unsigned char *buf) iap_send_tx(); device.auth.state = AUST_AUTH; +#if CONFIG_TUNER + if (radio_present == 1) + { + /* GetTunerCaps */ + IAP_TX_INIT(0x07, 0x01); + + iap_send_tx(); + } +#endif + iap_set_remote_volume(); + break; } @@ -926,7 +1014,9 @@ void iap_handlepkt_mode0(const unsigned int len, const unsigned char *buf) CHECKLEN(7); device.capabilities = get_u32(&buf[0x03]); - /* Type 0x00 was already queried, that's where this information comes from */ + /* Type 0x00 was already queried, that's where this + * information comes from + */ device.capabilities_queried = 0x01; device.capabilities &= ~0x01; break; @@ -1045,9 +1135,8 @@ void iap_handlepkt_mode0(const unsigned int len, const unsigned char *buf) { #ifdef LOGF_ENABLE logf("iap: Unsupported Mode00 Command"); -#else - cmd_ack(cmd, IAP_ACK_BAD_PARAM); #endif + cmd_ack(cmd, IAP_ACK_BAD_PARAM); break; } } diff --git a/apps/iap/iap-lingo1.c b/apps/iap/iap-lingo1.c index 5702500f23..56c52d81ae 100644 --- a/apps/iap/iap-lingo1.c +++ b/apps/iap/iap-lingo1.c @@ -212,6 +212,7 @@ void iap_handlepkt_mode1(const unsigned int len, const unsigned char *buf) #ifdef LOGF_ENABLE logf("iap: Unsupported Mode1 Command"); #endif + cmd_ack(cmd, IAP_ACK_BAD_PARAM); break; } } diff --git a/apps/iap/iap-lingo2.c b/apps/iap/iap-lingo2.c index d4c2f18c2f..946e51222d 100644 --- a/apps/iap/iap-lingo2.c +++ b/apps/iap/iap-lingo2.c @@ -30,6 +30,10 @@ #include "button.h" #include "audio.h" #include "settings.h" +#include "tuner.h" +#if CONFIG_TUNER +#include "ipod_remote_tuner.h" +#endif /* * This macro is meant to be used inside an IAP mode message handler. @@ -57,6 +61,9 @@ static void cmd_ack(const unsigned char cmd, const unsigned char status) void iap_handlepkt_mode2(const unsigned int len, const unsigned char *buf) { static bool poweron_pressed = false; +#if CONFIG_TUNER + static bool remote_mute = false; +#endif unsigned int cmd = buf[1]; /* We expect at least three bytes in the buffer, one for the @@ -95,7 +102,21 @@ void iap_handlepkt_mode2(const unsigned int len, const unsigned char *buf) if(buf[2] != 0) { if(buf[2] & 1) + { REMOTE_BUTTON(BUTTON_RC_PLAY); +#if CONFIG_TUNER + if (radio_present == 1) { + if (remote_mute == 0) { + /* Not Muted so radio on*/ + tuner_set(RADIO_MUTE,0); + } else { + /* Muted so radio off*/ + tuner_set(RADIO_MUTE,1); + } + remote_mute = !remote_mute; + } +#endif + } if(buf[2] & 2) REMOTE_BUTTON(BUTTON_RC_VOL_UP); if(buf[2] & 4) @@ -111,11 +132,21 @@ void iap_handlepkt_mode2(const unsigned int len, const unsigned char *buf) { if (audio_status() != AUDIO_STATUS_PLAY) REMOTE_BUTTON(BUTTON_RC_PLAY); +#if CONFIG_TUNER + if (radio_present == 1) { + tuner_set(RADIO_MUTE,0); + } +#endif } if(buf[3] & 2) /* pause */ { if (audio_status() == AUDIO_STATUS_PLAY) REMOTE_BUTTON(BUTTON_RC_PLAY); +#if CONFIG_TUNER + if (radio_present == 1) { + tuner_set(RADIO_MUTE,1); + } +#endif } if(buf[3] & 128) /* Shuffle */ { @@ -295,9 +326,8 @@ void iap_handlepkt_mode2(const unsigned int len, const unsigned char *buf) { #ifdef LOGF_ENABLE logf("iap: Unsupported Mode02 Command"); -#else - cmd_ack(cmd, IAP_ACK_BAD_PARAM); #endif + cmd_ack(cmd, IAP_ACK_BAD_PARAM); break; } } diff --git a/apps/iap/iap-lingo3.c b/apps/iap/iap-lingo3.c index 0ed3df118e..c7801fbce0 100644 --- a/apps/iap/iap-lingo3.c +++ b/apps/iap/iap-lingo3.c @@ -38,6 +38,9 @@ #include "settings.h" #include "metadata.h" #include "playback.h" +#if CONFIG_TUNER +#include "ipod_remote_tuner.h" +#endif /* * This macro is meant to be used inside an IAP mode message handler. @@ -262,7 +265,7 @@ void iap_handlepkt_mode3(const unsigned int len, const unsigned char *buf) device.play_status = audio_status(); /* TODO: Fix this */ device.mute = false; - device.volume = 0x80; + device.volume = global_settings.volume; device.power_state = charger_input_state; device.battery_level = battery_level(); /* TODO: Fix this */ @@ -299,8 +302,8 @@ void iap_handlepkt_mode3(const unsigned int len, const unsigned char *buf) /* GetRemoteEventStatus (0x0A) * - * Request the events changed since the last call to GetREmoteEventStatus - * or SetRemoteEventNotification + * Request the events changed since the last call to + * GetREmoteEventStatus or SetRemoteEventNotification * * Packet format (offset in buf[]: Description) * 0x00: Lingo ID: Display Remote Lingo, always 0x03 @@ -434,15 +437,18 @@ void iap_handlepkt_mode3(const unsigned int len, const unsigned char *buf) */ case 0x04: { - /* Figuring out what the current volume is - * seems to be tricky. - * TODO: Fix. - */ + if (device.mute == false) { + /* Mute status False*/ + IAP_TX_PUT(0x00); + /* Volume */ + IAP_TX_PUT(0xFF & (int)((global_settings.volume + 90) * 2.65625)); - /* Mute status */ - IAP_TX_PUT(0x00); - /* Volume */ - IAP_TX_PUT(0x80); + } else { + /* Mute status True*/ + IAP_TX_PUT(0x01); + /* Volume should be 0 if muted */ + IAP_TX_PUT(0x00); + } iap_send_tx(); break; @@ -620,15 +626,24 @@ void iap_handlepkt_mode3(const unsigned int len, const unsigned char *buf) */ case 0x10: { - /* TODO: See volume above */ - IAP_TX_PUT(0x00); - IAP_TX_PUT(0x80); - IAP_TX_PUT(0x80); + if (device.mute == false) { + /* Mute status False*/ + IAP_TX_PUT(0x00); + /* Volume */ + IAP_TX_PUT(0xFF & (int)((global_settings.volume + 90) * 2.65625)); + IAP_TX_PUT(0xFF & (int)((global_settings.volume + 90) * 2.65625)); + + } else { + /* Mute status True*/ + IAP_TX_PUT(0x01); + /* Volume should be 0 if muted */ + IAP_TX_PUT(0x00); + IAP_TX_PUT(0x00); + } iap_send_tx(); break; } - default: { cmd_ack(cmd, IAP_ACK_BAD_PARAM); @@ -746,14 +761,18 @@ void iap_handlepkt_mode3(const unsigned int len, const unsigned char *buf) break; } - /* Volume/Mute - * Data length: 2 - * TODO: Fix this - */ case 0x04: { CHECKLEN(5); - cmd_ack(cmd, IAP_ACK_CMD_FAILED); + if (buf[0x03]==0x00){ + /* Not Muted */ + global_settings.volume = (int) (buf[0x04]/2.65625)-90; + device.mute = false; + } + else { + device.mute = true; + } + cmd_ok(cmd); break; } @@ -919,7 +938,16 @@ void iap_handlepkt_mode3(const unsigned int len, const unsigned char *buf) case 0x10: { CHECKLEN(7); - cmd_ack(cmd, IAP_ACK_CMD_FAILED); + if (buf[0x03]==0x00){ + /* Not Muted */ + global_settings.volume = (int) (buf[0x04]/2.65625)-90; + device.mute = false; + } + else { + device.mute = true; + } + + cmd_ok(cmd); break; } @@ -1499,9 +1527,8 @@ void iap_handlepkt_mode3(const unsigned int len, const unsigned char *buf) { #ifdef LOGF_ENABLE logf("iap: Unsupported Mode03 Command"); -#else - cmd_ack(cmd, IAP_ACK_BAD_PARAM); #endif + cmd_ack(cmd, IAP_ACK_BAD_PARAM); break; } } diff --git a/apps/iap/iap-lingo4.c b/apps/iap/iap-lingo4.c index 903cef9378..b601501b3d 100644 --- a/apps/iap/iap-lingo4.c +++ b/apps/iap/iap-lingo4.c @@ -109,9 +109,8 @@ static void seek_to_playlist(unsigned long index) ft_play_playlist(selected_playlist, global_settings.playlist_catalog_dir, strrchr(selected_playlist, '/') + 1); - } - + static unsigned long nbr_total_playlists(void) { DIR* dp; @@ -161,7 +160,7 @@ void iap_handlepkt_mode4(const unsigned int len, const unsigned char *buf) switch (cmd) { case 0x0001: /* CmdAck. See above cmd_ack() */ - /* + /* * The following is the description for the Apple Firmware * The iPod sends this telegram to acknowledge the receipt of a * command and return the command status. The command ID field @@ -1457,7 +1456,7 @@ void iap_handlepkt_mode4(const unsigned int len, const unsigned char *buf) case 0x05: /* Tracks */ case 0x02: /* Artists */ case 0x03: /* Albums */ - case 0x04: /* Genre */ + case 0x04: /* Genre */ case 0x06: /* Composer */ playlist_get_track_info(NULL, start_index + counter, &track); @@ -2019,8 +2018,8 @@ void iap_handlepkt_mode4(const unsigned int len, const unsigned char *buf) playlist_randomise(NULL, current_tick, true); } else - { - playlist_sort(NULL, true); + { + playlist_sort(NULL, true); } audio_skip(index - playlist_next(0)); if (!paused) diff --git a/apps/iap/iap-lingo7.c b/apps/iap/iap-lingo7.c new file mode 100644 index 0000000000..467a81cc76 --- /dev/null +++ b/apps/iap/iap-lingo7.c @@ -0,0 +1,491 @@ +/*************************************************************************** + * __________ __ ___. + * 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 "iap-core.h" +#include "iap-lingo.h" +#include "kernel.h" +#include "system.h" +#include "tuner.h" +#if CONFIG_TUNER +#include "ipod_remote_tuner.h" +#endif + +/* + * This macro is meant to be used inside an IAP mode message handler. + * It is passed the expected minimum length of the message inbufferfer. + * If the inbufferfer does not have the required lenght an ACK + * packet with a Bad Parameter error is generated. + */ +#define CHECKLEN(x) do { \ + if (len < (x)) { \ + cmd_ack(cmd, IAP_ACK_BAD_PARAM); \ + return; \ + }} while(0) + +/* Check for authenticated state, and return an ACK Not + * Authenticated on failure. + */ +#define CHECKAUTH do { \ + if (!DEVICE_AUTHENTICATED) { \ + cmd_ack(cmd, IAP_ACK_NO_AUTHEN); \ + return; \ + }} while(0) + + +static void cmd_ack(const unsigned char cmd, const unsigned char status) +{ + IAP_TX_INIT(0x07, 0x00); + IAP_TX_PUT(status); + IAP_TX_PUT(cmd); + + iap_send_tx(); +} + +#define cmd_ok(cmd) cmd_ack((cmd), IAP_ACK_OK) + +void iap_handlepkt_mode7(const unsigned int len, const unsigned char *inbuffer) +{ + /* Note that some of the Lingo Mode 7 commands are handled by + * ../firmware/drivers/tuner/ipod_remote_tuner.c as some of the + * commands are sourced with the remote as the master with the ipod acting + * as the slave. + */ + unsigned char cmd = inbuffer[1]; + unsigned char statusnotifymaskbyte = 0; + + /* We expect at least two bytes in the inbuffer, one for the + * lingo and one for the command + */ + CHECKLEN(2); + + /* Lingo 0x07 must have been negotiated */ + if (!DEVICE_LINGO_SUPPORTED(0x07)) { + cmd_ack(cmd, IAP_ACK_BAD_PARAM); + return; + } + + switch (cmd) + { + /* case 00 ToIpod Ack 2/6 bytes*/ + case 0x00: + { + /* 0x00 OK + * 0x01 Unknown Track Category + * 0x02 Command Failed. Command is valid but did not succeed + * 0x03 Out Of Resources + * 0x04 Bad Parameter + * 0x05 Unknown Track ID + * 0x06 Command Pending. + * 0x07 Not Authenticated + * + * byte 1 is ID of command being acknowledged + * bytes 2-5 only if status byte is pending. timeout in ms. + */ + break; + } + + /* case 0x01 ToAccessory GetTunerCaps + * This is sent by iap-lingo0.c through case 0x15 after device + * has been authenticated FF55020701F6 + */ + + /* case 02 ToIpod RetTunerCaps 8 bytes */ + case 0x02: + { + /* Capabilities are stored as bits in first 4 bytes, + * inbuffer[2] byte is bits 31:24 + * inbuffer[3] byte is bits 23:16 + * inbuffer[4] byte is bits 15:08 + * inbuffer[5] byte is bits 07:00 + * inbuffer[6] and inbuffer[7] are all reserved bits + * Bit 0 = AM Band 520-1710 Khz + * Bit 1 = FM Europe/US 87.5 - 108.0 Mhz + * Bit 2 = FM Japan 76.0 - 90.0 Mhz + * Bit 3 = FM Wide 76.0 - 108.0 Mhz + * Bit 4 = HD Radio Capable + * Bit 5:7 Reserved + * Bit 8 = Tuner Power On/Off Control Capable + * Bit 9 = Status Change Notification Capable + * Bit 10:15 Reserved + * Bit 17:16 Minimum FM Resolution ID Bits + * 00 = 200Khz, 01 = 100Khz, 10 = 50Khz, 11 = reserved + * Bit 18 = Tuner Seek Up/Down Capable + * Bit 19 = Tuner Seek RSSI Threshold. Only if 18=1 + * Bit 20 = Force Monophonic mode capable + * Bit 21 = Stero Blend Capable + * Bit 22 = FM Tuner deemphasis select capable + * Bit 23 = AM Tuner Resolution 9Khz (0=10Khz Only) capable + * Bit 24 = Radio Data System (RDS/RBDS) data capable + * Bit 25 = Tuner Channel RSSI indicator capable + * Bit 26 = Stero Source Indicator capable + * Bit 27 = RDS/RBDS Raw mode capable + * Bit 31:28 Reserved + * + * ipod Tuner returns 07 5E 07 0E 10 4B + * Bytes 6,7 Reserved + * ???????? ???????? + * ???????? ???????? + * 00010000 01001011 + * + * Byte 5 - 0E + * 00000000 + * 76543210 + * 00001110 + * AM + * FM Europe/US + * FM Japan + * FM Wide + * + * Byte 4 - 07 + * 11111100 + * 54321098 + * 00000111 + * Tuner Power On/Off + * Status Change Notification + * ?? Should be reserved + * + * Byte 3 - 5E + * 22221111 + * 32109876 + * 01011110 + * Tuner Seek Up/Down + * Tuner Seek RSSI Threshold + * Force Mono Mode Capable + * Stereo Blend Capable + * FM Tuner deemphasis select capable + * + * Byte 2 - 07 + * 33222222 + * 10987654 + * 00000111 + * RDS/RBDS Capable + * Tuner Channel RSSI Indicator + * Stereo Source + * + * Just need to see what we can use this data for + * Make a selection for the tuner mode to select + * Preference is + * 1st - 76 to 108 FM + * 2nd - 87.5 to 108 Fm + * 3rd - 76 to 90 Fm + * 4th - AM + * + */ + + if ((inbuffer[4] & 0x03) >0) { + statusnotifymaskbyte = 0; + if ((inbuffer[4] >> 0) & 0x01) { + /* Supports Tuner Power On/Off, so set ON */ + statusnotifymaskbyte = 1; + } + if ((inbuffer[4] >> 1) & 0x01) { + /* Supports Status Change Notification so set ON */ + /* Apple 5/6/7G firmware does NOT enable this bit */ + /* statusnotifymaskbyte += 2; */ + } + IAP_TX_INIT(0x07, 0x05); + IAP_TX_PUT(statusnotifymaskbyte); + iap_send_tx(); + } + if ((inbuffer[5] >> 1) & 0x01) { + /* Supports FM Europe/US Tuner 87.5 - 108.0 Mhz */ + /* Apple firmware sends this before setting region */ + IAP_TX_INIT(0x07, 0x0E); + IAP_TX_PUT(0x00); + iap_send_tx(); + /* Apple firmware then sends region */ + IAP_TX_INIT(0x07, 0x08); + IAP_TX_PUT(0x02); + iap_send_tx(); + } else if ((inbuffer[5] >> 3) & 0x01) { + /* Supports FM Wide Tuner 76 - 108.0 Mhz */ + /* apple firmware send this before setting region */ + IAP_TX_INIT(0x07, 0x0E); + IAP_TX_PUT(0x00); + iap_send_tx(); + /* Apple firmware then send region */ + IAP_TX_INIT(0x07, 0x08); + IAP_TX_PUT(0x08); + iap_send_tx(); + } else if ((inbuffer[5] >> 2) & 0x01) { + /* Supports FM Japan Tuner 76 - 90.0 Mhz */ + /* apple firmware send this before setting region */ + IAP_TX_INIT(0x07, 0x0E); + IAP_TX_PUT(0x41); + iap_send_tx(); + /* Apple firmware then send region */ + IAP_TX_INIT(0x07, 0x08); + IAP_TX_PUT(0x04); + iap_send_tx(); + } else if ((inbuffer[5] >> 0) & 0x01) { + /* Supports AM Tuner */ + IAP_TX_INIT(0x07, 0x08); + IAP_TX_PUT(0x01); + iap_send_tx(); + } + + if ((inbuffer[2] & 0x03) > 0) { + statusnotifymaskbyte = 0; + if ((inbuffer[2] >> 0) & 0x01) { + /* Supports RDS/RBDS Capable so set + *StatusChangeNotify for RDS/RBDS Data + */ + statusnotifymaskbyte = 1; + } + if ((inbuffer[2] >> 1) & 0x01) { + /* Supports Tuner Channel RSSi Indicator Capable so set */ + /* StatusChangeNotify for RSSI */ + /* Apple 5G firmware does NOT enable this bit so we wont */ + /* statusnotifymaskbyte += 2; */ + } + IAP_TX_INIT(0x07, 0x18); + IAP_TX_PUT(statusnotifymaskbyte); + iap_send_tx(); + } + + if ((inbuffer[4] >> 2) & 0x01) { + /* Reserved */ + } + if ((inbuffer[4] >> 3) & 0x01) { + /* Reserved */ + } + if ((inbuffer[3] >> 1) & 0x01) { + /* Tuner Seek Up/Down` */ + } + if ((inbuffer[3] >> 2) & 0x01) { + /* Tuner Seek RSSI Threshold */ + } + if ((inbuffer[3] >> 3) & 0x01) { + /* Force Mono Mode */ + } + if ((inbuffer[3] >> 4) & 0x01) { + /* Stereo Blend */ + } + if ((inbuffer[3] >> 6) & 0x01) { + /* FM Tuner deemphasis */ + } + if ((inbuffer[2] >> 2) & 0x01) { + /* Stereo Source */ + } + break; + } + /* case 03 ToAccessory GetTunerCtrl 2 bytes */ + + /* case 04 ToIpod RetTunerCtrl 3 bytes + * Bit 0 power is on (1) or Off (0) + * Bit 1 StatusChangeNotify is enabled (1) or disabled (0) + * Bit 3 RDS/RBDS Raw mode enabled + * + * Should/Can we do something with these? + */ + + /* case 05 ToAccessory SetTunerCtrl 3 bytes + * Bits as per 0x04 above + * Bit 0/1 set through Lingo7 Cmd02 */ + + /* case 06 ToAccessory GetTunerBand 2 bytes */ + + /* case 07 ToIpod RetTunerBand 3 bytes + * Returns current band for Tuner. See 0x08 below + * + * Should/Can we do something with these? + */ + + /* case 08 ToAccessory SetTuneBand + * Set Bit 0 for AM + * Set Bit 1 for FM Europe/U S 87.5-108Mhz + * Set Bit 2 for FM JApan 76.0-90.0Mhz + * Set Bit 3 for FM Wide 76.0-108Mhz + * Currently we send this after receiving capabilities + * on 0x02 above + */ + + /* case 09 ToAccessory GetTunerFreq 2 bytes */ + + /* case 0A ToIpod RetTunerFreq 7 bytes */ + case 0x0A: + { + /* Returns Frequency set and RSSI Power Levels + * These are sent as is to rmt_tuner_freq() in + * ../firmware/drivers/tuner/ipod_remote_tuner.c */ + rmt_tuner_freq(len, inbuffer); + break; + } + + /* case 0B ToAccessory SetTunerFreq 6 bytes */ + + /* case 0C ToAccessory GetTunerMode 2 bytes */ + + /* case 0D ToIpod RetTunerMode 3 bytes + * Returns Tuner Mode Status in 8 bits as follows + * Bit 1:0 - FM Tuner Resolution + * Bit 2 Tuner is seeking up or down + * Bit 3 Tuner is seeking with RSSI min theshold enabled + * Bit 4 Force Mono Mode (1) or allow stereo (0) + * Bit 5 Stereo Blend enabled. Valid only if Bit 4 is 0 + * Bit 6 FM Tuner Deemphasis 50uS (1) or 75uS (0) + * Bit 7 Reserved 0 + */ + + /* case 0E ToAccessory SetTunerMode 3 bytes + * See 0x0D for Bit Descriptions + * Bits set by Cmd 02 + */ + + /* case 0F ToAccessory GetTunerSeekRssi 2 bytes */ + + /* case 10 ToIpod RetTunerSeekRssi 3 bytes + * Returns RSSI Value for seek operations + * value is 0 (min) - 255 (max) + */ + + /* case 11 ToAccessory SetTunerSeekRssi 3 bytes */ + + /* case 12 ToAccessory TunerSeekStart 3 bytes */ + + /* case 13 ToIpod TunerSeekDone 7 bytes */ + case 0x13: + { + rmt_tuner_freq(len, inbuffer); + break; + } + + /* case 14 ToAccessory GetTunerStatus 2 bytes */ + + /* case 15 ToIpod RetTunerStatus 3 bytes */ + + /* case 16 ToAccessory GetStatusNotifyMask 2 bytes */ + + /* case 17 ToIpod RetStatusNotifyMask 3 bytes */ + + /* case 18 ToAccessory SetStatusNotifyMask 3 bytes + * This is set by Cmd 02 + */ + + /* case 19 ToIpod StatusChangeNotify 3 bytes */ + case 0x19: + { + /* Returns StatusChangeNotify bits to ipod. + * Bit 0 set for RDS/RBDS data ready + * Bit 1 set for Tuner RSSI level change + * Bit 2 for Stereo Indicator changed + * If any of these are set we will request the data + * need to look at using these + */ + break; + } + + /* case 1A ToAccessory GetRdsReadyStatus 2 bytes */ + + /* case 1B ToIpod RetRdsReadyStatus 6 bytes */ + case 0x1B: + { + break; + } + /* case 1C ToAccessory GetRdsData 3 bytes */ + + /* case 1D ToIpod RetRdsData NN bytes */ + case 0x1D: + { + rmt_tuner_rds_data(len, inbuffer); + break; + } + + /* case 1E ToAccessory GetRdsNotifyMask 2 bytes*/ + + /* case 1F ToIpod RetRdsNotifyMask 6 Bytes*/ + case 0x1F: + { + break; + } + + /* case 20 ToAccessory SetRdsNotifyMask 6 bytes */ + + /* case 21 ToIpod RdsReadyNotify NN bytes */ + case 0x21: + { + rmt_tuner_rds_data(len, inbuffer); + break; + } + /* case 22 Reserved */ + + /* case 23 Reserved */ + + /* case 24 Reserved */ + + /* case 25 ToAccessory GetHDProgramServiceCount 0 bytes */ + + /* case 26 ToIpod RetHDProgramServiceCount 1 bytes */ + case 0x26: + { + break; + } + + /* case 27 ToAccessory GetHDProgramService 0 bytes */ + + /* case 28 ToIpod RetHDProgramService 1 bytes */ + case 0x28: + { + break; + } + + /* case 29 ToAccessory SetHDProgramService 1 bytes */ + + /* case 2A ToAccessory GetHDDataReadyStatus 0 bytes */ + + /* case 2B ToIpod RetHDDataReadyStatus 4 bytes */ + case 0x2B: + { + break; + } + + /* case 2C ToAccessory GetHDData 1 bytes */ + + /* case 2D ToIpod RetHDData NN bytes */ + case 0x2D: + { + break; + } + + /* case 2E ToAccessory GetHDDataNotifyMask 0 bytes */ + + /* case 2F ToIpod RetHDDataNotifyMask 4 bytes */ + case 0x2F: + { + break; + } + + /* case 30 ToAccessory SetHDDataNotifyMask 4 bytes */ + + /* case 31 ToIpod HDDataReadyNotify NN bytes */ + case 0x31: + { + break; + } + + /* The default response is IAP_ACK_BAD_PARAM */ + default: + { +#ifdef LOGF_ENABLE + logf("iap: Unsupported Mode07 Command"); +#endif + cmd_ack(cmd, IAP_ACK_BAD_PARAM); + break; + } + } +} -- cgit v1.2.3