Merge pull request #1 from sweetlilmre/select_machine

Update
This commit is contained in:
Juri Fossaroli
2015-05-05 00:16:08 +02:00
6 changed files with 226 additions and 55 deletions
+11
View File
@@ -34,7 +34,18 @@ const char S_CHDIR_FAILED[] PROGMEM = "CHDIR fail!";
const char S_READ_FAILED[] PROGMEM = "READ fail!";
const char S_OPEN_FAILED[] PROGMEM = "OPEN fail!";
const char S_INVALID_TAP[] PROGMEM = "Invalid TAP!";
const char S_INVALID_SIZE[] PROGMEM = "Invalid size!";
const char S_LOADING[] PROGMEM = "Loading:";
const char S_OPERATION_COMPLETE[] PROGMEM = "Complete!";
const char S_OPERATION_ABORTED[] PROGMEM = "Aborted!";
const char S_OPTION_MACHINE_TYPE[] PROGMEM = "Machine";
const char S_C64[] PROGMEM = "C64";
const char S_C16[] PROGMEM = "C16";
const char S_VIC[] PROGMEM = "VIC";
extern const char S_OPTION_VIDEO_MODE[] PROGMEM = "Video";
extern const char S_PAL[] PROGMEM = "PAL";
extern const char S_NTSC[] PROGMEM = "NTSC";
+10
View File
@@ -34,7 +34,17 @@ const char S_CHDIR_FAILED[] PROGMEM = "Errore CHDIR!";
const char S_READ_FAILED[] PROGMEM = "READ fallito!";
const char S_OPEN_FAILED[] PROGMEM = "OPEN fallito!";
const char S_INVALID_TAP[] PROGMEM = "TAP Invalido!";
const char S_INVALID_SIZE[] PROGMEM = "Formato non valido!";
const char S_LOADING[] PROGMEM = "Loading:";
const char S_OPERATION_COMPLETE[] PROGMEM = "Completato!";
const char S_OPERATION_ABORTED[] PROGMEM = "Annullato!";
const char S_OPTION_MACHINE_TYPE[] PROGMEM = "Machine";
const char S_C64[] PROGMEM = "C64";
const char S_C16[] PROGMEM = "C16";
const char S_VIC[] PROGMEM = "VIC";
extern const char S_OPTION_VIDEO_MODE[] PROGMEM = "Video";
extern const char S_PAL[] PROGMEM = "PAL";
extern const char S_NTSC[] PROGMEM = "NTSC";
+11
View File
@@ -37,8 +37,19 @@ extern const char S_CHDIR_FAILED[];
extern const char S_READ_FAILED[];
extern const char S_OPEN_FAILED[];
extern const char S_INVALID_TAP[];
extern const char S_INVALID_SIZE[];
extern const char S_LOADING[];
extern const char S_OPERATION_COMPLETE[];
extern const char S_OPERATION_ABORTED[];
extern const char S_OPTION_MACHINE_TYPE[];
extern const char S_C64[];
extern const char S_C16[];
extern const char S_VIC[];
extern const char S_OPTION_VIDEO_MODE[];
extern const char S_PAL[];
extern const char S_NTSC[];
#endif
+70 -13
View File
@@ -18,11 +18,13 @@
#define REC_MODE_MANUAL 0
#define REC_MODE_AUTO 1
#define OPTION_SIGNAL 0
#define OPTION_KEY_REPEAT 1
#define OPTION_TICKER_SPEED 2
#define OPTION_TICKER_HOLD 3
#define OPTION_REC_FINALIZE 4
#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 SELECT_MODE_EXIT 0xFF
@@ -279,7 +281,7 @@ void handle_record_mode(FILINFO* pfile_info) {
}
uint8_t handle_option_value(const char* ptitle, const char* poption, uint16_t* pcur_value, uint16_t min_value, uint16_t max_value, uint16_t step_value) {
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;
lcd_title_P(poption);
@@ -316,16 +318,71 @@ uint8_t handle_option_value(const char* ptitle, const char* poption, uint16_t* p
}
}
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_SIGNAL, S_OPTION_KEY_REPEAT, S_OPTION_TICKER_SPEED, S_OPTION_TICKER_HOLD, S_OPTION_REC_FINALIZE};
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};
uint16_t value = 0;
uint8_t save = 0;
while (1) {
switch (handle_select_mode(S_MODE_OPTIONS, ppitems, 5)) {
switch (handle_select_mode(S_MODE_OPTIONS, ppitems, 7)) {
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_MODE_OPTIONS, S_OPTION_SIGNAL, &value, 0, 1, 1)) {
if (handle_option_value(S_OPTION_SIGNAL, &value, 0, 1, 1)) {
g_invert_signal = value;
if (value) {
CONTROL_SET_BUS1();
@@ -337,28 +394,28 @@ void handle_mode_options() {
break;
case OPTION_KEY_REPEAT:
value = g_key_repeat_next * 10;
if (handle_option_value(S_MODE_OPTIONS, S_OPTION_KEY_REPEAT, &value, 50, 500, 50)) {
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_MODE_OPTIONS, S_OPTION_TICKER_SPEED, &value, 50, 500, 50)) {
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_MODE_OPTIONS, S_OPTION_TICKER_HOLD, &value, 250, 2500, 250)) {
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_MODE_OPTIONS, S_OPTION_REC_FINALIZE, &value, 500, 2500, 500)) {
if (handle_option_value(S_OPTION_REC_FINALIZE, &value, 500, 2500, 500)) {
g_rec_finalize_time = value / 10;
save = 1;
}
+121 -42
View File
@@ -23,13 +23,19 @@
#include "menu.h"
#ifdef USE_NTSC_TIMING
#define CYCLE_MULT_RAW 0.978 // (1000000 / 1022730 NTSC cycles)
#define CYCLE_MULT_8 7.82 // (CYCLE_MULT_RAW * 8)
#else
#define CYCLE_MULT_RAW 1.015 // (1000000 / 985248 PAL cycles)
#define CYCLE_MULT_8 8.12 // (CYCLE_MULT_RAW * 8)
#endif
typedef enum
{
C64,
VIC,
C16,
} MACHINE_TYPE;
typedef enum
{
PAL,
NSTC,
} VIDEO_MODE;
// magic strings found in the TAP header, represented as uint32_t values in little endian format (reversed string)
#define TAP_MAGIC_C64 0x2D343643 // "C64-" as "-46C"
@@ -39,11 +45,14 @@
struct TAP_INFO {
uint8_t version; // TAP file format version:
// Version 0: 8-bit data, 0x00 indicates overflow
// 1: 8-bit, 0x00 indicates 24-bit overflow to follow
// 2: same as 1 but with 2 half-wave values
uint8_t platform;
uint8_t video;
// Version 0: 8-bit data, 0x00 indicates overflow
// 1: 8-bit, 0x00 indicates 24-bit overflow to follow
// 2: same as 1 but with 2 half-wave values
uint8_t platform; // Platform 0: C64
// 1: C16
// 2: VIC
uint8_t video; // Video 0: PAL
// 1: NTSC
uint8_t reserved;
volatile uint32_t length; // total length of the TAP data excluding header in bytes
volatile uint32_t cycles; //
@@ -55,7 +64,7 @@ static struct TAP_INFO g_tap_info;
// we need this constant to determine if the loader has switched off the motor before the tap has completed
// which would cause the code to enter an endless loop (when the motor is off the buffers do not progress)
// so we check during the buffer wait loop to see if we have exceeded the maximum delay time and exit if so.
#define MAX_SIGNAL_CYCLES (CYCLE_MULT_RAW * 0xFFFFFF * 2)
#define MAX_SIGNAL_CYCLES (g_cycle_mult_raw * 0xFFFFFF * 2)
// helper variables for the ISR and loader code
@@ -70,6 +79,11 @@ static uint32_t g_pulse_length_save; // save length for read
static volatile uint32_t g_overflow; // write signal overflow timer detection
static volatile uint32_t g_timer_tick = 0; // timer tick at 100Hz (10 ms interval)
uint8_t g_machine_type = C64;
uint8_t g_video_mode = PAL;
static double g_cycle_mult_raw = 0;
static double g_cycle_mult_8 = 0;
volatile uint8_t g_invert_signal = 0; // invert the signal for transmission/reception to/from a real Datasette
volatile uint16_t g_ticker_rate = TICKER_RATE / 10;
@@ -78,6 +92,39 @@ volatile uint16_t g_key_repeat_start = KEY_REPEAT_START / 10;
volatile uint16_t g_key_repeat_next = KEY_REPEAT_NEXT / 10;
volatile uint16_t g_rec_finalize_time = REC_FINALIZE_TIME / 10;
void setup_cycle_timing() {
double ntsc_cycles_per_second;
double pal_cycles_per_second;
switch (g_machine_type)
{
case C64:
ntsc_cycles_per_second = 1022272;
pal_cycles_per_second = 985248;
break;
case VIC:
ntsc_cycles_per_second = 1022727;
pal_cycles_per_second = 1108404;
break;
case C16:
ntsc_cycles_per_second = 894886;
pal_cycles_per_second = 886724;
break;
}
switch(g_video_mode)
{
case PAL:
g_cycle_mult_raw = (1000000.0 / pal_cycles_per_second);
break;
case NSTC:
g_cycle_mult_raw = (1000000.0 / ntsc_cycles_per_second);
break;
}
g_cycle_mult_8 = (g_cycle_mult_raw * 8.0);
}
uint32_t get_timer_tick() {
return g_timer_tick;
}
@@ -93,7 +140,7 @@ ISR(TIMER1_CAPT_vect) {
// start counting here
g_overflow = 0;
TCNT1 = 0;
tap_data = g_pulse_length / CYCLE_MULT_8; // get the standard divided value
tap_data = g_pulse_length / g_cycle_mult_8; // get the standard divided value
if (tap_data == 0) { // safe guard
tap_data++;
@@ -102,7 +149,7 @@ ISR(TIMER1_CAPT_vect) {
g_fat_buffer[g_read_index++] = (uint8_t) tap_data;
g_tap_file_pos++;
} else { // long signal
tap_data = g_pulse_length / CYCLE_MULT_RAW; // get the raw divided value (cycles)
tap_data = g_pulse_length / g_cycle_mult_raw; // get the raw divided value (cycles)
g_fat_buffer[g_read_index++] = 0;
g_fat_buffer[g_read_index++] = (uint8_t) (tap_data & 0xff);
g_fat_buffer[g_read_index++] = (uint8_t) ((tap_data & 0xff00) >> 8);
@@ -122,6 +169,7 @@ ISR(TIMER1_OVF_vect){
g_overflow++;
}
// timer1 is running at 2MHz or 0.5 uS per tick.
// signal values are measured in uS, so OCR1A is set to the value from the TAP file (converted into uS) for each signal half
// i.e. TAP value converted to uS * 2 == full signal length
@@ -168,21 +216,43 @@ ISR(TIMER1_COMPA_vect) {
}
tap_data = (unsigned long) g_fat_buffer[g_read_index++];
g_tap_file_pos++;
if (tap_data == 0) {
// code for format 0 handling
if (g_tap_info.version == 0) {
g_pulse_length = 256 * CYCLE_MULT_8;
// code for format 0 handling
if (g_tap_info.version == 0 && tap_data == 0) {
tap_data = 256;
}
if (tap_data != 0) {
g_pulse_length = tap_data * g_cycle_mult_8;
} else {
g_pulse_length = (unsigned long) g_fat_buffer[g_read_index++];
g_pulse_length |= ((unsigned long) g_fat_buffer[g_read_index++]) << 8;
g_pulse_length |= ((unsigned long) g_fat_buffer[g_read_index++]) << 16;
g_pulse_length *= g_cycle_mult_raw;
g_tap_file_pos += 3;
}
if (g_tap_info.version != 2) {
g_pulse_length_save = g_pulse_length; // save this for the 2nd half of the wave
} else {
// format 2 is half-wave and timer is running at 2Mhz so double
g_pulse_length <<= 1;
// now read second half-wave for C16 / Plus4 format
tap_data = (unsigned long) g_fat_buffer[g_read_index++];
g_tap_file_pos++;
if (tap_data != 0) {
g_pulse_length_save = tap_data * g_cycle_mult_8;
} else {
g_pulse_length = (unsigned long) g_fat_buffer[g_read_index++];
g_pulse_length |= ((unsigned long) g_fat_buffer[g_read_index++]) << 8;
g_pulse_length |= ((unsigned long) g_fat_buffer[g_read_index++]) << 16;
g_pulse_length *= CYCLE_MULT_RAW;
g_pulse_length_save = (unsigned long) g_fat_buffer[g_read_index++];
g_pulse_length_save |= ((unsigned long) g_fat_buffer[g_read_index++]) << 8;
g_pulse_length_save |= ((unsigned long) g_fat_buffer[g_read_index++]) << 16;
g_pulse_length_save *= g_cycle_mult_raw;
g_tap_file_pos += 3;
}
} else {
g_pulse_length = tap_data * CYCLE_MULT_8;
// format 2 is half-wave and timer is running at 2Mhz so double
g_pulse_length_save <<= 1;
}
g_pulse_length_save = g_pulse_length; // save this for the 2nd half of the wave
if (g_pulse_length > 0xFFFF) { // check to see if its bigger than 16 bits
g_pulse_length -= 0xFFFF;
OCR1A = 0xFFFF;
@@ -268,8 +338,9 @@ int verify_tap(FILINFO* pfile_info) {
// check size first
if (g_tap_info.length != (pfile_info->fsize - 20)) {
lcd_title_P(S_INVALID_TAP);
return 0;
lcd_title_P(S_INVALID_SIZE);
g_tap_info.length = pfile_info->fsize - 20;
lcd_busy_spinner();
}
uint32_t* tap_magic = (uint32_t*) g_fat_buffer;
@@ -302,6 +373,8 @@ int play_file(FILINFO* pfile_info)
int perc = 0;
g_tap_file_complete = 0;
setup_cycle_timing();
if (!verify_tap(pfile_info)) {
lcd_busy_spinner();
return 0;
@@ -394,6 +467,8 @@ void record_file(char* pfile_name) {
g_tap_file_complete = 0;
g_tap_file_pos = 0;
setup_cycle_timing();
if (pfile_name == NULL) {
// generate a filename
br = 0;
@@ -522,24 +597,28 @@ if((uint8_t)(val) != eeprom_read_byte((loc))) \
#endif
void load_eeprom_data() {
if (eeprom_read_byte((uint8_t *) 0) == 0xE7) {
// g_invert_signal = eeprom_read_byte((uint8_t *) 1);
g_ticker_rate = eeprom_read_byte((uint8_t *) 2);
g_ticker_hold_rate = eeprom_read_byte((uint8_t *) 3);
g_key_repeat_start = eeprom_read_byte((uint8_t *) 4);
g_key_repeat_next = eeprom_read_byte((uint8_t *) 5);
g_rec_finalize_time = eeprom_read_byte((uint8_t *) 6);
if (eeprom_read_byte((uint8_t *) 0) == 0xB6) {
g_machine_type = eeprom_read_byte((uint8_t *) 1);
g_video_mode = eeprom_read_byte((uint8_t *) 2);
g_ticker_rate = eeprom_read_byte((uint8_t *) 3);
g_ticker_hold_rate = eeprom_read_byte((uint8_t *) 4);
g_key_repeat_start = eeprom_read_byte((uint8_t *) 5);
g_key_repeat_next = eeprom_read_byte((uint8_t *) 6);
g_rec_finalize_time = eeprom_read_byte((uint8_t *) 7);
}
}
void save_eeprom_data() {
eeprom_update_byte((uint8_t *) 0, 0xE7);
// eeprom_update_byte((uint8_t *) 1, g_invert_signal);
eeprom_update_byte((uint8_t *) 2, g_ticker_rate);
eeprom_update_byte((uint8_t *) 3, g_ticker_hold_rate);
eeprom_update_byte((uint8_t *) 4, g_key_repeat_start);
eeprom_update_byte((uint8_t *) 5, g_key_repeat_next);
eeprom_update_byte((uint8_t *) 6, g_rec_finalize_time);
eeprom_update_byte((uint8_t *) 0, 0xB6);
eeprom_update_byte((uint8_t *) 1, g_machine_type);
eeprom_update_byte((uint8_t *) 2, g_video_mode);
eeprom_update_byte((uint8_t *) 3, g_ticker_rate);
eeprom_update_byte((uint8_t *) 4, g_ticker_hold_rate);
eeprom_update_byte((uint8_t *) 5, g_key_repeat_start);
eeprom_update_byte((uint8_t *) 6, g_key_repeat_next);
eeprom_update_byte((uint8_t *) 7, g_rec_finalize_time);
}
int tapuino_hardware_setup(void)
+3
View File
@@ -14,5 +14,8 @@ extern volatile uint8_t g_ticker_rate;
extern volatile uint8_t g_ticker_hold_rate;
extern volatile uint8_t g_key_repeat_next;
extern volatile uint8_t g_rec_finalize_time;
extern uint8_t g_machine_type;
extern uint8_t g_video_mode;
#endif