rockbox/apps/iap.c
Jonathan Gordon 4c6b3551b5 split the theme settings apply() sutff out of settings_apply(). this should fix splashes not being loc'ed, statusbar over the splash (fixed in sim, not on my mini2g though), and the supposed boot time slowdown.
What this also does is remove a bunch of unnecessary settings_Apply()'s from the ipod accessory code, and causes all non-skin settings to get applied each time (this includes font and langs which we wernt doing to stop disk access)


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@24922 a1c6a512-1295-4272-9138-f99709370657
2010-02-26 08:01:41 +00:00

868 lines
28 KiB
C

/***************************************************************************
* __________ __ ___.
* 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 <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <memory.h>
#include <string.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"
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;
unsigned char serbuf[RX_BUFLEN];
static int serbuf_i = 0;
static unsigned char response[TX_BUFLEN];
static int responselen;
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);
}
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;
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]);
}
}
int iap_getc(unsigned char x)
{
static unsigned char last_x = 0;
static bool newpkt = true;
static unsigned char chksum = 0;
/* Restart if the sync word is seen */
if(x == 0x55 && last_x == 0xff/* && newpkt*/)
{
serbuf[0] = 0;
serbuf_i = 0;
chksum = 0;
newpkt = false;
}
else
{
if(serbuf_i >= RX_BUFLEN)
serbuf_i = 0;
serbuf[serbuf_i++] = x;
chksum += x;
}
last_x = x;
/* Broadcast to queue if we have a complete message */
if(serbuf_i && (serbuf_i == serbuf[0]+2))
{
serbuf_i = 0;
newpkt = true;
if(chksum == 0)
queue_post(&button_queue, SYS_IAP_HANDLEPKT, 0);
}
return newpkt;
}
/* called by playback when the next track starts */
void iap_track_changed(void *ignored)
{
(void)ignored;
iap_changedctr = 1;
}
void iap_periodic(void)
{
if(!iap_setupflag) return;
if(!iap_pollspeed) return;
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;
}
data[4] = time_elapsed >> 24;
data[5] = time_elapsed >> 16;
data[6] = time_elapsed >> 8;
data[7] = time_elapsed;
iap_send_pkt(data, sizeof(data));
}
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));
}
void iap_handlepkt(void)
{
if(!iap_setupflag) return;
if(serbuf[0] == 0) 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 Mode 0 */
if (serbuf[1] == 0x00)
{
switch (serbuf[2])
{
case 0x24:
{
/* ipod video send this */
unsigned char data[] = {0x00, 0x25, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,0x01};
iap_send_pkt(data, sizeof(data));
break;
}
case 0x18:
{
/* ciphered authentication command */
/* Isn't used since we don't send the 0x00 0x17 command */
break;
}
case 0x15:
{
unsigned char data0[] = {0x00, 0x16, 0x00};
iap_send_pkt(data0, sizeof(data0));
unsigned char data1[] = {0x00, 0x27, 0x00};
iap_send_pkt(data1, sizeof(data1));
/* authentication ack, mandatory to enable some hardware */
unsigned char data2[] = {0x00, 0x19, 0x00};
iap_send_pkt(data2, sizeof(data2));
if (radio_present == 1)
{
/* get tuner capacities */
unsigned char data3[] = {0x07, 0x01};
iap_send_pkt(data3, sizeof(data3));
}
iap_set_remote_volume();
break;
}
case 0x13:
{
unsigned char data[] = {0x00, 0x02, 0x00, 0x13};
iap_send_pkt(data, sizeof(data));
if (serbuf[6] == 0x35)
/* FM transmitter sends this: */
/* FF 55 0E 00 13 00 00 00 35 00 00 00 04 00 00 00 00 A6 (??)*/
{
unsigned char data2[] = {0x00, 0x27, 0x00};
iap_send_pkt(data2, sizeof(data2));
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 (serbuf[6] |= 0x80)
radio_present = 1;
unsigned char data4[] = {0x00, 0x14};
iap_send_pkt(data4, sizeof(data4));
}
break;
}
/* Init */
case 0x0F:
{
unsigned char data[] = {0x00, 0x10, 0x00, 0x01, 0x05};
data[2] = serbuf[3];
iap_send_pkt(data, sizeof(data));
break;
}
/* get model info */
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) */
unsigned char data[] = {0x00, 0x0E, 0x00, 0x0B, 0x00, 0x10,
'R', 'O', 'C', 'K', 'B', 'O', 'X', 0x00};
iap_send_pkt(data, sizeof(data));
break;
}
/* Ipod FM remote sends this: FF 55 02 00 09 F5 */
case 0x09:
{
/* ipod5G firmware version */
unsigned char data[] = {0x00, 0x0A, 0x01, 0x02, 0x01 };
iap_send_pkt(data, sizeof(data));
break;
}
/* FM transmitter sends this: */
/* FF 55 02 00 05 F9 (mode switch: AiR mode) */
case 0x05:
{
unsigned char data[] = {0x00, 0x02, 0x06,
0x05, 0x00, 0x00, 0x0B, 0xB8, 0x28};
iap_send_pkt(data, sizeof(data));
unsigned char data2[] = {0x00, 0x02, 0x00, 0x05};
iap_send_pkt(data2, sizeof(data2));
break;
}
case 0x01:
{
/* FM transmitter sends this: */
/* FF 55 06 00 01 05 00 02 01 F1 (mode switch) */
if(serbuf[3] == 0x05)
{
sleep(HZ/3);
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(serbuf[3] == 0x02)
{
/* useful only for apple firmware */
}
break;
}
/* default response is with cmd ok packet */
default:
{
unsigned char data[] = {0x00, 0x02, 0x00, 0x00};
data[3] = serbuf[2]; /* respond with cmd */
iap_send_pkt(data, sizeof(data));
break;
}
}
}
/* Handle Mode 2 */
else if (serbuf[1] == 0x02)
{
if(serbuf[2] != 0) return;
iap_remotebtn = BUTTON_NONE;
iap_remotetick = false;
if(serbuf[0] >= 3 && serbuf[3] != 0)
{
if(serbuf[3] & 1)
iap_remotebtn |= BUTTON_RC_PLAY;
if(serbuf[3] & 2)
iap_remotebtn |= BUTTON_RC_VOL_UP;
if(serbuf[3] & 4)
iap_remotebtn |= BUTTON_RC_VOL_DOWN;
if(serbuf[3] & 8)
iap_remotebtn |= BUTTON_RC_RIGHT;
if(serbuf[3] & 16)
iap_remotebtn |= BUTTON_RC_LEFT;
}
else if(serbuf[0] >= 4 && serbuf[4] != 0)
{
if(serbuf[4] & 1) /* play */
{
if (audio_status() != AUDIO_STATUS_PLAY)
{
iap_remotebtn |= BUTTON_RC_PLAY;
iap_repeatbtn = 2;
iap_remotetick = false;
iap_changedctr = 1;
}
}
if(serbuf[4] & 2) /* pause */
{
if (audio_status() == AUDIO_STATUS_PLAY)
{
iap_remotebtn |= BUTTON_RC_PLAY;
iap_repeatbtn = 2;
iap_remotetick = false;
iap_changedctr = 1;
}
}
if((serbuf[4] & 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(serbuf[0] >= 5 && serbuf[5] != 0)
{
if((serbuf[5] & 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(serbuf[5] & 16) /* ffwd */
{
iap_remotebtn |= BUTTON_RC_RIGHT;
}
if(serbuf[5] & 32) /* frwd */
{
iap_remotebtn |= BUTTON_RC_LEFT;
}
}
}
/* Handle Mode 3 */
else if (serbuf[1] == 0x03)
{
switch(serbuf[2])
{
/* some kind of status packet? */
case 0x01:
{
unsigned char data[] = {0x03, 0x02, 0x00, 0x00, 0x00, 0x00};
iap_send_pkt(data, sizeof(data));
break;
}
case 0x08:
{
/* ACK */
unsigned char data[] = {0x03, 0x00, 0x00, 0x08};
iap_send_pkt(data, sizeof(data));
break;
}
case 0x0C:
{
/* request ipod volume */
if (serbuf[3] == 0x04)
{
iap_set_remote_volume();
}
break;
}
/* get volume from accessory */
case 0x0E:
if (serbuf[3] == 0x04)
global_settings.volume = (-58)+((int)serbuf[5]+1)/4;
sound_set_volume(global_settings.volume);
break;
}
}
/* Handle Mode 4 */
else if (serbuf[1] == 0x04)
{
switch (((unsigned long)serbuf[2] << 8) | serbuf[3])
{
/* Get data updated??? flag */
case 0x0009:
{
unsigned char data[] = {0x04, 0x00, 0x0A, 0x00};
data[3] = iap_updateflag ? 0 : 1;
iap_send_pkt(data, sizeof(data));
break;
}
/* Set data updated??? flag */
case 0x000B:
{
iap_updateflag = serbuf[4] ? 0 : 1;
/* respond with cmd ok packet */
unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x0B};
iap_send_pkt(data, sizeof(data));
break;
}
/* Get iPod size? */
case 0x0012:
{
unsigned char data[] = {0x04, 0x00, 0x13, 0x01, 0x0B};
iap_send_pkt(data, sizeof(data));
break;
}
/* Get count of given types */
case 0x0018:
{
unsigned char data[] = {0x04, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00};
unsigned long num = 0;
switch(serbuf[4]) /* type number */
{
case 0x01: /* total number of playlists */
num = 1;
break;
case 0x05: /* total number of songs */
num = 1;
}
data[3] = num >> 24;
data[4] = num >> 16;
data[5] = num >> 8;
data[6] = num;
iap_send_pkt(data, sizeof(data));
break;
}
/* Get time and status */
case 0x001C:
{
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();
data[3] = time_total >> 24;
data[4] = time_total >> 16;
data[5] = time_total >> 8;
data[6] = time_total;
data[7] = time_elapsed >> 24;
data[8] = time_elapsed >> 16;
data[9] = time_elapsed >> 8;
data[10] = 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;
}
/* Get current pos in playlist */
case 0x001E:
{
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();
data[3] = playlist_pos >> 24;
data[4] = playlist_pos >> 16;
data[5] = playlist_pos >> 8;
data[6] = playlist_pos;
iap_send_pkt(data, sizeof(data));
break;
}
/* Get title of a song number */
case 0x0020:
/* Get artist of a song number */
case 0x0022:
/* Get album of a song number */
case 0x0024:
{
unsigned char data[70] = {0x04, 0x00, 0xFF};
struct mp3entry id3;
int fd;
size_t len;
long tracknum = (signed long)serbuf[4] << 24 |
(signed long)serbuf[5] << 16 |
(signed long)serbuf[6] << 8 | serbuf[7];
data[2] = serbuf[3] + 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(serbuf[3])
{
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;
}
/* Set polling mode */
case 0x0026:
{
iap_pollspeed = serbuf[4] ? 1 : 0;
/*responsed with cmd ok packet */
unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x26};
iap_send_pkt(data, sizeof(data));
break;
}
/* AiR playback control */
case 0x0029:
{
/* respond with cmd ok packet */
unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x29};
iap_send_pkt(data, sizeof(data));
switch(serbuf[4])
{
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;
}
break;
}
/* Get shuffle mode */
case 0x002C:
{
unsigned char data[] = {0x04, 0x00, 0x2D, 0x00};
data[3] = global_settings.playlist_shuffle ? 1 : 0;
iap_send_pkt(data, sizeof(data));
break;
}
/* Set shuffle mode */
case 0x002E:
{
if(serbuf[4] && !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(!serbuf[4] && 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 */
unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x2E};
iap_send_pkt(data, sizeof(data));
break;
}
/* Get repeat mode */
case 0x002F:
{
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;
}
/* Set repeat mode */
case 0x0031:
{
int oldmode = global_settings.repeat_mode;
if (serbuf[4] == 0)
global_settings.repeat_mode = REPEAT_OFF;
else if (serbuf[4] == 1)
global_settings.repeat_mode = REPEAT_ONE;
else if (serbuf[4] == 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 */
unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x31};
iap_send_pkt(data, sizeof(data));
break;
}
/* Get Max Screen Size for Picture Upload??? */
case 0x0033:
{
unsigned char data[] = {0x04, 0x00, 0x34, 0x01, 0x36, 0x00, 0xA8, 0x01};
iap_send_pkt(data, sizeof(data));
break;
}
/* Get number songs in current playlist */
case 0x0035:
{
unsigned char data[] = {0x04, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00};
unsigned long playlist_amt = playlist_amount();
data[3] = playlist_amt >> 24;
data[4] = playlist_amt >> 16;
data[5] = playlist_amt >> 8;
data[6] = playlist_amt;
iap_send_pkt(data, sizeof(data));
break;
}
/* Jump to track number in current playlist */
case 0x0037:
{
int paused = (is_wps_fading() || (audio_status() & AUDIO_STATUS_PAUSE));
long tracknum = (signed long)serbuf[4] << 24 |
(signed long)serbuf[5] << 16 |
(signed long)serbuf[6] << 8 | serbuf[7];
audio_pause();
audio_skip(tracknum - playlist_next(0));
if (!paused)
audio_resume();
/* respond with cmd ok packet */
unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x00};
data[4] = serbuf[2];
data[5] = serbuf[3];
iap_send_pkt(data, sizeof(data));
break;
}
default:
{
/* default response is with cmd ok packet */
unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x00};
data[4] = serbuf[2];
data[5] = serbuf[3];
iap_send_pkt(data, sizeof(data));
break;
}
}
}
/* Handle Mode 7 */
else if (serbuf[1] == 0x07)
{
switch(serbuf[2])
{
/* tuner capabilities */
case 0x02:
{
/* do nothing */
unsigned char data[] = {0x00, 0x27, 0x00};
iap_send_pkt(data, sizeof(data));
break;
}
/* actual tuner frequency */
case 0x0A:
/* fall through */
/* tuner frequency from scan */
case 0x13:
{
rmt_tuner_freq();
break;
}
/* RDS station name 0x21 1E 00 + ASCII text*/
case 0x21:
{
rmt_tuner_rds_data();
break;
}
}
}
serbuf[0] = 0;
}
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;
}