int CheckUpgrade(void) { struct _header h; // check if the firmware is there SPI_FLASH_BufferRead((void*)&h, FIRMWARE_BASE, sizeof(h)); if (h.signature != SIGNATURE) return 0; printf("Found firmware, length = %lu\n", h.length); SPI_FLASH_BufferRead((void*)&h, FIRMWARE_BASE + h.length + sizeof(h), sizeof(h)); if (h.signature != SIGNATURE) return 1; SPI_FLASH_BufferRead((void*)&h, FIRMWARE_BASE + h.length + 2 * sizeof(h), sizeof(h)); if (h.signature == SIGNATURE) return 2; // ignore flag if (battery_state() == BATTERY_STATE_DISCHARGING && battery_level(BATTERY_STATE_DISCHARGING) < 4) return 3; // not enough power // check CRC return 0xff; }
/** * get_menu_selection() * */ int get_menu_selection(char** headers, char** items, int menu_only, int initial_selection) { // throw away keys pressed previously, so user doesn't // accidentally trigger menu items. ui_clear_key_queue(); ui_start_menu(headers, items, initial_selection); int selected = initial_selection; int chosen_item = -1; while (chosen_item < 0) { #ifdef BOARD_WITH_CPCAP int level = battery_level(); if (level > 0) { if ((50 * progress_value) != level / 2) { progress_value = level / 100.0; if (level < 20) ui_print("Low battery ! %3d %%\n", level); ui_reset_progress(); ui_show_progress(progress_value, 1); ui_set_progress(1.0); } } #endif int key = ui_wait_key(); int visible = ui_text_visible(); int action = device_handle_key(key, visible); if (action < 0) { switch (action) { case HIGHLIGHT_UP: --selected; selected = ui_menu_select(selected); break; case HIGHLIGHT_DOWN: ++selected; selected = ui_menu_select(selected); break; case SELECT_ITEM: chosen_item = selected; break; case ACTION_CANCEL: chosen_item = GO_BACK; break; case NO_ACTION: break; } } else if (!menu_only) { chosen_item = action; } } ui_end_menu(); return chosen_item; }
/* battery is between 3.7 to 4.2 4.2 => 2.1 / 2.5 * 255 = 214 3.7 => 1.86 / 2.5 * 255 = 189 */ static void check_battery() { //uint8_t report = 0; // update battery status BATTERY_STATE state = battery_state(); uint8_t level = battery_level(state); status &= ~BATTERY_STATUS; switch(level) { case 0: case 1: status |= BATTERY_EMPTY; break; case 2: case 3: status |= BATTERY_LESS; break; case 4: case 5: case 6: status |= BATTERY_MORE; break; default: status |= BATTERY_FULL; } if (window_current() != &charging_process) { if ((level == 0) && (state == BATTERY_STATE_DISCHARGING)) { window_open(&charging_process, 0); } } #ifndef UNITTEST if (window_current() == &menu_process || window_current() == &analogclock_process || window_current() == &digitclock_process) { if (state != BATTERY_STATE_DISCHARGING) { window_open(&charging_process, 0); } } #endif if (state == BATTERY_STATE_CHARGING) { status |= BATTERY_CHARGING; level |= 0x10; } hfp_battery(level); }
void gui_statusbar_draw(struct gui_statusbar * bar, bool force_redraw, struct viewport *vp) { struct screen * display = bar->display; if (!display) return; #ifdef HAVE_LCD_CHARCELLS int val; (void)force_redraw; /* The Player always has "redraw" */ (void)vp; #endif /* HAVE_LCD_CHARCELLS */ bar->info.battlevel = battery_level(); #ifdef HAVE_USB_POWER bar->info.usb_inserted = usb_inserted(); #endif #if CONFIG_CHARGING bar->info.inserted = (charger_input_state == CHARGER); if (bar->info.inserted) { bar->info.battery_state = true; #if CONFIG_CHARGING >= CHARGING_MONITOR /* zero battery run time if charging */ if (charge_state > DISCHARGING) lasttime = current_tick; /* animate battery if charging */ if ((charge_state == DISCHARGING) || (charge_state == TRICKLE)) { bar->info.batt_charge_step = -1; } else { #else /* CONFIG_CHARGING < CHARGING_MONITOR */ lasttime = current_tick; { #endif /* CONFIG_CHARGING < CHARGING_MONITOR */ /* animate in (max.) 4 steps, starting near the current charge level */ if (TIME_AFTER(current_tick, bar->battery_icon_switch_tick)) { if (++bar->info.batt_charge_step > 3) bar->info.batt_charge_step = bar->info.battlevel / 34; bar->battery_icon_switch_tick = current_tick + HZ; } } } else #endif /* CONFIG_CHARGING */ {
static void charging_screen(void) { unsigned int button; const char* msg; ide_power_enable(false); /* power down the disk, else would be spinning */ lcd_clear_display(); do { #ifdef ARCHOS_RECORDER if (charge_state == CHARGING) msg = "charging"; else if (charge_state == TOPOFF) msg = "topoff charge"; else if (charge_state == TRICKLE) msg = "trickle charge"; else msg = "not charging"; #else msg = "charging"; #endif lcd_puts(0, 0, msg); { char buf[32]; int battv = battery_voltage(); snprintf(buf, sizeof(buf), "%d.%02dV %d%%", battv / 1000, (battv % 1000) / 10, battery_level()); lcd_puts(0, 1, buf); } lcd_update(); button = button_get_w_tmo(HZ/2); #ifdef BUTTON_ON if (button == (BUTTON_ON | BUTTON_REL)) #else if (button == (BUTTON_RIGHT | BUTTON_REL)) #endif break; /* start */ else { if (usb_detect() == USB_INSERTED) break; else if (!charger_inserted()) power_off(); /* charger removed: power down */ } } while (1); }
static void charging_display_info(bool animate) { unsigned char charging_logo[36]; const int pox_x = (LCD_WIDTH - sizeof(charging_logo)) / 2; const int pox_y = 32; static unsigned phase = 3; unsigned i; #ifdef NEED_ATA_POWER_BATT_MEASURE if (ide_powered()) /* FM and V2 can only measure when ATA power is on */ #endif { int battv = battery_voltage(); lcd_putsf(0, 7, " Batt: %d.%02dV %d%% ", battv / 1000, (battv % 1000) / 10, battery_level()); } #ifdef ARCHOS_RECORDER lcd_puts(0, 2, "Charge mode:"); const char *s; if (charge_state == CHARGING) s = str(LANG_BATTERY_CHARGE); else if (charge_state == TOPOFF) s = str(LANG_BATTERY_TOPOFF_CHARGE); else if (charge_state == TRICKLE) s = str(LANG_BATTERY_TRICKLE_CHARGE); else s = "not charging"; lcd_puts(0, 3, s); if (!charger_enabled()) animate = false; #endif /* ARCHOS_RECORDER */ /* middle part */ memset(charging_logo+3, 0x00, 32); charging_logo[0] = 0x3C; charging_logo[1] = 0x24; charging_logo[2] = charging_logo[35] = 0xFF; if (!animate) { /* draw the outline */ /* middle part */ lcd_mono_bitmap(charging_logo, pox_x, pox_y + 8, sizeof(charging_logo), 8); lcd_set_drawmode(DRMODE_FG); /* upper line */ charging_logo[0] = charging_logo[1] = 0x00; memset(charging_logo+2, 0x80, 34); lcd_mono_bitmap(charging_logo, pox_x, pox_y, sizeof(charging_logo), 8); /* lower line */ memset(charging_logo+2, 0x01, 34); lcd_mono_bitmap(charging_logo, pox_x, pox_y + 16, sizeof(charging_logo), 8); lcd_set_drawmode(DRMODE_SOLID); } else { /* animate the middle part */ for (i = 3; i<MIN(sizeof(charging_logo)-1, phase); i++) { if ((i-phase) % 8 == 0) { /* draw a "bubble" here */ unsigned bitpos; bitpos = (phase + i/8) % 15; /* "bounce" effect */ if (bitpos > 7) bitpos = 14 - bitpos; charging_logo[i] = BIT_N(bitpos); } } lcd_mono_bitmap(charging_logo, pox_x, pox_y + 8, sizeof(charging_logo), 8); phase++; } lcd_update(); }
void draw_progressbar(struct gui_wps *gwps, int line, struct progressbar *pb) { struct screen *display = gwps->display; struct viewport *vp = pb->vp; struct wps_state *state = skin_get_global_state(); struct mp3entry *id3 = state->id3; int x = pb->x, y = pb->y, width = pb->width, height = pb->height; unsigned long length, end; int flags = HORIZONTAL; if (height < 0) height = font_get(vp->font)->height; if (y < 0) { int line_height = font_get(vp->font)->height; /* center the pb in the line, but only if the line is higher than the pb */ int center = (line_height-height)/2; /* if Y was not set calculate by font height,Y is -line_number-1 */ y = line*line_height + (0 > center ? 0 : center); } if (pb->type == SKIN_TOKEN_VOLUMEBAR) { int minvol = sound_min(SOUND_VOLUME); int maxvol = sound_max(SOUND_VOLUME); length = maxvol-minvol; end = global_settings.volume-minvol; } else if (pb->type == SKIN_TOKEN_BATTERY_PERCENTBAR) { length = 100; end = battery_level(); } else if (pb->type == SKIN_TOKEN_PEAKMETER_LEFTBAR || pb->type == SKIN_TOKEN_PEAKMETER_RIGHTBAR) { int left, right, val; peak_meter_current_vals(&left, &right); val = pb->type == SKIN_TOKEN_PEAKMETER_LEFTBAR ? left : right; length = MAX_PEAK; end = peak_meter_scale_value(val, length); } #if CONFIG_TUNER else if (in_radio_screen() || (get_radio_status() != FMRADIO_OFF)) { #ifdef HAVE_RADIO_RSSI if (pb->type == SKIN_TOKEN_TUNER_RSSI_BAR) { int val = tuner_get(RADIO_RSSI); int min = tuner_get(RADIO_RSSI_MIN); int max = tuner_get(RADIO_RSSI_MAX); end = val - min; length = max - min; } else #endif { int min = fm_region_data[global_settings.fm_region].freq_min; end = radio_current_frequency() - min; length = fm_region_data[global_settings.fm_region].freq_max - min; } } #endif else if (id3 && id3->length) { length = id3->length; end = id3->elapsed + state->ff_rewind_count; } else { length = 1; end = 0; } if (!pb->horizontal) { /* we want to fill upwards which is technically inverted. */ flags = INVERTFILL; } if (pb->invert_fill_direction) { flags ^= INVERTFILL; } if (pb->nofill) { flags |= INNER_NOFILL; } if (pb->slider) { struct gui_img *img = pb->slider; /* clear the slider */ screen_clear_area(display, x, y, width, height); /* shrink the bar so the slider is inside bounds */ if (flags&HORIZONTAL) { width -= img->bm.width; x += img->bm.width / 2; } else { height -= img->bm.height; y += img->bm.height / 2; } } if (pb->backdrop) { struct gui_img *img = pb->backdrop; #if LCD_DEPTH > 1 if(img->bm.format == FORMAT_MONO) { #endif display->mono_bitmap_part(img->bm.data, 0, 0, img->bm.width, x, y, width, height); #if LCD_DEPTH > 1 } else { display->transparent_bitmap_part((fb_data *)img->bm.data, 0, 0, STRIDE(display->screen_type, img->bm.width, img->bm.height), x, y, width, height); } #endif flags |= DONT_CLEAR_EXCESS; } if (!pb->nobar) { if (pb->image) gui_bitmap_scrollbar_draw(display, &pb->image->bm, x, y, width, height, length, 0, end, flags); else gui_scrollbar_draw(display, x, y, width, height, length, 0, end, flags); } if (pb->slider) { int xoff = 0, yoff = 0; int w = width, h = height; struct gui_img *img = pb->slider; if (flags&HORIZONTAL) { w = img->bm.width; xoff = width * end / length; if (flags&INVERTFILL) xoff = width - xoff; xoff -= w / 2; } else { h = img->bm.height; yoff = height * end / length; if (flags&INVERTFILL) yoff = height - yoff; yoff -= h / 2; } #if LCD_DEPTH > 1 if(img->bm.format == FORMAT_MONO) { #endif display->mono_bitmap_part(img->bm.data, 0, 0, img->bm.width, x + xoff, y + yoff, w, h); #if LCD_DEPTH > 1 } else { display->transparent_bitmap_part((fb_data *)img->bm.data, 0, 0, STRIDE(display->screen_type, img->bm.width, img->bm.height), x + xoff, y + yoff, w, h); } #endif } if (pb->type == SKIN_TOKEN_PROGRESSBAR) { if (id3 && id3->length) { #ifdef AB_REPEAT_ENABLE if (ab_repeat_mode_enabled()) ab_draw_markers(display, id3->length, x, y, width, height); #endif if (id3->cuesheet) cue_draw_markers(display, id3->cuesheet, id3->length, x, y+1, width, height-2); } #if 0 /* disable for now CONFIG_TUNER */ else if (in_radio_screen() || (get_radio_status() != FMRADIO_OFF)) { presets_draw_markers(display, x, y, width, height); } #endif } }
/* Monitor remote hotswap */ static void remote_tick(void) { unsigned char i; int bat_level; static unsigned char pause_length=0; if(remote_state_control!=REMOTE_CONTROL_DRAW && remote_state_control!=REMOTE_CONTROL_IDLE) { remote_state_control=remote_state_control_next; remote_state_control_next=REMOTE_CONTROL_MASK; } switch (remote_state_control) { case REMOTE_CONTROL_IDLE: /* State machine never leaves idle unless remote_state_control is * manually set. */ remote_payload_size=0; remote_state_control=REMOTE_CONTROL_IDLE; break; case REMOTE_CONTROL_NOP: remote_payload[0]=0x11; remote_payload[1]=0x30; remote_payload_size=2; remote_state_control=REMOTE_CONTROL_MASK; break; case REMOTE_CONTROL_POWER: remote_payload[0]=0x31; remote_payload[1]=remote_power; remote_payload[2]=remote_contrast; remote_payload_size=3; remote_state_control=REMOTE_CONTROL_MASK; break; case REMOTE_CONTROL_MASK: bat_level=battery_level()>>5; remote_payload[1]=0; if(bat_level&0x02) { remote_payload[1] |= 0x07 << 5; } else if(bat_level&0x01) { remote_payload[1] |= 0x03 << 5; } else { remote_payload[1] |= 0x01 << 5; } remote_payload[1]|=1<<4; remote_payload[0]=0x41; remote_payload_size=2; remote_state_control=REMOTE_CONTROL_MASK; break; case REMOTE_CONTROL_DRAW: remote_payload[0]=0x51; remote_payload[1]=0x80; remote_payload[2]=remote_draw_width; remote_payload[3]=remote_draw_x; remote_payload[5]=remote_draw_x+remote_draw_width; remote_payload_size=7+remote_payload[2]; switch (remote_state_draw) { case DRAW_TOP: remote_payload[4]=0; remote_payload[6]=8; pause_length=6; remote_state_draw_next=DRAW_BOTTOM; remote_state_draw=DRAW_PAUSE; break; case DRAW_BOTTOM: remote_payload[4]=8; remote_payload[6]=16; pause_length=6; remote_state_draw_next=DRAW_TOP; remote_state_draw=DRAW_PAUSE; break; case DRAW_PAUSE: remote_payload_size=0; if(--pause_length==0) { if(remote_state_draw_next==DRAW_TOP) remote_state_control=REMOTE_CONTROL_MASK; remote_state_draw=remote_state_draw_next; } else remote_state_draw=DRAW_PAUSE; break; default: remote_payload_size=0; break; } break; case REMOTE_CONTROL_SLEEP: remote_payload[0]=0x71; remote_payload[1]=0x30; remote_payload_size=2; remote_state_control=REMOTE_CONTROL_IDLE; break; default: remote_payload_size=0; break; } if(remote_payload_size==0) { return; } if(remote_payload[0]==0x51) { for(i=7; i<remote_payload_size; i++) { remote_payload[i]= *FBREMOTEADDR(i+remote_draw_x-7, remote_payload[4]>>3); } } /* Calculate the xor and sum to place in the payload */ remote_payload[remote_payload_size]=remote_payload[0]; remote_payload[remote_payload_size+1]=remote_payload[0]; for(i=1; i<remote_payload_size; i++) { remote_payload[remote_payload_size]^=remote_payload[i]; remote_payload[remote_payload_size+1]+=remote_payload[i]; } uart1_puts(remote_payload, remote_payload_size+2); }
static bool clean_shutdown(void (*callback)(void *), void *parameter) { #ifdef SIMULATOR (void)callback; (void)parameter; bookmark_autobookmark(); call_storage_idle_notifys(true); exit(0); #else long msg_id = -1; int i; scrobbler_poweroff(); #if CONFIG_CHARGING && !defined(HAVE_POWEROFF_WHILE_CHARGING) if(!charger_inserted()) #endif { bool batt_safe = battery_level_safe(); int audio_stat = audio_status(); FOR_NB_SCREENS(i) { screens[i].clear_display(); screens[i].update(); } if (batt_safe) { #ifdef HAVE_TAGCACHE if (!tagcache_prepare_shutdown()) { cancel_shutdown(); splash(HZ, ID2P(LANG_TAGCACHE_BUSY)); return false; } #endif if (battery_level() > 10) splash(0, str(LANG_SHUTTINGDOWN)); else { msg_id = LANG_WARNING_BATTERY_LOW; splashf(0, "%s %s", str(LANG_WARNING_BATTERY_LOW), str(LANG_SHUTTINGDOWN)); } } else { msg_id = LANG_WARNING_BATTERY_EMPTY; splashf(0, "%s %s", str(LANG_WARNING_BATTERY_EMPTY), str(LANG_SHUTTINGDOWN)); } if (global_settings.fade_on_stop && (audio_stat & AUDIO_STATUS_PLAY)) { fade(false, false); } if (batt_safe) /* do not save on critical battery */ { #if defined(HAVE_RECORDING) && CONFIG_CODEC == SWCODEC if (audio_stat & AUDIO_STATUS_RECORD) { rec_command(RECORDING_CMD_STOP); /* wait for stop to complete */ while (audio_status() & AUDIO_STATUS_RECORD) sleep(1); } #endif bookmark_autobookmark(); /* audio_stop_recording == audio_stop for HWCODEC */ audio_stop(); if (callback != NULL) callback(parameter); #if CONFIG_CODEC != SWCODEC /* wait for audio_stop or audio_stop_recording to complete */ while (audio_status()) sleep(1); #endif #if defined(HAVE_RECORDING) && CONFIG_CODEC == SWCODEC audio_close_recording(); #endif if(global_settings.talk_menu) { bool enqueue = false; if(msg_id != -1) { talk_id(msg_id, enqueue); enqueue = true; } talk_id(LANG_SHUTTINGDOWN, enqueue); #if CONFIG_CODEC == SWCODEC voice_wait(); #endif } system_flush(); #ifdef HAVE_EEPROM_SETTINGS if (firmware_settings.initialized) { firmware_settings.disk_clean = true; firmware_settings.bl_version = 0; eeprom_settings_store(); } #endif } #ifdef HAVE_DIRCACHE else dircache_disable(); #endif shutdown_hw(); }
void draw_progressbar(struct gui_wps *gwps, int line, struct progressbar *pb) { struct screen *display = gwps->display; struct viewport *vp = SKINOFFSETTOPTR(get_skin_buffer(gwps->data), pb->vp); struct wps_state *state = skin_get_global_state(); struct mp3entry *id3 = state->id3; int x = pb->x, y = pb->y, width = pb->width, height = pb->height; unsigned long length, end; int flags = HORIZONTAL; if (height < 0) height = font_get(vp->font)->height; if (y < 0) { int line_height = font_get(vp->font)->height; /* center the pb in the line, but only if the line is higher than the pb */ int center = (line_height-height)/2; /* if Y was not set calculate by font height,Y is -line_number-1 */ y = line*line_height + (0 > center ? 0 : center); } if (pb->type == SKIN_TOKEN_VOLUMEBAR) { int minvol = sound_min(SOUND_VOLUME); int maxvol = sound_max(SOUND_VOLUME); length = maxvol-minvol; end = global_settings.volume-minvol; } else if (pb->type == SKIN_TOKEN_BATTERY_PERCENTBAR) { length = 100; end = battery_level(); } else if (pb->type == SKIN_TOKEN_PEAKMETER_LEFTBAR || pb->type == SKIN_TOKEN_PEAKMETER_RIGHTBAR) { int left, right, val; peak_meter_current_vals(&left, &right); val = pb->type == SKIN_TOKEN_PEAKMETER_LEFTBAR ? left : right; length = MAX_PEAK; end = peak_meter_scale_value(val, length); } else if (pb->type == SKIN_TOKEN_LIST_SCROLLBAR) { int val, min, max; skinlist_get_scrollbar(&val, &min, &max); end = val - min; length = max - min; } else if (pb->type == SKIN_TOKEN_SETTINGBAR) { int val, count; get_setting_info_for_bar(pb->setting_id, &count, &val); length = count - 1; end = val; } #if CONFIG_TUNER else if (in_radio_screen() || (get_radio_status() != FMRADIO_OFF)) { #ifdef HAVE_RADIO_RSSI if (pb->type == SKIN_TOKEN_TUNER_RSSI_BAR) { int val = tuner_get(RADIO_RSSI); int min = tuner_get(RADIO_RSSI_MIN); int max = tuner_get(RADIO_RSSI_MAX); end = val - min; length = max - min; } else #endif { int min = fm_region_data[global_settings.fm_region].freq_min; end = radio_current_frequency() - min; length = fm_region_data[global_settings.fm_region].freq_max - min; } } #endif else if (id3 && id3->length) { length = id3->length; end = id3->elapsed + state->ff_rewind_count; } else { length = 1; end = 0; } if (!pb->horizontal) { /* we want to fill upwards which is technically inverted. */ flags = INVERTFILL; } if (pb->invert_fill_direction) { flags ^= INVERTFILL; } if (pb->nofill) { flags |= INNER_NOFILL; } if (SKINOFFSETTOPTR(get_skin_buffer(gwps->data), pb->slider)) { struct gui_img *img = SKINOFFSETTOPTR(get_skin_buffer(gwps->data), pb->slider); /* clear the slider */ screen_clear_area(display, x, y, width, height); /* account for the sliders width in the progressbar */ if (flags&HORIZONTAL) { width -= img->bm.width; } else { height -= img->bm.height; } } if (SKINOFFSETTOPTR(get_skin_buffer(gwps->data), pb->backdrop)) { struct gui_img *img = SKINOFFSETTOPTR(get_skin_buffer(gwps->data), pb->backdrop); img->bm.data = core_get_data(img->buflib_handle); display->bmp_part(&img->bm, 0, 0, x, y, pb->width, height); flags |= DONT_CLEAR_EXCESS; } if (!pb->nobar) { struct gui_img *img = SKINOFFSETTOPTR(get_skin_buffer(gwps->data), pb->image); if (img) { char *img_data = core_get_data(img->buflib_handle); img->bm.data = img_data; gui_bitmap_scrollbar_draw(display, &img->bm, x, y, width, height, length, 0, end, flags); } else gui_scrollbar_draw(display, x, y, width, height, length, 0, end, flags); } if (SKINOFFSETTOPTR(get_skin_buffer(gwps->data), pb->slider)) { int xoff = 0, yoff = 0; int w = width, h = height; struct gui_img *img = SKINOFFSETTOPTR(get_skin_buffer(gwps->data), pb->slider); img->bm.data = core_get_data(img->buflib_handle); if (flags&HORIZONTAL) { w = img->bm.width; xoff = width * end / length; if (flags&INVERTFILL) xoff = width - xoff; } else { h = img->bm.height; yoff = height * end / length; if (flags&INVERTFILL) yoff = height - yoff; } display->bmp_part(&img->bm, 0, 0, x + xoff, y + yoff, w, h); } if (pb->type == SKIN_TOKEN_PROGRESSBAR) { if (id3 && id3->length) { #ifdef AB_REPEAT_ENABLE if (ab_repeat_mode_enabled()) ab_draw_markers(display, id3->length, x, y, width, height); #endif if (id3->cuesheet) cue_draw_markers(display, id3->cuesheet, id3->length, x, y+1, width, height-2); } #if 0 /* disable for now CONFIG_TUNER */ else if (in_radio_screen() || (get_radio_status() != FMRADIO_OFF)) { presets_draw_markers(display, x, y, width, height); } #endif } }