Files
Peter Edwards 8e005ff1a4 Fixed bug when ABORT was pressed in Select Mode menu
Potential fix to prevent LONG pauses when recording using manual finalize mode with multiple blocks and motor stops (rainbow islands masterings software)
2015-08-19 12:36:34 +02:00

473 lines
12 KiB
C

#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include "ff.h"
#include "config.h"
#include "comms.h"
#include "memstrings.h"
#include "fileutils.h"
#include "tapuino.h"
#include "lcd_interface.h"
#include "lcdutils.h"
#define MODE_PLAY 0
#define MODE_RECORD 1
#define MODE_OPTIONS 2
#define REC_MODE_MANUAL 0
#define REC_MODE_AUTO 1
#define OPTION_MACHINE_TYPE 0
#define OPTION_VIDEO_MODE 1
#define OPTION_SIGNAL 2
#define OPTION_KEY_REPEAT 3
#define OPTION_TICKER_SPEED 4
#define OPTION_TICKER_HOLD 5
#define OPTION_REC_FINALIZE 6
#define OPTION_REC_AUTO_FINALIZE 7
#define SELECT_MODE_EXIT 0xFF
int g_num_files = 0;
int g_cur_file_index = 0;
uint8_t get_cur_command() {
// this order of operations is very important
// first get an 'atomic' read of g_cur_command into a local
uint8_t cur_command = g_cur_command;
// then compare the _local_ against a non-IDLE command
if (cur_command != COMMAND_IDLE) {
// and clear the global i.e. only if the global was non-idle at the time of read
// this prevents clearing the global as a key is pressed and missing it
g_cur_command = COMMAND_IDLE;
}
return cur_command;
}
uint8_t handle_select_mode(const char* ptitle, const char** ppitems, uint8_t max, uint8_t cur_mode) {
uint8_t prev_mode = (cur_mode + 1) % max;
lcd_title_P(ptitle);
while (1) {
if (prev_mode != cur_mode) {
lcd_status_P(ppitems[cur_mode]);
prev_mode = cur_mode;
}
switch(get_cur_command()) {
case COMMAND_SELECT:
return cur_mode;
break;
case COMMAND_ABORT:
return SELECT_MODE_EXIT;
break;
case COMMAND_NEXT:
if (cur_mode == (max - 1)) {
cur_mode = 0;
} else {
cur_mode++;
}
break;
case COMMAND_PREVIOUS:
if (cur_mode == 0) {
cur_mode = max -1;
} else {
cur_mode--;
}
break;
}
}
}
void handle_play_mode(FILINFO* pfile_info) {
// reset to the root after a possible record operation
change_dir("/");
// refresh the file list to avoid blank entries bug
if ((g_num_files = get_num_files(pfile_info)) == 0) {
lcd_title_P(S_NO_FILES_FOUND);
lcd_busy_spinner();
return;
}
g_cur_file_index = 0;
if (!get_file_at_index(pfile_info, g_cur_file_index)) {
// shouldn't happen...
lcd_title_P(S_NO_FILES_FOUND);
lcd_busy_spinner();
return;
}
lcd_title_P(S_SELECT_FILE);
display_filename(pfile_info);
while (1) {
switch(get_cur_command()) {
case COMMAND_SELECT:
if (pfile_info->fattrib & AM_DIR) {
if (change_dir(pfile_info->fname) == FR_OK) {
g_num_files = get_num_files(pfile_info);
g_cur_file_index = 0;
get_file_at_index(pfile_info, g_cur_file_index);
display_filename(pfile_info);
} else {
lcd_status_P(S_CHDIR_FAILED);
}
} else {
display_filename(pfile_info);
play_file(pfile_info);
lcd_title_P(S_SELECT_FILE);
// buffer is used so get the file again
get_file_at_index(pfile_info, g_cur_file_index);
display_filename(pfile_info);
}
break;
case COMMAND_ABORT:
if (g_fs.cdir != 0) {
if (change_dir("..") == FR_OK) {
g_num_files = get_num_files(pfile_info);
g_cur_file_index = 0;
get_file_at_index(pfile_info, g_cur_file_index);
display_filename(pfile_info);
} else {
lcd_status_P(S_CHDIR_FAILED);
}
} else {
// back to main menu
return;
}
break;
case COMMAND_NEXT:
if (++g_cur_file_index >= g_num_files) {
g_cur_file_index = 0;
}
get_file_at_index(pfile_info, g_cur_file_index);
display_filename(pfile_info);
break;
case COMMAND_PREVIOUS:
if (--g_cur_file_index < 0) {
g_cur_file_index = g_num_files - 1;
}
get_file_at_index(pfile_info, g_cur_file_index);
display_filename(pfile_info);
break;
}
filename_ticker(pfile_info, get_timer_tick());
}
}
void handle_record_mode_ready(char* pfile_name) {
lcd_title_P(S_READY_RECORD);
lcd_status_P(S_PRESS_START);
while (1) {
switch(get_cur_command()) {
case COMMAND_SELECT:
record_file(pfile_name);
return;
break;
case COMMAND_ABORT:
// back to main menu
return;
break;
}
}
}
uint8_t handle_manual_filename(FILINFO* pfile_info) {
uint8_t cur_char_pos = 0;
uint8_t cursor_pos = 0;
uint8_t max_chars = strlen_P(S_FILENAME_CHARS);
uint8_t cur_char = 0;
lcd_title_P(S_ENTER_FILENAME);
lcd_status("");
lcd_cursor();
lcd_setCursor(0, 1);
// start with a nicely terminated string!
memset(pfile_info->lfname, 0, pfile_info->lfsize);
while (1) {
switch(get_cur_command()) {
case COMMAND_SELECT:
if (cursor_pos < (MAX_LCD_LINE_LEN - 1)) {
cur_char = pgm_read_byte(S_FILENAME_CHARS + cur_char_pos);
pfile_info->lfname[cursor_pos] = cur_char;
cursor_pos++;
lcd_setCursor(cursor_pos, 1);
cur_char_pos = 0;
}
break;
case COMMAND_SELECT_LONG:
strcat(pfile_info->lfname, ".tap");
lcd_noCursor();
// exit to previous menu, with accept
return 1;
break;
case COMMAND_ABORT:
if (cursor_pos != 0) {
pfile_info->lfname[cursor_pos] = 0;
lcd_setCursor(cursor_pos, 1);
lcd_write(' ');
cursor_pos--;
lcd_setCursor(cursor_pos, 1);
cur_char_pos = 0;
cur_char = pfile_info->lfname[cursor_pos];
while (pgm_read_byte(S_FILENAME_CHARS + cur_char_pos) != cur_char) {
cur_char_pos++;
}
}
break;
case COMMAND_ABORT_LONG:
lcd_title_P(S_OPERATION_ABORTED);
lcd_noCursor();
lcd_busy_spinner();
// exit to previous menu, with cancel
return 0;
break;
case COMMAND_NEXT:
cur_char_pos = (cur_char_pos + 1) % max_chars;
cur_char = pgm_read_byte(S_FILENAME_CHARS + cur_char_pos);
lcd_write(cur_char);
lcd_setCursor(cursor_pos, 1);
pfile_info->lfname[cursor_pos] = cur_char;
break;
case COMMAND_PREVIOUS:
if (cur_char_pos == 0) {
cur_char_pos = max_chars;
}
cur_char_pos--;
cur_char = pgm_read_byte(S_FILENAME_CHARS + cur_char_pos);
lcd_write(cur_char);
lcd_setCursor(cursor_pos, 1);
pfile_info->lfname[cursor_pos] = cur_char;
break;
}
}
}
void handle_record_mode(FILINFO* pfile_info) {
const char* ppitems[] = {S_REC_MODE_MANUAL, S_REC_MODE_AUTO};
uint8_t cur_mode = 0;
lcd_title_P(S_SELECT_RECORD_MODE);
// attempt to open the recording dir
strcpy_P((char*)g_fat_buffer, S_DEFAULT_RECORD_DIR);
// change to the recording dir
if (change_dir((char*)g_fat_buffer) != FR_OK) {
lcd_status_P(S_CHDIR_FAILED);
lcd_busy_spinner();
return;
}
while (1) {
cur_mode = handle_select_mode(S_SELECT_RECORD_MODE, ppitems, 2, cur_mode);
switch (cur_mode) {
case REC_MODE_AUTO:
handle_record_mode_ready(NULL);
return;
break;
case REC_MODE_MANUAL:
if (handle_manual_filename(pfile_info)) {
handle_record_mode_ready(pfile_info->lfname);
return;
}
break;
case SELECT_MODE_EXIT:
return;
break;
}
}
}
uint8_t handle_option_value(const char* poption, uint16_t* pcur_value, uint16_t min_value, uint16_t max_value, uint16_t step_value) {
char buffer[MAX_LCD_LINE_LEN + 1];
int32_t cur_value = *pcur_value;
if (cur_value < min_value || cur_value > max_value) {
cur_value = min_value;
}
lcd_title_P(poption);
utoa((uint16_t)cur_value, buffer, 10);
lcd_status(buffer);
while (1) {
switch(get_cur_command()) {
case COMMAND_SELECT:
*pcur_value = (uint16_t) cur_value;
return 1;
break;
case COMMAND_ABORT:
return 0;
break;
case COMMAND_NEXT:
cur_value += step_value;
if (cur_value > max_value) {
cur_value = max_value;
}
utoa((uint16_t)cur_value, buffer, 10);
lcd_status(buffer);
break;
case COMMAND_PREVIOUS:
cur_value -= step_value;
if (cur_value < min_value) {
cur_value = min_value;
}
utoa((uint16_t)cur_value, buffer, 10);
lcd_status(buffer);
break;
}
}
}
uint8_t handle_option_enum(const char* poption, uint16_t* pcur_value, uint16_t max_items, const char* ppitems[]) {
int32_t cur_value = *pcur_value;
lcd_title_P(poption);
lcd_status_P(ppitems[cur_value]);
while (1) {
switch(get_cur_command()) {
case COMMAND_SELECT:
*pcur_value = (uint16_t) cur_value;
return 1;
break;
case COMMAND_ABORT:
return 0;
break;
case COMMAND_NEXT:
cur_value++;
if (cur_value >= max_items) {
cur_value = 0;
}
lcd_status_P(ppitems[cur_value]);
break;
case COMMAND_PREVIOUS:
cur_value--;
if (cur_value < 0) {
cur_value = max_items - 1;
}
lcd_status_P(ppitems[cur_value]);
break;
}
}
}
void handle_mode_options() {
const char* ppitems[] = {S_OPTION_MACHINE_TYPE, S_OPTION_VIDEO_MODE, S_OPTION_SIGNAL, S_OPTION_KEY_REPEAT, S_OPTION_TICKER_SPEED, S_OPTION_TICKER_HOLD, S_OPTION_REC_FINALIZE, S_OPTION_REC_AUTO_FINALIZE};
uint16_t value = 0;
uint8_t save = 0;
uint8_t cur_mode = 0;
while (1) {
cur_mode = handle_select_mode(S_MODE_OPTIONS, ppitems, 8, cur_mode);
switch (cur_mode) {
case OPTION_MACHINE_TYPE:
{
const char* ppenum[] = {S_C64, S_VIC, S_C16};
value = g_machine_type;
if (handle_option_enum(S_OPTION_MACHINE_TYPE, &value, 3, ppenum)) {
save = 1;
g_machine_type = value;
}
}
break;
case OPTION_VIDEO_MODE:
{
const char* ppenum[] = {S_PAL, S_NTSC};
value = g_video_mode;
if (handle_option_enum(S_OPTION_VIDEO_MODE, &value, 2, ppenum)) {
save = 1;
g_video_mode = value;
}
}
break;
case OPTION_SIGNAL:
value = g_invert_signal;
if (handle_option_value(S_OPTION_SIGNAL, &value, 0, 1, 1)) {
g_invert_signal = value;
if (value) {
CONTROL_SET_BUS1();
} else {
CONTROL_SET_BUS0();
}
save = 1;
}
break;
case OPTION_KEY_REPEAT:
value = g_key_repeat_next * 10;
if (handle_option_value(S_OPTION_KEY_REPEAT, &value, 50, 500, 50)) {
g_key_repeat_next = value / 10;
save = 1;
}
break;
case OPTION_TICKER_SPEED:
value = g_ticker_rate * 10;
if (handle_option_value(S_OPTION_TICKER_SPEED, &value, 50, 500, 50)) {
g_ticker_rate = value / 10;
save = 1;
}
break;
case OPTION_TICKER_HOLD:
value = g_ticker_hold_rate * 10;
if (handle_option_value(S_OPTION_TICKER_HOLD, &value, 250, 2500, 250)) {
g_ticker_hold_rate = value / 10;
save = 1;
}
break;
case OPTION_REC_FINALIZE:
value = g_rec_finalize_time * 10;
if (handle_option_value(S_OPTION_REC_FINALIZE, &value, 500, 2500, 500)) {
g_rec_finalize_time = value / 10;
save = 1;
}
break;
case OPTION_REC_AUTO_FINALIZE:
value = g_rec_auto_finalize;
if (handle_option_value(S_OPTION_REC_AUTO_FINALIZE, &value, 0, 1, 1)) {
g_rec_auto_finalize = value;
save = 1;
}
break;
case SELECT_MODE_EXIT:
if (save) {
save_eeprom_data();
}
return;
break;
}
}
}
void main_menu(FILINFO* pfile_info) {
const char* ppitems[] = {S_MODE_PLAY, S_MODE_RECORD, S_MODE_OPTIONS};
uint8_t cur_mode = 0;
if ((g_num_files = get_num_files(pfile_info)) == 0) {
lcd_title_P(S_NO_FILES_FOUND);
return;
}
while (1) {
cur_mode = handle_select_mode(S_SELECT_MODE, ppitems, 3, cur_mode);
switch (cur_mode) {
case MODE_PLAY:
handle_play_mode(pfile_info);
break;
case MODE_RECORD:
handle_record_mode(pfile_info);
break;
case MODE_OPTIONS:
handle_mode_options();
break;
case SELECT_MODE_EXIT:
cur_mode = 0;
break;
}
}
}