mirror of
https://github.com/sweetlilmre/tapuino.git
synced 2026-07-28 04:05:49 +00:00
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user