diff --git a/Cart_Reader/Cart_Reader.ino b/Cart_Reader/Cart_Reader.ino index 11b4940c..28eeb48d 100644 --- a/Cart_Reader/Cart_Reader.ino +++ b/Cart_Reader/Cart_Reader.ino @@ -66,7 +66,6 @@ *****************************************/ // SD Card -#include "SdFat.h" SdFs sd; FsFile myFile; #ifdef global_log @@ -2117,83 +2116,92 @@ int32_t initializeClockOffset() { Setup *****************************************/ void setup() { -#if !defined(enable_serial) && defined(ENABLE_UPDATER) - ClockedSerial.begin(UPD_BAUD); -#endif - // Set Button Pin PG2 to Input DDRG &= ~(1 << 2); -#if defined(HW5) && !defined(ENABLE_VSELECT) - // HW5 has status LED connected to PD7 - // Set LED Pin PD7 to Output +# if defined(HW5) && !defined(ENABLE_VSELECT) + /** + * HW5 has status LED connected to PD7 + * Set LED Pin PD7 to Output + **/ DDRD |= (1 << 7); PORTD |= (1 << 7); -#elif defined(ENABLE_VSELECT) +# elif defined(ENABLE_VSELECT) + /** + * VSELECT uses pin PD7 + * Set LED Pin PD7 to Output + **/ DDRD |= (1 << 7); -#else - // HW1/2/3 have button connected to PD7 - // Set Button Pin PD7 to Input +# else /* !defined(HW5) && !defined(HW5) */ + /** + * HW1-3 have button connected to PD7 + * Set pin PD7 to input for button + **/ DDRD &= ~(1 << 7); -#endif - // Activate Internal Pullup Resistors - //PORTG |= (1 << 2); - //PORTD |= (1 << 7); +# endif /* HW5 &| ENABLE_VSELECT */ + + // Set power to low to protect carts + setVoltage(VOLTS_SET_3V3); + +# if defined(ENABLE_3V3FIX) + // Set clock high during setup + setClockScale(CLKSCALE_16MHZ); + delay(10); +# endif /* ENABLE_3V3FIX */ +# if !defined(enable_serial) && defined(ENABLE_UPDATER) + ClockedSerial.begin(UPD_BAUD); + printVersionToSerial(); + ClockedSerial.flush(); +# endif /* ENABLE_UPDATER */ - // Read current folder number out of eeprom + // Read current folder number out of the EEPROM EEPROM_readAnything(0, foldern); if (foldern < 0) foldern = 0; -#ifdef enable_LCD +# ifdef enable_LCD display.begin(); display.setContrast(40); display.setFont(u8g2_font_haxrcorp4089_tr); -#endif +# endif /* enable_LCD */ -#ifdef enable_neopixel -#if defined(ENABLE_3V3FIX) - // Set power high for neopixel - setVoltage(VOLTS_SET_5V); - delay(10); -#endif +# ifdef enable_neopixel pixels.begin(); - pixels.clear(); - pixels.setPixelColor(0, pixels.Color(background_color)); - pixels.setPixelColor(1, pixels.Color(0, 0, 100)); - pixels.setPixelColor(2, pixels.Color(0, 0, 100)); - pixels.show(); + setColor_RGB(0, 0, 100); // Set TX0 LED Pin(PE1) to Output for status indication during flashing for HW4 -#if !(defined(enable_serial) || defined(HW5)) +# if !(defined(enable_serial) || defined(HW5)) DDRE |= (1 << 1); -#endif -#else -#ifndef enable_LCD -#ifdef CA_LED +# endif /* enable_serial */ +# else /* enable_neopixel */ +# ifndef enable_LCD +# ifdef CA_LED // Turn LED off digitalWrite(12, 1); digitalWrite(11, 1); digitalWrite(10, 1); -#endif +# endif /* CA_LED */ // Configure 4 Pin RGB LED pins as output DDRB |= (1 << DDB6); // Red LED (pin 12) DDRB |= (1 << DDB5); // Green LED (pin 11) DDRB |= (1 << DDB4); // Blue LED (pin 10) -#endif -#endif +# endif /* enable_LCD */ +# endif /* enable_neopixel */ -#ifdef ENABLE_VSELECT - // Set power to low to protect carts - setVoltage(VOLTS_SET_3V3); -#endif +# ifdef RTC_installed + // Start RTC + RTCStart(); -#ifdef enable_OLED + // Set Date/Time Callback Funtion + SdFile::dateTimeCallback(dateTime); +# endif /* RTC_installed */ + +# ifdef enable_OLED display.begin(); //isplay.setContrast(40); display.setFont(u8g2_font_haxrcorp4089_tr); -#endif +# endif /* enable_OLED */ -#ifdef enable_serial +# ifdef enable_serial // Serial Begin Serial.begin(9600); Serial.println(""); @@ -2201,52 +2209,73 @@ void setup() { Serial.println(F("2023 github.com/sanni")); // LED Error setColor_RGB(0, 0, 255); -#endif +# endif /* enable_serial */ // Init SD card if (!sd.begin(SS)) { display_Clear(); +# ifdef ENABLE_VSELECT + print_STR(sd_error_STR, 1); + println_Msg(F("")); + println_Msg(F("Press button to enable 5V for")); + println_Msg(F(" updating firmware...")); + display_Update(); + wait(); + display_Clear(); + setVoltage(VOLTS_SET_5V); // Set voltage high for flashing + println_Msg(F(" ======== UPDATE MODE ======== ")); + println_Msg(F("Waiting for update...")); + println_Msg(F("")); + println_Msg(F("Press button to cancel/restart.")); + display_Update(); + wait(); + resetArduino(); +# else /* !ENABLE_VSELECT */ print_FatalError(sd_error_STR); +# endif /* ENABLE_VSELECT */ } -#if !defined(enable_serial) && defined(ENABLE_UPDATER) - printVersionToSerial(); - ClockedSerial.flush(); -#endif +# if defined(ENABLE_CONFIG) + configInit(); +# if defined(global_log) + loggingEnabled = !!configGetLong(F("oscr.logging"), 1); +# endif /*ENABLE_CONFIG*/ -#ifdef global_log + // Change LCD background if config specified +# ifdef enable_neopixel + setColor_RGB(0, 0, 100); +# endif /* enable_neopixel */ +# endif /* ENABLE_CONFIG */ + +# ifdef global_log if (!myLog.open("OSCR_LOG.txt", O_RDWR | O_CREAT | O_APPEND)) { print_FatalError(sd_error_STR); } println_Msg(F("")); -#if defined(HW1) +# if defined(HW1) print_Msg(F("OSCR HW1")); -#elif defined(HW2) +# elif defined(HW2) print_Msg(F("OSCR HW2")); -#elif defined(HW3) +# elif defined(HW3) print_Msg(F("OSCR HW3")); -#elif defined(HW4) +# elif defined(HW4) print_Msg(F("OSCR HW4")); -#elif defined(HW5) +# elif defined(HW5) print_Msg(F("OSCR HW5")); -#elif defined(SERIAL_MONITOR) +# elif defined(SERIAL_MONITOR) print_Msg(F("OSCR Serial")); -#endif +# endif /* HWn */ print_Msg(F(" V")); println_Msg(ver); -#endif +# endif /* global_log */ -#ifdef RTC_installed - // Start RTC - RTCStart(); - - // Set Date/Time Callback Funtion - SdFile::dateTimeCallback(dateTime); -#endif - - // status LED ON + // Turn status LED on statusLED(true); +# if defined(ENABLE_3V3FIX) + setClockScale(CLKSCALE_8MHZ); // Set clock back to low after setup +# endif /* ENABLE_3V3FIX */ + // Start menu system mainMenu(); } @@ -2273,15 +2302,31 @@ void dataIn() { // Set RGB color void setColor_RGB(byte r, byte g, byte b) { #if defined(enable_neopixel) -#if defined(ENABLE_3V3FIX) +# if defined(ENABLE_3V3FIX) if (clock == CS_8MHZ) return; -#endif +# endif // Dim Neopixel LEDs if (r >= 100) r = 100; if (g >= 100) g = 100; if (b >= 100) b = 100; + pixels.clear(); + +# if defined(ENABLE_CONFIG) + uint8_t lcdConfColor = configGetLong(F("lcd.confColor")); + + if (lcdConfColor > 0) { + uint8_t lcdRed = configGetLong(F("lcd.red")); + uint8_t lcdGreen = configGetLong(F("lcd.green")); + uint8_t lcdBlue = configGetLong(F("lcd.blue")); + + pixels.setPixelColor(0, pixels.Color(lcdGreen, lcdRed, lcdBlue)); + } else { + pixels.setPixelColor(0, pixels.Color(background_color)); + } +# else /* !ENABLE_CONFIG */ pixels.setPixelColor(0, pixels.Color(background_color)); +# endif /* ENABLE_CONFIG */ pixels.setPixelColor(1, pixels.Color(g, r, b)); pixels.setPixelColor(2, pixels.Color(g, r, b)); pixels.show(); @@ -2465,7 +2510,7 @@ void print_Msg(const __FlashStringHelper* string) { Serial.print(string); #endif #ifdef global_log - if (!dont_log) myLog.print(string); + if (!dont_log && loggingEnabled) myLog.print(string); #endif } @@ -2494,7 +2539,7 @@ void print_Msg(const char myString[]) { Serial.print(myString); #endif #ifdef global_log - if (!dont_log) myLog.print(myString); + if (!dont_log && loggingEnabled) myLog.print(myString); #endif } @@ -2506,7 +2551,7 @@ void print_Msg(long unsigned int message) { Serial.print(message); #endif #ifdef global_log - if (!dont_log) myLog.print(message); + if (!dont_log && loggingEnabled) myLog.print(message); #endif } @@ -2518,7 +2563,7 @@ void print_Msg(byte message, int outputFormat) { Serial.print(message, outputFormat); #endif #ifdef global_log - if (!dont_log) myLog.print(message, outputFormat); + if (!dont_log && loggingEnabled) myLog.print(message, outputFormat); #endif } @@ -2530,7 +2575,7 @@ void print_Msg(word message, int outputFormat) { Serial.print(message, outputFormat); #endif #ifdef global_log - if (!dont_log) myLog.print(message, outputFormat); + if (!dont_log && loggingEnabled) myLog.print(message, outputFormat); #endif } @@ -2542,7 +2587,7 @@ void print_Msg(int message, int outputFormat) { Serial.print(message, outputFormat); #endif #ifdef global_log - if (!dont_log) myLog.print(message, outputFormat); + if (!dont_log && loggingEnabled) myLog.print(message, outputFormat); #endif } @@ -2554,7 +2599,7 @@ void print_Msg(long unsigned int message, int outputFormat) { Serial.print(message, outputFormat); #endif #ifdef global_log - if (!dont_log) myLog.print(message, outputFormat); + if (!dont_log && loggingEnabled) myLog.print(message, outputFormat); #endif } @@ -2566,7 +2611,7 @@ void print_Msg(String string) { Serial.print(string); #endif #ifdef global_log - if (!dont_log) myLog.print(string); + if (!dont_log && loggingEnabled) myLog.print(string); #endif } @@ -2595,7 +2640,7 @@ void println_Msg(String string) { Serial.println(string); #endif #ifdef global_log - if (!dont_log) myLog.println(string); + if (!dont_log && loggingEnabled) myLog.println(string); #endif } @@ -2608,7 +2653,7 @@ void println_Msg(byte message, int outputFormat) { Serial.println(message, outputFormat); #endif #ifdef global_log - if (!dont_log) myLog.println(message, outputFormat); + if (!dont_log && loggingEnabled) myLog.println(message, outputFormat); #endif } @@ -2638,7 +2683,7 @@ void println_Msg(const char myString[]) { Serial.println(myString); #endif #ifdef global_log - if (!dont_log) myLog.println(myString); + if (!dont_log && loggingEnabled) myLog.println(myString); #endif } @@ -2654,7 +2699,7 @@ void println_Msg(const __FlashStringHelper* string) { char myBuffer[15]; strlcpy_P(myBuffer, (char*)string, 15); if ((strncmp(myBuffer, "Press Button...", 14) != 0) && (strncmp(myBuffer, "Select file", 10) != 0)) { - if (!dont_log) myLog.println(string); + if (!dont_log && loggingEnabled) myLog.println(string); } #endif } @@ -2668,7 +2713,7 @@ void println_Msg(long unsigned int message) { Serial.println(message); #endif #ifdef global_log - if (!dont_log) myLog.println(message); + if (!dont_log && loggingEnabled) myLog.println(message); #endif } @@ -2680,7 +2725,7 @@ void display_Update() { delay(100); #endif #ifdef global_log - if (!dont_log) myLog.flush(); + if (!dont_log && loggingEnabled) myLog.flush(); #endif } @@ -2690,7 +2735,7 @@ void display_Clear() { display.setCursor(0, 8); #endif #ifdef global_log - if (!dont_log) myLog.println(""); + if (!dont_log && loggingEnabled) myLog.println(""); #endif } @@ -2980,41 +3025,50 @@ void checkUpdater() { if (ClockedSerial.available() > 0) { String cmd = ClockedSerial.readStringUntil('\n'); cmd.trim(); - if (cmd == "VERCHK") { + if (cmd == "VERCHK") + { // VERCHK: Gets OSCR version and features delay(500); printVersionToSerial(); - } else if (cmd == "GETCLOCK") { -#if defined(ENABLE_3V3FIX) + } + else if (cmd == "GETCLOCK") + { // GETCLOCK: Gets the MEGA's current clock speed. +# if defined(ENABLE_3V3FIX) ClockedSerial.print(F("Clock is running at ")); ClockedSerial.print((clock == CS_16MHZ) ? 16UL : 8UL); ClockedSerial.println(F("MHz")); -#else +# else /* !ENABLE_3V3FIX */ ClockedSerial.println(F("Dynamic clock speed (3V3FIX) is not enabled.")); -#endif - } else if (cmd == "GETVOLTS") { -#if defined(ENABLE_VSELECT) +# endif /* ENABLE_3V3FIX */ + } + else if (cmd.substring(1, 8) == "ETVOLTS") + { // (G/S)ETVOLTS: Get and set the voltage. +# if defined(ENABLE_VSELECT) + if (cmd != "GETVOLTS") { + switch(cmd.substring(9, 10).toInt()) { + case 3: setVoltage(VOLTS_SET_3V3); break; + case 5: setVoltage(VOLTS_SET_5V); break; + } + } ClockedSerial.print(F("Voltage is set to ")); ClockedSerial.print((voltage == VOLTS_SET_5V) ? 5 : 3.3); ClockedSerial.println(F("V")); -#else +# else /* !ENABLE_VSELECT */ ClockedSerial.println(F("Automatic voltage selection (VSELECT) is not enabled.")); -#endif - } else if (cmd == "GETTIME") { -#if defined(RTC_installed) - ClockedSerial.print(F("Current Time: ")); - ClockedSerial.println(RTCStamp()); -#else - ClockedSerial.println(F("RTC not installed")); -#endif - } else if (cmd.substring(0, 7) == "SETTIME") { -#if defined(RTC_installed) - ClockedSerial.println(F("Setting Time...")); - rtc.adjust(DateTime(cmd.substring(8).toInt())); +# endif /* ENABLE_VSELECT */ + } + // RTC commands + else if (cmd.substring(1, 7) == "ETTIME") + { // (G/S)ETTIME: Get and set the date/time. +# if defined(RTC_installed) + if (cmd != "GETTIME") { + ClockedSerial.println(F("Setting Time...")); + rtc.adjust(DateTime(cmd.substring(8).toInt())); + } ClockedSerial.print(F("Current Time: ")); ClockedSerial.println(RTCStamp()); -#else +# else /* !RTC_installed */ ClockedSerial.println(F("RTC not installed")); -#endif +# endif /* RTC_installed */ } else { ClockedSerial.println(F("OSCR: Unknown Command")); } diff --git a/Cart_Reader/Config.h b/Cart_Reader/Config.h index 68080a90..47dce287 100644 --- a/Cart_Reader/Config.h +++ b/Cart_Reader/Config.h @@ -288,9 +288,30 @@ /*==== FIRMWARE OPTIONS ===========================================*/ +/* [ Config File -------------------------------------------------- ] + Allow changing some configuration values via a config file. You + generally can only use the config to set options or disable + certain featuress. It cannot be used to toggle firmware options + on, only off. + + Note For Developers: See OSCR.* for info. + + Filename: config.txt +*/ + +//#define ENABLE_CONFIG + +/****/ + /* [ LCD: Background Color ---------------------------------------- ] Set the backlight color of the LCD if you have one. + Can be set using config: + lcd.confColor=1 + lcd.red=0 + lcd.green=0 + lcd.blue=0 + PARAMETERS: Green, Red, Blue */ @@ -332,6 +353,9 @@ /* [ Logging ------------------------------------------------------ ] Write all info to OSCR_LOG.txt in root dir + + Can be toggled off using config: + oscr.logging=0 */ #define global_log @@ -367,13 +391,26 @@ 0: Output each byte once. Not supported by emulators. (default) 1: Duplicate each byte. Usable by Kega Fusion. 2: Same as 1 + pad with 0xFF so that the file size is 64KB. + + ** + ** DEPRECATED: Use the config file instead. See below. + ** */ //#define use_md_conf /* - Alternatively, define it here by uncommenting and changing the - following line. Setting both allows you to change the default. + Configure how the MD core saves are formatted. + + Can be set using config: + md.sramType=0 + + If config is enabled, this option does nothing -- use the config. + + Options: + 0: Output each byte once. Not supported by emulators. (default) + 1: Duplicate each byte. Usable by Kega Fusion. + 2: Same as 1 + pad with 0xFF so that the file size is 64KB. */ //#define DEFAULT_VALUE_segaSram16bit 0 @@ -404,39 +441,47 @@ You probably shouldn't change this stuff! */ +#if defined(ENABLE_CONFIG) +# define CONFIG_FILE "config.txt" +// Define the max length of the key=value pairs +// Do your best not to have to increase these. +# define CONFIG_KEY_MAX 32 +# define CONFIG_VALUE_MAX 32 +#endif + #if (defined(HW4) || defined(HW5)) -#define enable_LCD -#define enable_neopixel -#define enable_rotary -//#define rotate_counter_clockwise -#define clockgen_installed -#define fastcrc -#define ws_adapter_v2 +# define enable_LCD +# define enable_neopixel +# define enable_rotary +//# define rotate_counter_clockwise +# define clockgen_installed +# define fastcrc +# define ws_adapter_v2 #endif #if (defined(HW2) || defined(HW3)) -#define enable_OLED -#define enable_Button2 -#define clockgen_installed -#define CA_LED -#define fastcrc +# define enable_OLED +# define enable_Button2 +# define clockgen_installed +# define CA_LED +# define fastcrc #endif #if defined(HW1) -#define enable_OLED +# define enable_OLED //#define clockgen_installed //#define fastcrc #endif #if defined(SERIAL_MONITOR) -#define enable_serial +# define enable_serial //#define clockgen_installed //#define fastcrc #endif /* Firmware updater only works with HW3 and HW5 */ #if !(defined(HW5) || defined(HW3)) -#undef ENABLE_UPDATER +# undef ENABLE_UPDATER #endif /* End of settings */ diff --git a/Cart_Reader/MD.ino b/Cart_Reader/MD.ino index a5585dcd..c6e7f3e4 100644 --- a/Cart_Reader/MD.ino +++ b/Cart_Reader/MD.ino @@ -87,11 +87,20 @@ unsigned long bramSize = 0; // REALTEC MAPPER boolean realtec = 0; -#ifndef DEFAULT_VALUE_segaSram16bit -#define DEFAULT_VALUE_segaSram16bit 0 -#endif +#if defined(ENABLED_CONFIG) + +int segaSram16bit = 0; + +#else /* !ENABLED_CONFIG */ + +# ifndef DEFAULT_VALUE_segaSram16bit +# define DEFAULT_VALUE_segaSram16bit 0 +# endif /* !DEFAULT_VALUE_segaSram16bit */ + int segaSram16bit = DEFAULT_VALUE_segaSram16bit; +#endif /* ENABLED_CONFIG */ + //***************************************** // SONIC & KNUCKLES LOCK-ON MODE VARIABLES // SnKmode : @@ -111,12 +120,15 @@ static word chksumSonic2 = 0x0635; /****************************************** Configuration *****************************************/ -#ifdef use_md_conf +#if defined(use_md_conf) && !defined(ENABLE_CONFIG) + +#warning "DEPRECATED: use_md_conf is deprecated. You should use ENABLE_CONFIG instead." + void mdLoadConf() { if (myFile.open("mdconf.txt", O_READ)) { char line[64]; - int n; - int i; + unsigned int n; + unsigned int i; while ((n = myFile.fgets(line, sizeof(line) - 1)) > 0) { // preprocess for (i = 0; i < n; i++) { @@ -467,9 +479,11 @@ void setup_MD() { // Request 5V setVoltage(VOLTS_SET_5V); -#ifdef use_md_conf +#if defined(ENABLE_CONFIG) + segaSram16bit = configGetLong(F("md.sramType")); +#elif defined(use_md_conf) mdLoadConf(); -#endif +#endif /*ENABLE_CONFIG*/ // Set Address Pins to Output //A0-A7 diff --git a/Cart_Reader/OSCR.cpp b/Cart_Reader/OSCR.cpp index 1965180a..70b96be5 100644 --- a/Cart_Reader/OSCR.cpp +++ b/Cart_Reader/OSCR.cpp @@ -7,7 +7,10 @@ * Contains various enums, variables, etc, for the main program. * * PUBLIC FUNCTIONS : -* void setClockScale( VOLTS ) +* void setClockScale( ClockScale ) +* VOLTS setVoltage( Voltage ) +* long configGetLong( Key, OnFailure ) +* String configGetStr( Key ) * * NOTES : * This file is a WIP, I've been moving things into it on my local working @@ -32,6 +35,7 @@ * CHANGES : * * REF NO VERSION DATE WHO DETAIL +* 13.2 2024-02-29 Ancyker Add config support * 12.5 2023-03-29 Ancyker Initial version * *H*/ @@ -41,7 +45,7 @@ /*==== VARIABLES ==================================================*/ // Firmware Version -char ver[5] = "13.1"; +char ver[5] = "13.2"; // Clock speed unsigned long clock = CS_16MHZ; @@ -49,6 +53,22 @@ unsigned long clock = CS_16MHZ; // Voltage VOLTS voltage = VOLTS_SET_5V; +#if defined(ENABLE_CONFIG) + +FsFile configFile; +bool useConfig = false; + +# if defined(global_log) +// Logging +bool loggingEnabled = true; +# endif /* global_log */ +#else /* !ENABLE_CONFIG */ +# if defined(global_log) +// Logging: Define it as true using a const instead. +const bool loggingEnabled = true; +# endif /* global_log */ +#endif /* ENABLE_CONFIG */ + /*==== /VARIABLES =================================================*/ /*F****************************************************************** @@ -107,7 +127,8 @@ void printVersionToSerial() {} * * INPUTS : * PARAMETERS: -* VOLTS ClockScale Clock scale +* VOLTS ClockScale Clock scale +* CLKSCALE ClockScale Clock scale * * PROCESS : * [1] Enable clock prescaler change @@ -139,6 +160,24 @@ void setClockScale(VOLTS __x) ); /*[2]*/ } +void setClockScale(CLKSCALE __x) +{ + clock = (__x == CLKSCALE_16MHZ ? CS_16MHZ : CS_8MHZ); + uint8_t __tmp = _BV(CLKPCE); /*[1]*/ + __asm__ __volatile__ ( + "in __tmp_reg__,__SREG__" "\n\t" + "cli" "\n\t" + "sts %1, %0" "\n\t" + "sts %1, %2" "\n\t" + "out __SREG__, __tmp_reg__" + : /* no outputs */ + : "d" (__tmp), + "M" (_SFR_MEM_ADDR(CLKPR)), + "d" (__x) + : "r0" + ); /*[2]*/ +} + /*F****************************************************************** * NAME : VOLTS setVoltage( Voltage ) * @@ -263,3 +302,146 @@ VOLTS setVoltage(VOLTS newVoltage __attribute__((unused))) { return VOLTS_NOTENABLED; } #endif + +#if defined(ENABLE_CONFIG) + +/*F****************************************************************** +* NAME : void configInit() +* +* DESCRIPTION : Setup the config file. +* +*F*/ +void configInit() { + useConfig = configFile.open(CONFIG_FILE, O_READ); +} + +/*F****************************************************************** +* NAME : uint8_t configFindKey( Key, Value ) +* +* DESCRIPTION : Search for a key=value pair. +* +* INPUTS : +* PARAMETERS: +* __FlashStringHelper Key The key to get the value for. +* char* value Variable to store the value in. +* +* OUTPUTS : +* RETURN : +* Type: uint8_t Length of the value. +* +* PROCESS : +* [1] Get key length and convert to char array/string. +* [2] Parse file line by line. +* [3] Check if key in file matches. +* [4] Copy string after equals character. +* [5] Add null terminator. +* +* NOTES : +* You aren't meant to use this function directly. Check the +* functions configGetStr() and configGetLong(). +* +*F*/ +uint8_t configFindKey(const __FlashStringHelper* searchKey, char* value) { + if (!useConfig) return 0; + + char key[CONFIG_KEY_MAX + 1]; + char buffer[CONFIG_KEY_MAX + CONFIG_VALUE_MAX + 4]; + int keyLen = 0; + int valueLen = 0; + + keyLen = strlcpy_P(key, reinterpret_cast(searchKey), CONFIG_KEY_MAX); /*[1]*/ + + configFile.rewind(); + + while (configFile.available()) { /*[2]*/ + int bufferLen = configFile.readBytesUntil('\n', buffer, CONFIG_KEY_MAX + CONFIG_VALUE_MAX + 3); + + if (buffer[bufferLen - 1] == '\r') + bufferLen--; + + if (bufferLen > (keyLen + 1)) { + if (memcmp(buffer, key, keyLen) == 0) { /*[3]*/ + if (buffer[keyLen] == '=') { /*[4]*/ + valueLen = bufferLen - keyLen - 1; + memcpy(&value[0], &buffer[keyLen + 1], valueLen); + value[valueLen] = '\0'; /*[5]*/ + break; + } + } + } + } + + return valueLen; +} + +/*F****************************************************************** +* NAME : String configGetStr( Key ) +* +* DESCRIPTION : Return the value of a key as a string. +* +* INPUTS : +* PARAMETERS: +* __FlashStringHelper Key The key to get the value for. +* +* OUTPUTS : +* RETURN : +* Type: String The value of the key or an empty string. +* +* PROCESS : +* [1] Find the key via configFindKey(). +* [2] Return empty if nothing was found. +* [3] Convert to String type. +* +* NOTES : +* You can use this to get strings stored in the config file. +* Take care when allocating memory for strings. You should +* probably use malloc for it if it's a global variable. If +* you do, make sure to free() it after it's not needed. +* +*F*/ +String configGetStr(const __FlashStringHelper* key) { + if (!useConfig) return {}; + char value[CONFIG_VALUE_MAX + 1]; + + uint8_t valueLen = configFindKey(key, value); /*[1]*/ + if (valueLen < 1) return {}; /*[2]*/ + + String stringVal(value); /*[3]*/ + + return stringVal; +} + +/*F****************************************************************** +* NAME : long configGetLong( Key, OnFailure ) +* +* DESCRIPTION : Return the value of a key as an int/long. +* +* INPUTS : +* PARAMETERS: +* __FlashStringHelper Key The key to get the value for. +* int onFail Value to return on failure. (def=0) +* +* OUTPUTS : +* RETURN : +* Type: int The value of the key or onFail. +* +* PROCESS : +* [1] Find the key via configFindKey(). +* [2] Return onFail if nothing was found. +* [3] Convert to long int type and return. +* +* NOTES : +* You can specify hex, i.e. 0xFF for 255, if you want to. +* +*F*/ +long configGetLong(const __FlashStringHelper* key, int onFail) { + if (!useConfig) return onFail; + char value[CONFIG_VALUE_MAX + 1]; + + uint8_t valueLen = configFindKey(key, value); /*[1]*/ + if (valueLen < 1) return onFail; /*[2]*/ + + return strtol(value, NULL, 0); /*[3]*/ +} + +#endif /* ENABLE_CONFIG */ diff --git a/Cart_Reader/OSCR.h b/Cart_Reader/OSCR.h index 8b6e3506..5bbe99ea 100644 --- a/Cart_Reader/OSCR.h +++ b/Cart_Reader/OSCR.h @@ -10,6 +10,7 @@ #include #include #include +#include "SdFat.h" #include "Config.h" @@ -29,6 +30,13 @@ const uint16_t UPD_BAUD = 9600; const unsigned long CS_16MHZ = 16000000UL; const unsigned long CS_8MHZ = 8000000UL; +// ENUM for VSELECT & 3V3FIX +enum CLKSCALE: uint8_t { + // Paramters to pass to setVoltage() and setClockScale() + CLKSCALE_16MHZ = 0, // ClockScale 0 = 16MHz + CLKSCALE_8MHZ, // ClockScale 1 = 8MHz +}; + // ENUM for VSELECT & 3V3FIX enum VOLTS: uint8_t { // Paramters to pass to setVoltage() and setClockScale() @@ -47,11 +55,37 @@ extern unsigned long clock; extern char ver[5]; extern VOLTS voltage; +#if defined(ENABLE_CONFIG) + /** + * Config File Stuff + * + * You can register GLOBAL configuration variables in this section. + * You should put core-specific config variables in the related file. + **/ + + extern bool useConfig; +# ifdef global_log + extern bool loggingEnabled; +# endif /* global_log */ +#else /* !ENABLE_CONFIG */ +# ifdef global_log + extern const bool loggingEnabled; +# endif /* global_log */ +#endif /* ENABLE_CONFIG */ + /*==== FUNCTIONS ==================================================*/ extern void printVersionToSerial(); extern void setClockScale(VOLTS __x); +extern void setClockScale(CLKSCALE __x); extern VOLTS setVoltage(VOLTS volts); +#if defined(ENABLE_CONFIG) +extern void configInit(); +extern uint8_t configFindKey(const __FlashStringHelper* key, char* value); +extern String configGetStr(const __FlashStringHelper* key); +extern long configGetLong(const __FlashStringHelper* key, int onFail = 0); +#endif /* ENABLE_CONFIG */ + #include "ClockedSerial.h" #endif /* OSCR_H_ */ diff --git a/sd/config.txt b/sd/config.txt new file mode 100644 index 00000000..30fcf4cc --- /dev/null +++ b/sd/config.txt @@ -0,0 +1,6 @@ +oscr.logging=1 +lcd.confColor=0 +lcd.red=0 +lcd.green=100 +lcd.blue=0 +md.sramType=0