static void check_device_task(struct state_machine_context *state_m) { Ai_player_flag_t player_flag_temp; static uint32_t old_status = 0; static t_cpu_time get_play_time_timer = { .timer_state = CPU_TIMER_STATE_STOPPED }; // By default, the command executed is asynchronous. state_m->async_cmd = true; switch (state_m->state) { // This state id the entry point of the check device function. case STATE_CHECK_DEVICE_ENTRY_POINT: state_m->cmd_status = true; if (usb_device_get_state() != DEVICE_STATE_READY) { state_m->async_cmd = false; state_m->state = STATE_DEVICE_DISCONNECTED; break; } if( cpu_is_timer_stopped(&get_play_time_timer) ) { cpu_set_timeout(cpu_ms_2_cy(ELAPSED_TIME_TIMER_VALUE_MS, FCPU_HZ), &get_play_time_timer); ai_async_audio_ctrl_status(); state_m->state = STATE_CHECK_DEVICE_UPDATE_STATUS; } else { if( cpu_is_timeout(&get_play_time_timer) ) { cpu_stop_timeout(&get_play_time_timer); } state_m->async_cmd = false; player_flag_temp.all = old_status; update_player_status(state_m, (Ai_player_flag_t *) &player_flag_temp); state_m->state = state_m->recorded_state; } break; // This state update the elapsed time of the current track being played. case STATE_CHECK_DEVICE_UPDATE_STATUS: state_m->async_cmd = false; player_flag_temp.all = ai_async_cmd_out_u32(); update_player_status(state_m, (Ai_player_flag_t *) &player_flag_temp); // The transitional states such as "new file played" can not be kept in the saved status. // Otherwise, we will send during 'ELAPSED_TIME_TIMER_VALUE_MS' second(s) a saved status with // the "new_file_played" event, leading do a full redisplay of the metadata information and audio // cracks. In other words, the saved status needs to keep the states (play/pause/...), not the events. player_flag_temp.new_file_played = 0; player_flag_temp.new_directory = 0; old_status = player_flag_temp.all; state_m->state = state_m->recorded_state; break; default: return; } // Error management if (state_m->cmd_status == false) state_m->state = STATE_DEVICE_DISCONNECTED; }
void *ai_audio_nav_file_info_image(ai_image_size_t *size) { if (!ai_async_audio_nav_file_info_image(size)) return NULL; do { AI_SYNC_TASK_CALL_BACK(); ai_async_cmd_task(); } while( !is_ai_async_cmd_finished() ); return (void *) ai_async_cmd_out_u32(); }
static void track_changed_task(struct state_machine_context *state_m) { // By default, the command executed is asynchronous. state_m->async_cmd = true; Ai_player_flag_t player_flag_temp; switch (state_m->state) { case STATE_TRACK_CHANGED_ENTRY_POINT: memset(&state_m->info, 0, sizeof(struct file_info)); ai_async_audio_nav_file_info_duration(); state_m->state = STATE_TRACK_CHANGED_TOTAL_TIME; break; // Record total time info and call file name. case STATE_TRACK_CHANGED_TOTAL_TIME: state_m->info.total_time = ai_async_cmd_out_u32(); ai_async_audio_nav_getname(); state_m->state = STATE_TRACK_CHANGED_FILE_NAME; break; // Record file name information and call for artist metadata. case STATE_TRACK_CHANGED_FILE_NAME: unicode2ascii((char *) state_m->info.name, (const char *) ai_async_cmd_out_PtrArrayU8(), Min(ai_async_cmd_out_SizeArrayU8(), STR_MAX_LENGTH*2)); ai_async_audio_nav_file_info_artist(); state_m->state = STATE_TRACK_CHANGED_ARTIST; break; // Record artist metadata and call title metadata. case STATE_TRACK_CHANGED_ARTIST: unicode2ascii((char *) state_m->info.artist, (const char *) ai_async_cmd_out_PtrArrayU8(), Min(ai_async_cmd_out_SizeArrayU8(), STR_MAX_LENGTH*2)); ai_async_audio_nav_file_info_title(); state_m->state = STATE_TRACK_CHANGED_TITLE; break; // Record title metadata. case STATE_TRACK_CHANGED_TITLE: unicode2ascii((char *) state_m->info.title, (const char *) ai_async_cmd_out_PtrArrayU8(), Min(ai_async_cmd_out_SizeArrayU8(), STR_MAX_LENGTH*2)); #if defined(SUPPORT_EMBEDDED_COVER_ARTS) && SUPPORT_EMBEDDED_COVER_ARTS == true state_m->info.size.width = 100; state_m->info.size.height = 100; ai_async_audio_nav_file_info_image(&state_m->info.size); state_m->state = STATE_TRACK_CHANGED_IMAGE; #else ai_async_audio_ctrl_status(); state_m->state = STATE_TRACK_CHECK_RESUME; #endif break; // Record image data. case STATE_TRACK_CHANGED_IMAGE: state_m->info.image_data = (void *) ai_async_cmd_out_u32(); ai_async_audio_ctrl_status(); state_m->state = STATE_TRACK_CHECK_RESUME; break; // Resume the track case STATE_TRACK_CHANGED_RESUME: state_m->async_cmd = false; state_m->state = state_m->recorded_state; break; // Check if the device is in pause before sending a ai_async_audio_ctrl_resume() // command. case STATE_TRACK_CHECK_RESUME: player_flag_temp.all = ai_async_cmd_out_u32(); if (player_flag_temp.status == PLAYER_FLAG_PAUSE) ai_async_audio_ctrl_resume(); state_m->state = STATE_TRACK_CHANGED_RESUME; break; default: return; } // Error management if (state_m->cmd_status == false) state_m->state = STATE_DEVICE_DISCONNECTED; }
static void config_task(struct state_machine_context *state_m) { // By default, the command executed is asynchronous. state_m->async_cmd = true; state_m->view = GUI_UPDATE_VIEW_CONFIG; switch (state_m->state) { // This state id the entry point of the configuration view. // It must be call on every access to this view. case STATE_CONFIG_ENTRY_POINT: state_m->view_elt = GUI_UPDATE_ELT_NONE; state_m->view_elt |= GUI_UPDATE_ELT_CONFIG_CURSOR; state_m->cmd_status = true; state_m->async_cmd = false; state_m->display_list.mode_pos = MODE_POS_REPEAT; state_m->state = STATE_CONFIG_UPDATE_STATES; break; // This state is the "idle" state of this view. case STATE_CONFIG_WAIT_FOR_EVENT: // Switch to navigation view if (controller_switch_to_navigation_view(GUI_UPDATE_VIEW_CONFIG)) { controller_clear(); state_m->async_cmd = false; state_m->state = STATE_NAVIGATION_ENTRY_POINT; break; } else if (controller_switch_to_playback_view(GUI_UPDATE_VIEW_CONFIG)) { controller_clear(); state_m->async_cmd = false; state_m->state = STATE_PLAYBACK_ENTRY_POINT; break; } else if (controller_config_change_mode()) { switch (state_m->display_list.mode_pos) { case MODE_POS_SHUFFLE: switch (state_m->player_status.shuffle) { case AUDIO_SHUFFLE_FOLDER: ai_async_audio_nav_shuffle_set(AUDIO_SHUFFLE_ALL); break; case AUDIO_SHUFFLE_ALL: ai_async_audio_nav_shuffle_set(AUDIO_SHUFFLE_OFF); break; case AUDIO_SHUFFLE_OFF: default: ai_async_audio_nav_shuffle_set(AUDIO_SHUFFLE_FOLDER); } break; case MODE_POS_REPEAT: switch (state_m->player_status.repeat) { case AUDIO_REPEAT_TRACK: ai_async_audio_nav_repeat_set(AUDIO_REPEAT_FOLDER); break; case AUDIO_REPEAT_FOLDER: ai_async_audio_nav_repeat_set(AUDIO_REPEAT_ALL); break; case AUDIO_REPEAT_ALL: ai_async_audio_nav_repeat_set(AUDIO_REPEAT_OFF); break; case AUDIO_REPEAT_OFF: default: ai_async_audio_nav_repeat_set(AUDIO_REPEAT_TRACK); } break; } state_m->state = STATE_CONFIG_UPDATE_STATES; break; } else if (controller_config_next_option()) { state_m->async_cmd = false; switch (state_m->display_list.mode_pos) { case MODE_POS_REPEAT: state_m->display_list.mode_pos = MODE_POS_SHUFFLE; break; case MODE_POS_SHUFFLE: default: state_m->display_list.mode_pos = MODE_POS_REPEAT; } state_m->view_elt |= GUI_UPDATE_ELT_CONFIG_CURSOR; break; } else if (controller_config_previous_option()) { state_m->async_cmd = false; switch (state_m->display_list.mode_pos) { case MODE_POS_REPEAT: state_m->display_list.mode_pos = MODE_POS_SHUFFLE; break; case MODE_POS_SHUFFLE: default: state_m->display_list.mode_pos = MODE_POS_REPEAT; } state_m->view_elt |= GUI_UPDATE_ELT_CONFIG_CURSOR; break; } state_m->async_cmd = false; break; // Get repeat states. case STATE_CONFIG_UPDATE_STATES: ai_async_audio_nav_repeat_get(); state_m->state = STATE_CONFIG_READ_REPEAT_STATE; break; // Get shuffle states. case STATE_CONFIG_READ_REPEAT_STATE: state_m->player_status.repeat = ai_async_cmd_out_u32(); state_m->view_elt |= GUI_UPDATE_ELT_CONFIG_REPEAT; ai_async_audio_nav_shuffle_get(); state_m->state = STATE_CONFIG_READ_SHUFFLE_STATE; break; // Read shuffle states. case STATE_CONFIG_READ_SHUFFLE_STATE: state_m->player_status.shuffle = ai_async_cmd_out_u32(); state_m->view_elt |= GUI_UPDATE_ELT_CONFIG_SHUFFLE; state_m->state = STATE_CONFIG_WAIT_FOR_EVENT; break; default: return; } // Error management if (state_m->cmd_status == false) state_m->state = STATE_CONFIG_ENTRY_POINT; }
static void playback_task(struct state_machine_context *state_m) { static enum { PLAYER_STATUS_NOT_DEFINED, PLAYER_STATUS_PLAY, PLAYER_STATUS_PAUSE, PLAYER_STATUS_STOP, PLAYER_STATUS_FFW, PLAYER_STATUS_FRW } current_view_player_status; static bool fast_mode = false; // By default, the command executed is asynchronous. state_m->async_cmd = true; state_m->view = GUI_UPDATE_VIEW_PLAYBACK; switch (state_m->state) { // This state id the entry point of the navigation view. // It must be call on every access to this view. case STATE_PLAYBACK_ENTRY_POINT: state_m->view_elt = GUI_UPDATE_ELT_NONE; state_m->view_elt |= GUI_UPDATE_ELT_PLAYBACK_ELAPSED_TIME; state_m->view_elt |= GUI_UPDATE_ELT_PLAYBACK_VOLUME; state_m->view_elt |= GUI_UPDATE_ELT_PLAYBACK_ARTIST; state_m->view_elt |= GUI_UPDATE_ELT_PLAYBACK_TITLE; state_m->view_elt |= GUI_UPDATE_ELT_PLAYBACK_FILE_NAME; state_m->view_elt |= GUI_UPDATE_ELT_PLAYBACK_TOTAL_TIME; state_m->view_elt |= GUI_UPDATE_ELT_PLAYBACK_COVER_ART; state_m->cmd_status = true; state_m->async_cmd = false; state_m->info.volume = audio_mixer_dacs_get_volume(); current_view_player_status = PLAYER_STATUS_NOT_DEFINED; cpu_set_timeout(cpu_ms_2_cy(ELAPSED_TIME_TIMER_VALUE_MS, FCPU_HZ), &state_m->elapsed_time_timer); state_m->state = STATE_PLAYBACK_WAIT_FOR_EVENT; break; // This state is the "idle" state of this view. case STATE_PLAYBACK_WAIT_FOR_EVENT: // Catch new track event if (state_m->player_status.flags.new_file_played) { // Notify the controller a new track is being played controller_playback_ffw(true); controller_playback_frw(true); state_m->async_cmd = false; state_m->player_status.flags.new_file_played = 0; state_m->recorded_state = STATE_PLAYBACK_ENTRY_POINT; state_m->state = STATE_TRACK_CHANGED_ENTRY_POINT; break; } // Switch to navigation view else if (controller_switch_to_navigation_view(GUI_UPDATE_VIEW_PLAYBACK)) { controller_clear(); state_m->async_cmd = false; state_m->state = STATE_NAVIGATION_ENTRY_POINT; break; } // Switch to configuration view else if (controller_switch_to_config_view(GUI_UPDATE_VIEW_PLAYBACK)) { controller_clear(); state_m->async_cmd = false; state_m->state = STATE_CONFIG_ENTRY_POINT; break; } // Increase volume else if (controller_playback_increase_volume()) { state_m->async_cmd = false; audio_mixer_dacs_increase_volume(); audio_mixer_dacs_increase_volume(); state_m->info.volume = audio_mixer_dacs_get_volume(); state_m->view_elt |= GUI_UPDATE_ELT_PLAYBACK_VOLUME; break; } // Decrease volume else if (controller_playback_decrease_volume()) { state_m->async_cmd = false; audio_mixer_dacs_decrease_volume(); audio_mixer_dacs_decrease_volume(); state_m->info.volume = audio_mixer_dacs_get_volume(); state_m->view_elt |= GUI_UPDATE_ELT_PLAYBACK_VOLUME; break; } else if (controller_playback_ffw(false)) { ai_async_audio_ctrl_start_ffw(); state_m->state = STATE_CHECK_DEVICE_ENTRY_POINT; state_m->recorded_state = STATE_PLAYBACK_HANDLE_FAST_MODES; fast_mode = true; break; } else if (controller_playback_frw(false)) { ai_async_audio_ctrl_start_frw(); state_m->state = STATE_CHECK_DEVICE_ENTRY_POINT; state_m->recorded_state = STATE_PLAYBACK_HANDLE_FAST_MODES; fast_mode = true; break; } else if (fast_mode) { ai_async_audio_ctrl_stop_ffw_frw(); state_m->state = STATE_CHECK_DEVICE_ENTRY_POINT; state_m->recorded_state = STATE_PLAYBACK_HANDLE_FAST_MODES; fast_mode = false; break; } // Previous track else if (controller_playback_previous_track()) { ai_async_audio_nav_previous(); break; } // Next track else if (controller_playback_next_track()) { ai_async_audio_nav_next(); break; } // Toggle play/pause else if (controller_playback_toggle_play_pause()) { switch (state_m->player_status.flags.status) { case PLAYER_FLAG_PLAY: ai_async_audio_ctrl_pause(); state_m->view_elt |= GUI_UPDATE_ELT_PLAYBACK_PAUSE; break; case PLAYER_FLAG_PAUSE: ai_async_audio_ctrl_resume(); state_m->view_elt |= GUI_UPDATE_ELT_PLAYBACK_PLAY; break; case PLAYER_FLAG_STOP: ai_async_audio_nav_playfile(); state_m->view_elt |= GUI_UPDATE_ELT_PLAYBACK_PLAY; break; } break; } else if (cpu_is_timeout(&state_m->elapsed_time_timer)) { cpu_set_timeout(cpu_ms_2_cy(ELAPSED_TIME_TIMER_VALUE_MS, FCPU_HZ), &state_m->elapsed_time_timer); ai_async_audio_ctrl_time(); state_m->state = STATE_PLAYBACK_UPDATE_TIME; break; } state_m->async_cmd = false; state_m->state = STATE_CHECK_DEVICE_ENTRY_POINT; state_m->recorded_state = STATE_PLAYBACK_UPDATE_STATUS; break; // This state is called after fats forward or fast rewind commands to handle return states. case STATE_PLAYBACK_HANDLE_FAST_MODES: cpu_set_timeout(cpu_ms_2_cy(ELAPSED_TIME_TIMER_VALUE_MS, FCPU_HZ), &state_m->elapsed_time_timer); ai_async_audio_ctrl_time(); state_m->state = STATE_PLAYBACK_UPDATE_TIME; break; // This state update the elapsed time of the current track being played. case STATE_PLAYBACK_UPDATE_TIME: state_m->async_cmd = false; state_m->info.elapsed_time = ai_async_cmd_out_u32(); state_m->view_elt |= GUI_UPDATE_ELT_PLAYBACK_ELAPSED_TIME; state_m->state = STATE_PLAYBACK_WAIT_FOR_EVENT; break; // This state update the elapsed time of the current track being played. case STATE_PLAYBACK_UPDATE_STATUS: state_m->async_cmd = false; // Update control GUI if (state_m->player_status.flags.status_fast == PLAYER_FLAG_FFW && current_view_player_status != PLAYER_STATUS_FFW) state_m->view_elt |= GUI_UPDATE_ELT_PLAYBACK_FFW; else if (state_m->player_status.flags.status_fast == PLAYER_FLAG_FRW && current_view_player_status != PLAYER_STATUS_FRW) state_m->view_elt |= GUI_UPDATE_ELT_PLAYBACK_FRW; else if (state_m->player_status.flags.status == PLAYER_FLAG_PLAY && current_view_player_status != PLAYER_STATUS_PLAY) state_m->view_elt |= GUI_UPDATE_ELT_PLAYBACK_PLAY; else if (state_m->player_status.flags.status == PLAYER_FLAG_PAUSE && current_view_player_status != PLAYER_STATUS_PAUSE) state_m->view_elt |= GUI_UPDATE_ELT_PLAYBACK_PAUSE; else if (state_m->player_status.flags.status == PLAYER_FLAG_STOP && current_view_player_status != PLAYER_STATUS_STOP) state_m->view_elt |= GUI_UPDATE_ELT_PLAYBACK_STOP; state_m->state = STATE_PLAYBACK_WAIT_FOR_EVENT; break; default: return; } // Error management if (state_m->cmd_status == false) state_m->state = STATE_PLAYBACK_WAIT_FOR_EVENT; }
static void navigation_task(struct state_machine_context *state_m) { static size_t item_updated; static uint16_t temp_cursor_pos; size_t i; // By default, the command executed is asynchronous. state_m->async_cmd = true; state_m->view = GUI_UPDATE_VIEW_NAVIGATION; switch (state_m->state) { // This state id the entry point of the navigation view. // It must be call on every access to this view. case STATE_NAVIGATION_ENTRY_POINT: state_m->view_elt = GUI_UPDATE_ELT_NAVIGATION_CURSOR; state_m->async_cmd = false; state_m->cmd_status = true; // Update file_list relatives info. state_m->list.file_pos = 0; state_m->list.nb_files = 0xFFFF; state_m->list.nb_valid_entries = 0; temp_cursor_pos = 0; state_m->cursor_pointer = 0; // Invalidate all the items on the list for (i=0; i<MAX_BUFFER_FILE; i++) state_m->list.list[i].updated = false; state_m->state = STATE_NAVIGATION_UPDATE_LIST; break; // Update the file list from the current directory. case STATE_NAVIGATION_UPDATE_LIST: // Re-center the file list. if (temp_cursor_pos < state_m->list.file_pos && state_m->list.nb_valid_entries) { // Scroll-down the list memmove((void *) &state_m->list.list[1], (const void *) &state_m->list.list[0], sizeof(state_m->list.list[0])*(MAX_BUFFER_FILE - 1)); // Every element of the list have to be updated for (i=1; i<MAX_BUFFER_FILE; i++) state_m->list.list[i].updated = true; // Get information of the file. item_updated = 0; state_m->list.file_pos--; state_m->list.nb_valid_entries--; ai_async_nav_file_goto(state_m->list.file_pos + item_updated); state_m->view_elt |= GUI_UPDATE_ELT_IN_PROGRESS; state_m->state = STATE_NAVIGATION_UPDATE_LIST_GET_NAME; break; } if (temp_cursor_pos > state_m->list.file_pos && state_m->list.nb_valid_entries) { // Scroll-up the list memmove((void *) &state_m->list.list[0], (const void *) &state_m->list.list[1], sizeof(state_m->list.list[0])*(MAX_BUFFER_FILE - 1)); // Every element of the list have to be updated for (i=0; i<MAX_BUFFER_FILE-1; i++) state_m->list.list[i].updated = true; // Get information of the file. item_updated = MAX_BUFFER_FILE - 1; state_m->list.file_pos++; state_m->list.nb_valid_entries--; ai_async_nav_file_goto(state_m->list.file_pos + item_updated); state_m->view_elt |= GUI_UPDATE_ELT_IN_PROGRESS; state_m->state = STATE_NAVIGATION_UPDATE_LIST_GET_NAME; break; } // There is nothing to update state_m->async_cmd = false; state_m->view_elt |= GUI_UPDATE_ELT_IN_PROGRESS; state_m->state = STATE_NAVIGATION_WAIT_FOR_EVENT; break; // Read the file name of the file selected. case STATE_NAVIGATION_UPDATE_LIST_GET_NAME: // The case when there is no more files... if (state_m->cmd_status == false) { state_m->list.nb_files = state_m->list.file_pos + item_updated; // If no files/folders are found in the current directory... if (!state_m->list.nb_files) state_m->view_elt |= GUI_UPDATE_ELT_NAVIGATION_NO_FILES; state_m->cmd_status = true; state_m->async_cmd = false; navigation_update_view(state_m); state_m->state = STATE_NAVIGATION_WAIT_FOR_EVENT; break; } ai_async_nav_file_name(); state_m->view_elt |= GUI_UPDATE_ELT_IN_PROGRESS; state_m->state = STATE_NAVIGATION_UPDATE_LIST_STORE_NAME; break; // Store the file name of the selected file. case STATE_NAVIGATION_UPDATE_LIST_STORE_NAME: unicode2ascii((char *) state_m->list.list[item_updated].file_name, (const char *) ai_async_cmd_out_PtrArrayU8(), Min(ai_async_cmd_out_SizeArrayU8(), STR_MAX_LENGTH*2)); ai_async_nav_file_isdir(); state_m->view_elt |= GUI_UPDATE_ELT_IN_PROGRESS; state_m->state = STATE_NAVIGATION_UPDATE_ISDIR; break; // Check if the selected file is a directory or not. case STATE_NAVIGATION_UPDATE_ISDIR: state_m->list.list[item_updated].type = (ai_async_cmd_out_u32())?FILE_TYPE_DIRECTORY:FILE_TYPE_FILE; state_m->list.list[item_updated].updated = true; state_m->list.nb_valid_entries++; navigation_update_view(state_m); state_m->async_cmd = false; state_m->view_elt |= GUI_UPDATE_ELT_IN_PROGRESS; state_m->state = STATE_NAVIGATION_UPDATE_LIST; break; // This state is the "idle" state of this view. case STATE_NAVIGATION_WAIT_FOR_EVENT: // Catch new track event state_m->cmd_status = true; if (state_m->player_status.flags.new_file_played) { state_m->async_cmd = false; state_m->player_status.flags.new_file_played = 0; state_m->recorded_state = STATE_NAVIGATION_WAIT_FOR_EVENT; state_m->state = STATE_TRACK_CHANGED_ENTRY_POINT; break; } // Switch to playback view else if (controller_switch_to_playback_view(GUI_UPDATE_VIEW_NAVIGATION)) { controller_clear(); state_m->async_cmd = false; state_m->state = STATE_PLAYBACK_ENTRY_POINT; break; } // Switch to configuration view else if (controller_switch_to_config_view(GUI_UPDATE_VIEW_NAVIGATION)) { controller_clear(); state_m->async_cmd = false; state_m->state = STATE_CONFIG_ENTRY_POINT; break; } // Go up in the file list. else if (controller_navigation_cursor_previous() && temp_cursor_pos) { state_m->async_cmd = false; temp_cursor_pos--; state_m->state = STATE_NAVIGATION_UPDATE_LIST; break; } // Go down in the file list. else if (controller_navigation_cursor_next() && (temp_cursor_pos + 1 < state_m->list.file_pos + state_m->list.nb_valid_entries)) { state_m->async_cmd = false; temp_cursor_pos++; state_m->state = STATE_NAVIGATION_UPDATE_LIST; break; } // Enter directory of play the file. else if (controller_navigation_change_directory()) { if (navigation_get_current_file_type(state_m) == FILE_TYPE_FILE) { ai_async_nav_file_goto(temp_cursor_pos); state_m->state = STATE_NAVIGATION_PLAY_SELECTED_FILE; break; } else { ai_async_nav_file_goto(temp_cursor_pos); state_m->state = STATE_NAVIGATION_CD; break; } } // Go to parent directory. else if (controller_navigation_go_to_parent_directory()) { ai_async_nav_file_goto(temp_cursor_pos); state_m->state = STATE_NAVIGATION_GOTOPARENT; break; } // Play the file or the directory. else if (controller_navigation_play()) { ai_async_nav_file_goto(temp_cursor_pos); state_m->state = STATE_NAVIGATION_PLAY_SELECTED_FILE; break; } // Fill the file list with valid data. else if (state_m->list.nb_valid_entries < MAX_BUFFER_FILE && state_m->list.file_pos + state_m->list.nb_valid_entries < state_m->list.nb_files) { item_updated = state_m->list.nb_valid_entries; ai_async_nav_file_goto(state_m->list.file_pos + state_m->list.nb_valid_entries); state_m->view_elt |= GUI_UPDATE_ELT_IN_PROGRESS; state_m->state = STATE_NAVIGATION_UPDATE_LIST_GET_NAME; break; } state_m->async_cmd = false; state_m->state = STATE_CHECK_DEVICE_ENTRY_POINT; state_m->recorded_state = STATE_NAVIGATION_WAIT_FOR_EVENT; break; // Enter directory. case STATE_NAVIGATION_CD: ai_async_nav_dir_cd(); state_m->state = STATE_NAVIGATION_ENTRY_POINT; break; // Go to parent directory. case STATE_NAVIGATION_GOTOPARENT: state_m->cmd_status = true; ai_async_nav_dir_gotoparent(); state_m->state = STATE_NAVIGATION_GOTOPARENT_ERROR_HANDLING; break; // This state handle a gotoparent error. case STATE_NAVIGATION_GOTOPARENT_ERROR_HANDLING: state_m->async_cmd = false; if (state_m->cmd_status == false) state_m->state = STATE_NAVIGATION_WAIT_FOR_EVENT; else state_m->state = STATE_NAVIGATION_ENTRY_POINT; state_m->cmd_status = true; break; // This states play the file selected by the cursor. case STATE_NAVIGATION_PLAY_SELECTED_FILE: if (state_m->cmd_status) ai_async_audio_nav_playfile(); else { state_m->cmd_status = true; state_m->async_cmd = false; state_m->state = STATE_NAVIGATION_ENTRY_POINT; break; } state_m->state = STATE_NAVIGATION_WAIT_FOR_SELECTION; break; // This states makes sure the file has been selected case STATE_NAVIGATION_WAIT_FOR_SELECTION: // If we were not able to play the selected song, then play any song if (!state_m->cmd_status) { state_m->cmd_status = true; state_m->state = STATE_COMMAND_PLAY_ANY_SONG; } else state_m->state = STATE_CHECK_DEVICE_ENTRY_POINT; state_m->recorded_state = STATE_NAVIGATION_UPDATE_METADATA_AND_PLAY; state_m->async_cmd = false; break; // This state update the status of the audio player. case STATE_NAVIGATION_UPDATE_METADATA_AND_PLAY: state_m->async_cmd = false; state_m->player_status.flags.new_file_played = 0; state_m->recorded_state = STATE_PLAYBACK_ENTRY_POINT; state_m->state = STATE_TRACK_CHANGED_ENTRY_POINT; break; default: return; } // Error management. if (state_m->cmd_status == false) state_m->state = STATE_NAVIGATION_WAIT_FOR_EVENT; }