/** * Change current media selection * \param media Media to select */ void media_select(enum media_types media) { if (media_selection == media) { return; } media_dbgp("media select: %s\r\n", media_get_type_str(media)); if (media_connected) { media_disconnect(); } media_selection = media; }
/** * Boot information edit * \param info Pointer to region information block */ static void _app_info_edit(struct regions_info *info) { uint32_t i, input_size = 1, input_flags = DBGIN_ECHO_ON; uint8_t menu = 0; bool wait_input = false; int rc; ioport_set_pin_dir(DBG_INFO_EDIT_TRIGGER_PIN, IOPORT_DIR_INPUT); if (!DBG_INFO_EDIT_TRIGGER_PIN_ACTIVE == ioport_get_pin_level(DBG_INFO_EDIT_TRIGGER_PIN)) { return; } while (1) { if (wait_input) { rc = _app_dbg_input(input_buf, input_size, input_flags); switch (menu) { case 1: /* Select boot mode */ if (input_buf[0] >= '0' && input_buf[0] < ('0' + TRIGGER_NUM_MAX)) { int new_trig = input_buf[0] - '0'; dbg_print("\r\n"); dbg_print( "- Trigger: %d, %s -> %d, %s\r\n", (int)info->trigger, trigger_get_mode_str(( enum trigger_modes) info ->trigger), new_trig, trigger_get_mode_str(( enum trigger_modes) new_trig)); info->trigger = input_buf[0] - '0'; /* Return to default menu */ menu = 0; wait_input = false; } else { /* Invalid input, wait another */ dbg_putchar(BS); } break; case 2: /* Change boot file */ dbg_print("\r\n"); if (-1 != rc) { dbg_print("- Set file: %s\r\n", input_buf); strcpy(info->boot_file_name, (char *)input_buf); } /* Return to default menu */ menu = 0; wait_input = false; break; default: /* Main menu */ switch (input_buf[0]) { /* Switch to menu */ case '1': case '2': dbg_print("\r\n"); menu = input_buf[0] - '0'; wait_input = false; break; /* Show regions info */ case 'i': case 'I': dbg_print("\r\n"); _app_show_regions_info(info); wait_input = false; break; /* Load regions info */ case 'l': case 'L': region_info_read((void *)INFO_ADDR( true), info); dbg_print("\r\n- Info loaded\r\n"); _app_show_regions_info(info); wait_input = false; break; /* Save regions info */ case 's': case 'S': _app_save_regions_info(info, true); dbg_print("\r\n- Info saved\r\n"); _app_show_regions_info(info); wait_input = false; break; /* Quit edit */ case 'q': case 'Q': dbg_print("\r\n"); return; default: /* Invalid input, wait another */ dbg_putchar(BS); } } } switch (menu) { case 1: /* Select trigger mode */ for (i = 0; i < TRIGGER_NUM_MAX; i++) { dbg_print("= %u: %s\r\n", (unsigned)i, trigger_get_mode_str((enum trigger_modes)i)); } dbg_print("= Current boot mode: %d, %s\r\n", (int)info->trigger, trigger_get_mode_str((enum trigger_modes) info->trigger)); dbg_print("> New mode:"); input_size = 1; input_flags = DBGIN_ECHO_ON | DBGIN_NUM_ONLY; break; case 2: /* Change boot file */ dbg_print("==== Available List ====\r\n"); for (i = 0; i < MEDIA_NUM_MAX; i++) { dbg_print(" - In #%u, %s\r\n", (unsigned)i, media_get_type_str((enum media_types)i)); media_select((enum media_types)i); media_scan_files(false); } dbg_print("= Current file: %s\r\n", info->boot_file_name); dbg_print("> New file:"); input_size = 13; input_flags = DBGIN_ECHO_ON | DBGIN_WANT_ESC | DBGIN_WANT_CR; break; default: dbg_print("\r\n==== Info Edit ====\r\n"); dbg_print(" - 1: Change boot mode\r\n"); dbg_print(" - 2: Change boot file\r\n"); dbg_print(" - i: Show regions information\r\n"); dbg_print(" - l: Load/restore boot information\r\n"); dbg_print(" - s: Save boot information\r\n"); dbg_print(" - q: quit edit\r\n"); input_size = 1; input_flags = DBGIN_ECHO_ON; } wait_input = true; } }
/** * Receive new firmware * * \param info Regions information struct * \param no_partition Use single partition, do not split memory to app + buff * * \return received firmware size */ static uint32_t _app_load(struct regions_info *info, bool no_partition) { void *addr, *info_addr; uint32_t *p_sign, *p_len; uint32_t rx_size; uint32_t target_region; uint32_t i = 0, flags = 0xFF; if (info->boot_region != 0 && info->boot_region != 1) { dbg_print("bl: Boot region information (%d) invalid\r\n", (int)info->boot_region); return 0; } /* Wait media connection */ i = 0; while (i < MEDIA_NUM_MAX) { media_select((enum media_types)i); if (media_connect()) { dbg_print("bl: Source media %s is ready\r\n", media_get_type_str((enum media_types)i)); break; } else if (flags & (1 << i)) { flags &= ~(1 << i); dbg_print("bl: Source media %s not ready\r\n", media_get_type_str((enum media_types)i)); } i++; } target_region = no_partition ? info->boot_region : (!info->boot_region); addr = (void *)APP_START(target_region); info_addr = (void *)INFO_ADDR(false); dbg_print("bl: Load to %x, info @ %x\r\n", (unsigned)addr, (unsigned)info_addr); dbg_print("bl: Unlock download buffer & info area ...\r\n"); memory_unlock(addr, (void *)((uint32_t)addr + APP_CODE_SIZE - 1)); memory_unlock(info_addr, (void *)((uint32_t)info_addr + INFO_SIZE - 1)); dbg_print("bl: Unlock download buffer & info area done\r\n"); dbg_print("bl: Erase download buffer & info area ...\r\n"); memory_erase( addr, APP_CODE_SIZE); memory_erase(info_addr, INFO_SIZE); dbg_print("bl: Erase download buffer & info area done\r\n"); #ifdef DBG_USE_LED _app_led_blink(50, 4); _app_led_on(DBG_LED_PIN); #endif /* Clear SW force boot trigger */ #ifdef TRIGGER_USE_FLAG info->trigger = TRIGGER_BOOT; #endif p_sign = &info->signature[target_region]; p_len = &info->length[target_region]; rx_size = media_load_file(addr, APP_SIZE, (uint8_t *)app_mem_block_buf, MEM_BLOCK_SIZE, _app_save_block); if (rx_size) { *p_sign = region_signature(addr, rx_size); *p_len = rx_size; } else { *p_sign = 0; *p_len = 0; } /* Save region information */ region_info_write(info_addr, info); dbg_print("bl: Lock download buffer & info area ...\r\n"); memory_lock(addr, (void *)((uint32_t)addr + APP_CODE_SIZE - 1)); memory_lock(info_addr, (void *)((uint32_t)info_addr + INFO_SIZE - 1)); dbg_print("bl: Lock download buffer & info area done\r\n"); #ifdef DBG_USE_LED _app_led_off(DBG_LED_PIN); #endif #if DUMP_ENABLE _dump_data("Downloaded APP:\r\n", addr, rx_size, true); _dump_data("INFO:\r\n", info_addr, INFO_SIZE, true); #endif return rx_size; }