| /*************************************************************************** |
| * __________ __ ___. |
| * 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 |