/* * Set the current buffer to the given buffer number if it exists. */ static void controller_set_current_buffer(unsigned int num) { if (GCon.buffers[num] != NULL) { bufstack_swap(current_buf_num, num); current_buf_num = num; current_buf = GCon.buffers[num]; } controller_clear(current_buf_num); buffer_redraw(current_buf); }
void rtc_init_qt( void ) { // Init touch_states controller_clear(); // Disable all interrupts Disable_global_interrupt(); // Register the RTC interrupt handler to the interrupt controller. BSP_INTC_IntReg( &rtc_irq, AVR32_RTC_IRQ, AVR32_INTC_INT1); // Initialize the RTC rtc_init(&AVR32_RTC, RTC_OSC_32KHZ, 4); rtc_set_top_value(&AVR32_RTC, 1); // Enable the interrupts rtc_enable_interrupt(&AVR32_RTC); // Enable the RTC rtc_enable(&AVR32_RTC); // Enable global interrupts Enable_global_interrupt(); }
int main(int argc, char *argv[]) { int rc = -1, n, priority; const char *importer, *scanner, *geo; char *endptr; size_t nctl; double speed; struct timecode_def *timecode; bool protect, use_mlock, phono; struct controller ctl[2]; struct rt rt; struct library library; #if defined WITH_OSS || WITH_ALSA int rate; #endif #ifdef WITH_OSS int oss_buffers, oss_fragment; #endif #ifdef WITH_ALSA int alsa_buffer; #endif fprintf(stderr, "%s\n\n" NOTICE "\n\n", banner); if (thread_global_init() == -1) return -1; if (rig_init() == -1) return -1; rt_init(&rt); library_init(&library); ndeck = 0; geo = ""; nctl = 0; priority = DEFAULT_PRIORITY; importer = DEFAULT_IMPORTER; scanner = DEFAULT_SCANNER; timecode = NULL; speed = 1.0; protect = false; phono = false; use_mlock = false; #if defined WITH_OSS || WITH_ALSA rate = DEFAULT_RATE; #endif #ifdef WITH_ALSA alsa_buffer = DEFAULT_ALSA_BUFFER; #endif #ifdef WITH_OSS oss_fragment = DEFAULT_OSS_FRAGMENT; oss_buffers = DEFAULT_OSS_BUFFERS; #endif /* Skip over command name */ argv++; argc--; while (argc > 0) { if (!strcmp(argv[0], "-h")) { usage(stdout); return 0; #ifdef WITH_OSS } else if (!strcmp(argv[0], "-f")) { /* Set fragment size for subsequent devices */ if (argc < 2) { fprintf(stderr, "-f requires an integer argument.\n"); return -1; } oss_fragment = strtol(argv[1], &endptr, 10); if (*endptr != '\0') { fprintf(stderr, "-f requires an integer argument.\n"); return -1; } /* Fragment sizes greater than the default aren't useful * as they are dependent on DEVICE_FRAME */ if (oss_fragment < DEFAULT_OSS_FRAGMENT) { fprintf(stderr, "Fragment size must be %d or more; aborting.\n", DEFAULT_OSS_FRAGMENT); return -1; } argv += 2; argc -= 2; } else if (!strcmp(argv[0], "-b")) { /* Set number of buffers for subsequent devices */ if (argc < 2) { fprintf(stderr, "-b requires an integer argument.\n"); return -1; } oss_buffers = strtol(argv[1], &endptr, 10); if (*endptr != '\0') { fprintf(stderr, "-b requires an integer argument.\n"); return -1; } argv += 2; argc -= 2; #endif #if defined WITH_OSS || WITH_ALSA } else if (!strcmp(argv[0], "-r")) { /* Set sample rate for subsequence devices */ if (argc < 2) { fprintf(stderr, "-r requires an integer argument.\n"); return -1; } rate = strtol(argv[1], &endptr, 10); if (*endptr != '\0') { fprintf(stderr, "-r requires an integer argument.\n"); return -1; } argv += 2; argc -= 2; #endif #ifdef WITH_ALSA } else if (!strcmp(argv[0], "-m")) { /* Set size of ALSA buffer for subsequence devices */ if (argc < 2) { fprintf(stderr, "-m requires an integer argument.\n"); return -1; } alsa_buffer = strtol(argv[1], &endptr, 10); if (*endptr != '\0') { fprintf(stderr, "-m requires an integer argument.\n"); return -1; } argv += 2; argc -= 2; #endif } else if (!strcmp(argv[0], "-d") || !strcmp(argv[0], "-a") || !strcmp(argv[0], "-j")) { int r; unsigned int sample_rate; struct deck *ld; struct device *device; struct timecoder *timecoder; /* Create a deck */ if (argc < 2) { fprintf(stderr, "-%c requires a device name as an argument.\n", argv[0][1]); return -1; } if (ndeck == ARRAY_SIZE(deck)) { fprintf(stderr, "Too many decks; aborting.\n"); return -1; } fprintf(stderr, "Initialising deck %zd (%s)...\n", ndeck, argv[1]); ld = &deck[ndeck]; device = &ld->device; timecoder = &ld->timecoder; ld->importer = importer; ld->protect = protect; /* Work out which device type we are using, and initialise * an appropriate device. */ switch(argv[0][1]) { #ifdef WITH_OSS case 'd': r = oss_init(device, argv[1], rate, oss_buffers, oss_fragment); break; #endif #ifdef WITH_ALSA case 'a': r = alsa_init(device, argv[1], rate, alsa_buffer); break; #endif #ifdef WITH_JACK case 'j': r = jack_init(device, argv[1]); break; #endif default: fprintf(stderr, "Device type is not supported by this " "distribution of xwax.\n"); return -1; } if (r == -1) return -1; sample_rate = device_sample_rate(device); /* Default timecode decoder where none is specified */ if (timecode == NULL) { timecode = timecoder_find_definition(DEFAULT_TIMECODE); assert(timecode != NULL); } timecoder_init(timecoder, timecode, speed, sample_rate, phono); /* Connect up the elements to make an operational deck */ r = deck_init(ld, &rt, ndeck); if (r == -1) return -1; /* Connect this deck to available controllers */ for (n = 0; n < nctl; n++) controller_add_deck(&ctl[n], &deck[ndeck]); /* Connect this deck to OSC server */ osc_add_deck(); ndeck++; argv += 2; argc -= 2; } else if (!strcmp(argv[0], "-t")) { /* Set the timecode definition to use */ if (argc < 2) { fprintf(stderr, "-t requires a name as an argument.\n"); return -1; } timecode = timecoder_find_definition(argv[1]); if (timecode == NULL) { fprintf(stderr, "Timecode '%s' is not known.\n", argv[1]); return -1; } argv += 2; argc -= 2; } else if (!strcmp(argv[0], "-33")) { speed = 1.0; argv++; argc--; } else if (!strcmp(argv[0], "-45")) { speed = 1.35; argv++; argc--; } else if (!strcmp(argv[0], "-c")) { protect = true; argv++; argc--; } else if (!strcmp(argv[0], "-u")) { protect = false; argv++; argc--; } else if (!strcmp(argv[0], "--line")) { phono = false; argv++; argc--; } else if (!strcmp(argv[0], "--phono")) { phono = true; argv++; argc--; } else if (!strcmp(argv[0], "-k")) { use_mlock = true; track_use_mlock(); argv++; argc--; } else if (!strcmp(argv[0], "-q")) { if (argc < 2) { fprintf(stderr, "-q requires an integer argument.\n"); return -1; } priority = strtol(argv[1], &endptr, 10); if (*endptr != '\0') { fprintf(stderr, "-q requires an integer argument.\n"); return -1; } if (priority < 0) { fprintf(stderr, "Priority (%d) must be zero or positive.\n", priority); return -1; } argv += 2; argc -= 2; } else if (!strcmp(argv[0], "-g")) { if (argc < 2) { fprintf(stderr, "-g requires an argument.\n"); return -1; } geo = argv[1]; argv += 2; argc -= 2; } else if (!strcmp(argv[0], "-i")) { /* Importer script for subsequent decks */ if (argc < 2) { fprintf(stderr, "-i requires an executable path " "as an argument.\n"); return -1; } importer = argv[1]; argv += 2; argc -= 2; } else if (!strcmp(argv[0], "-s")) { /* Scan script for subsequent libraries */ if (argc < 2) { fprintf(stderr, "-s requires an executable path " "as an argument.\n"); return -1; } scanner = argv[1]; argv += 2; argc -= 2; } else if (!strcmp(argv[0], "-l")) { /* Load in a music library */ if (argc < 2) { fprintf(stderr, "-%c requires a pathname as an argument.\n", argv[0][1]); return -1; } if (library_import(&library, scanner, argv[1]) == -1) return -1; argv += 2; argc -= 2; #ifdef WITH_ALSA } else if (!strcmp(argv[0], "--dicer")) { struct controller *c; if (nctl == sizeof ctl) { fprintf(stderr, "Too many controllers; aborting.\n"); return -1; } c = &ctl[nctl]; if (argc < 2) { fprintf(stderr, "Dicer requires an ALSA device name.\n"); return -1; } if (dicer_init(c, &rt, argv[1]) == -1) return -1; nctl++; argv += 2; argc -= 2; #endif } else { fprintf(stderr, "'%s' argument is unknown; try -h.\n", argv[0]); return -1; } } #ifdef WITH_ALSA alsa_clear_config_cache(); #endif if (ndeck == 0) { fprintf(stderr, "You need to give at least one audio device to use " "as a deck; try -h.\n"); return -1; } rc = EXIT_FAILURE; /* until clean exit */ if (osc_start((struct deck *)&deck, &library) == -1) return -1; osc_start_updater_thread(); /* Order is important: launch realtime thread first, then mlock. * Don't mlock the interface, use sparingly for audio threads */ if (rt_start(&rt, priority) == -1) return -1; if (use_mlock && mlockall(MCL_CURRENT) == -1) { perror("mlockall"); goto out_rt; } if (interface_start(&library, geo) == -1) goto out_rt; if (rig_main() == -1) goto out_interface; rc = EXIT_SUCCESS; fprintf(stderr, "Exiting cleanly...\n"); out_interface: interface_stop(); out_rt: rt_stop(&rt); for (n = 0; n < ndeck; n++) deck_clear(&deck[n]); for (n = 0; n < nctl; n++) controller_clear(&ctl[n]); timecoder_free_lookup(); library_clear(&library); rt_clear(&rt); rig_clear(); osc_stop(); thread_global_clear(); if (rc == EXIT_SUCCESS) fprintf(stderr, "Done.\n"); return rc; }
void controller_init(uint32_t fcpu_hz, uint32_t fhsb_hz, uint32_t fpbb_hz, uint32_t fpba_hz) { static const gpio_map_t QT60168_SPI_GPIO_MAP = { { QT60168_SPI_SCK_PIN, QT60168_SPI_SCK_FUNCTION }, // SPI Clock. { QT60168_SPI_MISO_PIN, QT60168_SPI_MISO_FUNCTION }, // MISO. { QT60168_SPI_MOSI_PIN, QT60168_SPI_MOSI_FUNCTION }, // MOSI. { QT60168_SPI_NPCS0_PIN, QT60168_SPI_NPCS0_FUNCTION } // Chip Select NPCS. }; // SPI options. spi_options_t spiOptions = { .reg = QT60168_SPI_NCPS, .baudrate = QT60168_SPI_MASTER_SPEED, // Defined in conf_qt60168.h. .bits = QT60168_SPI_BITS, // Defined in conf_qt60168.h. .spck_delay = 0, .trans_delay = 0, .stay_act = 0, .spi_mode = 3, .modfdis = 1 }; // Assign I/Os to SPI. gpio_enable_module(QT60168_SPI_GPIO_MAP, sizeof(QT60168_SPI_GPIO_MAP) / sizeof(QT60168_SPI_GPIO_MAP[0])); // Set selection mode: variable_ps, pcs_decode, delay. spi_selectionMode(QT60168_SPI, 0, 0, 0); // Enable SPI. spi_enable(QT60168_SPI); // Initialize QT60168 with SPI clock Osc0. spi_setupChipReg(QT60168_SPI, &spiOptions, fpba_hz); // Initialize QT60168 component. qt60168_init(fpba_hz); // Init timer to get key value. rtc_init_qt(); // Invalidate the timeout already cpu_set_timeout(0, &cpu_time_clear_wheel); } void rtc_init_qt( void ) { // Init touch_states controller_clear(); // Disable all interrupts cpu_irq_disable(); // Register the RTC interrupt handler to the interrupt controller. irq_register_handler(rtc_irq, AVR32_RTC_IRQ, 0); // Initialize the RTC rtc_init(&AVR32_RTC, RTC_OSC_32KHZ, 4); rtc_set_top_value(&AVR32_RTC, 1); // Enable the interrupts rtc_enable_interrupt(&AVR32_RTC); // Enable the RTC rtc_enable(&AVR32_RTC); // Enable global interrupts cpu_irq_enable(); }
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; }