blob: 00f8c5e1fe336665c040178a1ffa04ddd9e12849 [file] [log] [blame]
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2002 by Linus Nielsen Feltzing
*
* 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 "string.h"
#include "lcd.h"
#include "debug.h"
#include "kernel.h"
#include "power.h"
#include "thread.h"
#include "settings.h"
#include "status.h"
#include "mp3_playback.h"
#include "audio.h"
#include "gwps.h"
#include "abrepeat.h"
#ifdef HAVE_RTC
#include "timefuncs.h"
#endif
#ifdef HAVE_LCD_BITMAP
#include "icons.h"
#include "font.h"
#endif
#include "powermgmt.h"
#include "led.h"
#include "sound.h"
#if CONFIG_KEYPAD == IRIVER_H100_PAD
#include "button.h"
#endif
#include "usb.h"
#ifdef CONFIG_TUNER
#include "radio.h"
#endif
enum playmode ff_mode;
long switch_tick;
bool battery_state = true;
#ifdef HAVE_CHARGING
int battery_charge_step = 0;
#endif
struct status_info {
int battlevel;
int volume;
int hour;
int minute;
int playmode;
int repeat;
bool inserted;
bool shuffle;
bool keylock;
bool battery_safe;
bool redraw_volume; /* true if the volume gauge needs updating */
#if CONFIG_LED == LED_VIRTUAL
bool led; /* disk LED simulation in the status bar */
#endif
#ifdef HAVE_USB_POWER
bool usb_power;
#endif
};
void status_init(void)
{
ff_mode = 0;
}
void status_set_ffmode(enum playmode mode)
{
ff_mode = mode; /* Either STATUS_FASTFORWARD or STATUS_FASTBACKWARD */
status_draw(false);
}
enum playmode status_get_ffmode(void)
{
/* only use this function for STATUS_FASTFORWARD or STATUS_FASTBACKWARD */
/* use audio_status() for other modes */
return ff_mode;
}
int current_playmode(void)
{
int audio_stat = audio_status();
/* ff_mode can be either STATUS_FASTFORWARD or STATUS_FASTBACKWARD
and that supercedes the other modes */
if(ff_mode)
return ff_mode;
if(audio_stat & AUDIO_STATUS_PLAY)
{
if(audio_stat & AUDIO_STATUS_PAUSE)
return STATUS_PAUSE;
else
return STATUS_PLAY;
}
#if CONFIG_CODEC == MAS3587F
else
{
if(audio_stat & AUDIO_STATUS_RECORD)
{
if(audio_stat & AUDIO_STATUS_PAUSE)
return STATUS_RECORD_PAUSE;
else
return STATUS_RECORD;
}
}
#endif
#ifdef CONFIG_TUNER
audio_stat = get_radio_status();
if(audio_stat == FMRADIO_PLAYING)
return STATUS_RADIO;
if(audio_stat == FMRADIO_PAUSED)
return STATUS_RADIO_PAUSE;
#endif
return STATUS_STOP;
}
#if defined(HAVE_LCD_CHARCELLS)
bool record = false;
bool audio = false;
bool param = false;
bool usb = false;
void status_set_record(bool b)
{
record = b;
}
void status_set_audio(bool b)
{
audio = b;
}
void status_set_param(bool b)
{
param = b;
}
void status_set_usb(bool b)
{
usb = b;
}
#endif /* HAVE_LCD_CHARCELLS */
void status_draw(bool force_redraw)
{
/* This is static because we use memcmp() below to check for changes, and
the unused bytes (due to struct member alignment) might change if
the struct is allocated on the stack. */
static struct status_info info;
#ifdef HAVE_LCD_BITMAP
static struct status_info lastinfo;
struct tm* tm;
if ( !global_settings.statusbar )
return;
#else
(void)force_redraw; /* players always "redraw" */
#endif
info.volume = sound_val2phys(SOUND_VOLUME, global_settings.volume);
info.inserted = charger_inserted();
info.battlevel = battery_level();
info.battery_safe = battery_level_safe();
#ifdef HAVE_LCD_BITMAP
tm = get_time();
info.hour = tm->tm_hour;
info.minute = tm->tm_min;
info.shuffle = global_settings.playlist_shuffle;
#if CONFIG_KEYPAD == IRIVER_H100_PAD
info.keylock = button_hold();
#else
info.keylock = keys_locked;
#endif
info.repeat = global_settings.repeat_mode;
info.playmode = current_playmode();
#if CONFIG_LED == LED_VIRTUAL
info.led = led_read(HZ/2); /* delay should match polling interval */
#endif
#ifdef HAVE_USB_POWER
info.usb_power = usb_powered();
#endif
/* only redraw if forced to, or info has changed */
if (force_redraw ||
info.inserted ||
!info.battery_safe ||
info.redraw_volume ||
memcmp(&info, &lastinfo, sizeof(struct status_info)))
{
lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
lcd_fillrect(0,0,LCD_WIDTH,8);
lcd_set_drawmode(DRMODE_SOLID);
#else
/* players always "redraw" */
{
#endif
#ifdef HAVE_CHARGING
if (info.inserted) {
battery_state = true;
#if defined(HAVE_CHARGE_CTRL) || CONFIG_BATTERY == BATT_LIION2200
/* zero battery run time if charging */
if (charge_state > 0) {
global_settings.runtime = 0;
lasttime = current_tick;
}
/* animate battery if charging */
if ((charge_state == 1) ||
(charge_state == 2)) {
#else
global_settings.runtime = 0;
lasttime = current_tick;
{
#endif
/* animate in three steps (34% per step for a better look) */
info.battlevel = battery_charge_step * 34;
if (info.battlevel > 100)
info.battlevel = 100;
if(TIME_AFTER(current_tick, switch_tick)) {
battery_charge_step=(battery_charge_step+1)%4;
switch_tick = current_tick + HZ;
}
}
}
else
#endif /* HAVE_CHARGING */
{
if (info.battery_safe)
battery_state = true;
else {
/* blink battery if level is low */
if(TIME_AFTER(current_tick, switch_tick) &&
(info.battlevel > -1)) {
switch_tick = current_tick+HZ;
battery_state =! battery_state;
}
}
}
#ifdef HAVE_LCD_BITMAP
if (battery_state)
statusbar_icon_battery(info.battlevel);
/* draw power plug if charging */
if (info.inserted)
lcd_mono_bitmap(bitmap_icons_7x8[Icon_Plug], ICON_PLUG_X_POS,
STATUSBAR_Y_POS, ICON_PLUG_WIDTH, STATUSBAR_HEIGHT);
#ifdef HAVE_USB_POWER
else if (info.usb_power)
lcd_mono_bitmap(bitmap_icons_7x8[Icon_USBPlug], ICON_PLUG_X_POS,
STATUSBAR_Y_POS, ICON_PLUG_WIDTH, STATUSBAR_HEIGHT);
#endif
info.redraw_volume = statusbar_icon_volume(info.volume);
statusbar_icon_play_state(current_playmode() + Icon_Play);
switch (info.repeat) {
#ifdef AB_REPEAT_ENABLE
case REPEAT_AB:
statusbar_icon_play_mode(Icon_RepeatAB);
break;
#endif
case REPEAT_ONE:
statusbar_icon_play_mode(Icon_RepeatOne);
break;
case REPEAT_ALL:
case REPEAT_SHUFFLE:
statusbar_icon_play_mode(Icon_Repeat);
break;
}
if (info.shuffle)
statusbar_icon_shuffle();
if (info.keylock)
statusbar_icon_lock();
#ifdef HAVE_RTC
statusbar_time(info.hour, info.minute);
#endif
#if CONFIG_LED == LED_VIRTUAL
if (info.led)
statusbar_led();
#endif
lcd_update_rect(0, 0, LCD_WIDTH, STATUSBAR_HEIGHT);
lastinfo = info;
#endif
}
#if defined(HAVE_LCD_CHARCELLS)
if (info.battlevel > -1)
lcd_icon(ICON_BATTERY, battery_state);
lcd_icon(ICON_BATTERY_1, info.battlevel > 25);
lcd_icon(ICON_BATTERY_2, info.battlevel > 50);
lcd_icon(ICON_BATTERY_3, info.battlevel > 75);
lcd_icon(ICON_VOLUME, true);
lcd_icon(ICON_VOLUME_1, info.volume > 10);
lcd_icon(ICON_VOLUME_2, info.volume > 30);
lcd_icon(ICON_VOLUME_3, info.volume > 50);
lcd_icon(ICON_VOLUME_4, info.volume > 70);
lcd_icon(ICON_VOLUME_5, info.volume > 90);
lcd_icon(ICON_PLAY, current_playmode() == STATUS_PLAY);
lcd_icon(ICON_PAUSE, current_playmode() == STATUS_PAUSE);
lcd_icon(ICON_REPEAT, global_settings.repeat_mode != REPEAT_OFF);
lcd_icon(ICON_1, global_settings.repeat_mode == REPEAT_ONE);
lcd_icon(ICON_RECORD, record);
lcd_icon(ICON_AUDIO, audio);
lcd_icon(ICON_PARAM, param);
lcd_icon(ICON_USB, usb);
#endif
}
#if defined(HAVE_LCD_BITMAP) && (CONFIG_KEYPAD == RECORDER_PAD)
static void draw_buttonbar_btn(int num, const char* caption)
{
int xpos, ypos, button_width, text_width;
int fw, fh;
lcd_setfont(FONT_SYSFIXED);
lcd_getstringsize("M", &fw, &fh);
button_width = LCD_WIDTH/3;
xpos = num * button_width;
ypos = LCD_HEIGHT - fh;
if(caption)
{
/* center the text */
text_width = fw * strlen(caption);
lcd_putsxy(xpos + (button_width - text_width)/2, ypos, caption);
}
lcd_set_drawmode(DRMODE_COMPLEMENT);
lcd_fillrect(xpos, ypos, button_width - 1, fh);
lcd_set_drawmode(DRMODE_SOLID);
}
static char stored_caption1[8];
static char stored_caption2[8];
static char stored_caption3[8];
void buttonbar_set(const char* caption1, const char *caption2,
const char *caption3)
{
buttonbar_unset();
if(caption1)
{
strncpy(stored_caption1, caption1, 7);
stored_caption1[7] = 0;
}
if(caption2)
{
strncpy(stored_caption2, caption2, 7);
stored_caption2[7] = 0;
}
if(caption3)
{
strncpy(stored_caption3, caption3, 7);
stored_caption3[7] = 0;
}
}
void buttonbar_unset(void)
{
stored_caption1[0] = 0;
stored_caption2[0] = 0;
stored_caption3[0] = 0;
}
void buttonbar_draw(void)
{
lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
lcd_fillrect(0, LCD_HEIGHT-8, LCD_WIDTH, 8);
lcd_set_drawmode(DRMODE_SOLID);
draw_buttonbar_btn(0, stored_caption1);
draw_buttonbar_btn(1, stored_caption2);
draw_buttonbar_btn(2, stored_caption3);
}
bool buttonbar_isset(void)
{
/* If all buttons are unset, the button bar is considered disabled */
return (global_settings.buttonbar &&
((stored_caption1[0] != 0) ||
(stored_caption2[0] != 0) ||
(stored_caption3[0] != 0)));
}
#endif