From ee250685e1841973d9043e6b397d5146f4358d29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aitor=20G=C3=B3mez?= Date: Wed, 13 Mar 2019 06:04:26 +0100 Subject: [PATCH] Bootcore feature [MiSTer] ; lastcore - Autoboot the last loaded core (corename autosaved in CONFIG/lastcore.dat) first found on the SD/USB ; lastexactcore - Autoboot the last loaded exact core (corename_yyyymmdd.rbf autosaved in CONFIG/lastcore.dat) first found on the SD/USB ; corename - Autoboot first corename_*.rbf found on the SD/USB ; corename_yyyymmdd.rbf - Autoboot first corename_yyyymmdd.rbf found on the SD/USB ;bootcore=lastcore ; uncomment to autoboot a core, as the last loaded core. bootcore_timeout=10 ; 10-30 timeout before autoboot, comment for autoboot without timeout. --- MiSTer.ini | 7 ++ MiSTer.vcxproj | 2 + MiSTer.vcxproj.filters | 6 ++ bootcore.cpp | 240 +++++++++++++++++++++++++++++++++++++++++ bootcore.h | 18 ++++ cfg.cpp | 2 + cfg.h | 2 + file_io.cpp | 1 - fpga_io.cpp | 2 +- main.cpp | 2 + menu.cpp | 103 +++++++++++++++++- menu.h | 1 + osd.cpp | 7 +- osd.h | 4 +- user_io.cpp | 1 - 15 files changed, 389 insertions(+), 9 deletions(-) create mode 100644 bootcore.cpp create mode 100644 bootcore.h diff --git a/MiSTer.ini b/MiSTer.ini index 0d16ab8..8ef73f9 100644 --- a/MiSTer.ini +++ b/MiSTer.ini @@ -17,6 +17,13 @@ vscale_border=0 ; set vertical border for TVs cutting the upper/bottom pa rbf_hide_datecode=0 ; 1 - hides datecodes from rbf file names. Press F2 for quick temporary toggle menu_pal=0 ; 1 - PAL mode for menu core +; lastcore - Autoboot the last loaded core (corename autosaved in CONFIG/lastcore.dat) first found on the SD/USB +; lastexactcore - Autoboot the last loaded exact core (corename_yyyymmdd.rbf autosaved in CONFIG/lastcore.dat) first found on the SD/USB +; corename - Autoboot first corename_*.rbf found on the SD/USB +; corename_yyyymmdd.rbf - Autoboot first corename_yyyymmdd.rbf found on the SD/USB +;bootcore=lastcore ; uncomment to autoboot a core, as the last loaded core. +bootcore_timeout=10 ; 10-30 timeout before autoboot, comment for autoboot without timeout. + ; USER button emulation by keybaord. Usually it's reset button. ; 0 - lctrl+lalt+ralt (lctrl+lgui+rgui on keyrah) ; 1 - lctrl+lgui+rgui diff --git a/MiSTer.vcxproj b/MiSTer.vcxproj index 926e0f2..b10acb1 100644 --- a/MiSTer.vcxproj +++ b/MiSTer.vcxproj @@ -49,6 +49,7 @@ + @@ -84,6 +85,7 @@ + diff --git a/MiSTer.vcxproj.filters b/MiSTer.vcxproj.filters index f000c72..ac1508b 100644 --- a/MiSTer.vcxproj.filters +++ b/MiSTer.vcxproj.filters @@ -127,6 +127,9 @@ Source Files\miniz + + Source Files + @@ -258,5 +261,8 @@ Header Files\miniz + + Header Files + \ No newline at end of file diff --git a/bootcore.cpp b/bootcore.cpp new file mode 100644 index 0000000..5a02541 --- /dev/null +++ b/bootcore.cpp @@ -0,0 +1,240 @@ +// bootcore.cpp +// 2019, Aitor Gomez Garcia (spark2k06@gmail.com) +// Thanks to Sorgelig and BBond007 for their help and advice in the development of this feature. + +#include "file_io.h" +#include "cfg.h" +#include "fpga_io.h" +#include +#include +#include +#include + +int16_t btimeout; +char bootcoretype[64]; + +bool isExactcoreName(char *path) +{ + char *spl = strrchr(path, '.'); + return (spl && !strcmp(spl, ".rbf")); +} + +char *getcoreName(char *path) +{ + char *spl = strrchr(path, '.'); + if (spl && !strcmp(spl, ".rbf")) + { + *spl = '\0'; + } + else + { + return NULL; + } + if ((spl = strrchr(path, '/')) != NULL) + { + path = spl + 1; + } + if ((spl = strrchr(path, '_')) != NULL) + { + *spl = 0; + } + + return path; +} + +char *getcoreExactName(char *path) +{ + char *spl; + if ((spl = strrchr(path, '/')) != NULL) + { + path = spl + 1; + } + + return path; +} + +char *replaceStr(const char *str, const char *oldstr, const char *newstr) +{ + char *result; + int i, cnt = 0; + int newstrlen = strlen(newstr); + int oldstrlen = strlen(oldstr); + + for (i = 0; str[i] != '\0'; i++) + { + if (strstr(&str[i], oldstr) == &str[i]) + { + cnt++; + i += oldstrlen - 1; + } + } + + result = new char[i + cnt * (newstrlen - oldstrlen) + 1]; + + i = 0; + while (*str) + { + if (strstr(str, oldstr) == str) + { + strcpy(&result[i], newstr); + i += newstrlen; + str += oldstrlen; + } + else + result[i++] = *str++; + } + + result[i] = '\0'; + return result; +} + +char* loadLastcore() +{ + char full_path[2100]; + char path[256] = { CONFIG_DIR"/" }; + strcat(path, "lastcore.dat"); + sprintf(full_path, "%s/%s", getRootDir(), path); + FILE *fd = fopen(full_path, "r"); + if (!fd) + { + return NULL; + } + fseek(fd, 0L, SEEK_END); + long size = ftell(fd); + + fseek(fd, 0L, SEEK_SET); + char *lastcore = new char[size + 1]; + + int ret = fread(lastcore, sizeof(char), size, fd); + fclose(fd); + if (ret == size) + { + return lastcore; + } + delete[] lastcore; + return NULL; + +} + +char *findCore(const char *name, char *coreName, int indent) +{ + char *spl; + DIR *dir; + struct dirent *entry; + + if (!(dir = opendir(name))) + { + return NULL; + } + + + char *indir; + char* path = new char[256]; + while ((entry = readdir(dir)) != NULL) { + if (entry->d_type == DT_DIR) { + if (entry->d_name[0] != '_') + continue; + snprintf(path, 256, "%s/%s", name, entry->d_name); + indir = findCore(path, coreName, indent + 2); + if (indir != NULL) + { + closedir(dir); + delete[] path; + return indir; + } + } + else { + snprintf(path, 256, "%s/%s", name, entry->d_name); + if (strstr(path, coreName) != NULL) { + spl = strrchr(path, '.'); + if (spl && !strcmp(spl, ".rbf")) + { + closedir(dir); + return path; + } + } + } + } + closedir(dir); + delete[] path; + return NULL; +} + +void bootcore_init(const char *path) +{ + MiSTer_ini_parse(); + if (cfg.bootcore[0] == '\0') + { + return; + } + + char *auxpointer; + char auxstr[256]; + char bootcore[256]; + bool is_lastcore; + const char *rootdir = getRootDir(); + cfg.bootcore_timeout = cfg.bootcore_timeout * 10; + btimeout = cfg.bootcore_timeout; + strcpy(bootcore, cfg.bootcore); + + is_lastcore = (!strcmp(cfg.bootcore, "lastcore") || !strcmp(cfg.bootcore, "lastexactcore")); + + if (is_lastcore) + { + strcpy(bootcoretype, cfg.bootcore); + auxpointer = loadLastcore(); + if (auxpointer != NULL) + { + strcpy(bootcore, auxpointer); + delete[] auxpointer; + } + } + else + { + strcpy(bootcoretype, isExactcoreName(cfg.bootcore) ? "exactcorename" : "corename"); + } + + auxpointer = findCore(rootdir, bootcore, 0); + if (auxpointer != NULL) + { + strcpy(bootcore, auxpointer); + delete[] auxpointer; + + sprintf(auxstr, "%s/", rootdir); + auxpointer = replaceStr(bootcore, auxstr, ""); + if (auxpointer != NULL) + { + strcpy(bootcore, auxpointer); + delete[] auxpointer; + + if (path[0] == '\0') + { + if (!cfg.bootcore_timeout) + { + fpga_load_rbf(bootcore); + } + + strcpy(cfg.bootcore, strcmp(bootcore, "menu.rbf") ? bootcore : ""); + return; + } + } + } + + if (is_lastcore && path[0] != '\0') + { + + strcpy(auxstr, path); + auxpointer = !strcmp(cfg.bootcore, "lastexactcore") ? getcoreExactName(auxstr) : getcoreName(auxstr); + + if (auxpointer != NULL) + { + if (strcmp(bootcore, auxpointer)) + { + FileSaveConfig("lastcore.dat", (char*)auxpointer, strlen(auxpointer)); + } + } + } + strcpy(cfg.bootcore, ""); + +} + diff --git a/bootcore.h b/bootcore.h new file mode 100644 index 0000000..e86c891 --- /dev/null +++ b/bootcore.h @@ -0,0 +1,18 @@ +// bootcore.h +// 2019, Aitor Gomez Garcia (spark2k06@gmail.com) +// Thanks to Sorgelig and BBond007 for their help and advice in the development of this feature. + +#ifndef __BOOTCORE_H__ +#define __BOOTCORE_H__ + +char *getcoreName(char *path); +char *getcoreExactName(char *path); +char *replaceStr(const char *str, const char *oldstr, const char *newstr); +char *loadLastcore(); +char *findCore(const char *name, char *coreName, int indent); +void bootcore_init(const char *path); + +extern char bootcoretype[64]; +extern int16_t btimeout; + +#endif // __BOOTCORE_H__ \ No newline at end of file diff --git a/cfg.cpp b/cfg.cpp index b45cf4b..db33bdc 100644 --- a/cfg.cpp +++ b/cfg.cpp @@ -46,6 +46,8 @@ const ini_var_t ini_vars[] = { { "VSCALE_BORDER", (void*)(&(cfg.vscale_border)), UINT8, 0, 100, 1 }, { "RBF_HIDE_DATECODE", (void*)(&(cfg.rbf_hide_datecode)), UINT8, 0, 1, 1 }, { "MENU_PAL", (void*)(&(cfg.menu_pal)), UINT8, 0, 1, 1 }, + { "BOOTCORE", (void*)(&(cfg.bootcore)), STRING, 0, sizeof(cfg.bootcore) - 1, 1 }, + { "BOOTCORE_TIMEOUT", (void*)(&(cfg.bootcore_timeout)), INT8, 10, 30, 1 }, }; // mist ini config diff --git a/cfg.h b/cfg.h index c061ea7..f787321 100644 --- a/cfg.h +++ b/cfg.h @@ -32,6 +32,8 @@ typedef struct { uint8_t vscale_border; uint8_t rbf_hide_datecode; uint8_t menu_pal; + int16_t bootcore_timeout; + char bootcore[256]; char video_conf[1024]; char video_conf_pal[1024]; char video_conf_ntsc[1024]; diff --git a/file_io.cpp b/file_io.cpp index 4ba6235..413f401 100644 --- a/file_io.cpp +++ b/file_io.cpp @@ -737,7 +737,6 @@ void FindStorage(void) { int saveddev = device; device = 0; - MiSTer_ini_parse(); device = saveddev; parse_video_mode(); user_io_send_buttons(1); diff --git a/fpga_io.cpp b/fpga_io.cpp index cf6608b..0e48815 100644 --- a/fpga_io.cpp +++ b/fpga_io.cpp @@ -516,7 +516,7 @@ int fpga_load_rbf(const char *name, const char *cfg) } } close(rbf); - app_restart(!strcasecmp(name, "menu.rbf") ? NULL : path); + app_restart(!strcasecmp(name, "menu.rbf") ? "menu.rbf" : path); return ret; } diff --git a/main.cpp b/main.cpp index 4978076..a9fd5a9 100644 --- a/main.cpp +++ b/main.cpp @@ -31,6 +31,7 @@ along with this program. If not, see . #include "input.h" #include "fpga_io.h" #include "scheduler.h" +#include "bootcore.h" const char *version = "$VER:HPS" VDATE; @@ -65,6 +66,7 @@ int main(int argc, char *argv[]) } FindStorage(); + bootcore_init(argc > 1 ? argv[1] : ""); user_io_init((argc > 1) ? argv[1] : ""); scheduler_init(); diff --git a/menu.cpp b/menu.cpp index 4deb103..2dc6965 100644 --- a/menu.cpp +++ b/menu.cpp @@ -47,6 +47,7 @@ along with this program. If not, see . #include "cfg.h" #include "input.h" #include "battery.h" +#include "bootcore.h" #include "support.h" @@ -643,6 +644,26 @@ static void MenuWrite(unsigned char n, const char *s, unsigned char invert, unsi OsdWriteOffset(row, s, invert, stipple, 0, (row == 0 && firstmenu) ? 17 : (row == (OsdGetSize()-1) && !arrow) ? 16 : 0, 0); } +const char* get_rbf_name_bootcore(char *str) +{ + if (!strlen(cfg.bootcore)) return ""; + char *p = strrchr(str, '/'); + if (!p) return str; + + char *spl = strrchr(p + 1, '.'); + if (spl && !strcmp(spl, ".rbf")) + { + *spl = 0; + } + else + { + return NULL; + } + return p + 1; + + +} + void HandleUI(void) { switch (user_io_core_type()) @@ -689,6 +710,11 @@ void HandleUI(void) plus = false; minus = false; + if (c && c != KEY_F12 && cfg.bootcore[0] != '\0') + { + cfg.bootcore[0] = '\0'; + } + switch (c) { case KEY_F12: @@ -3556,8 +3582,35 @@ void HandleUI(void) if (!rtc_timer || CheckTimer(rtc_timer)) { - rtc_timer = GetTimer(1000); + rtc_timer = GetTimer(cfg.bootcore[0] != '\0' ? 100 : 1000); char str[64] = { 0 }; + char straux[64]; + + if (cfg.bootcore[0] != '\0') + { + if (btimeout >= 10) + { + sprintf(str, " Bootcore -> %s", bootcoretype); + OsdWrite(13, str, 0, 0); + strcpy(straux, cfg.bootcore); + sprintf(str, " %s", get_rbf_name_bootcore(straux)); + PrintFileName(str, 14, (32 * btimeout) / cfg.bootcore_timeout); + sprintf(str, " Press any key to cancel"); + OsdWrite(15, str, 0, 0); + btimeout--; + if (btimeout < 10) + { + OsdWrite(13, "", 0, 0); + strcpy(straux, cfg.bootcore); + sprintf(str, " %s", get_rbf_name_bootcore(straux)); + PrintFileName(str, 14, 0); + sprintf(str, " Loading..."); + OsdWrite(15, str, 1, 0); + fpga_load_rbf(cfg.bootcore); + } + } + } + sprintf(str, " MiSTer "); time_t t = time(NULL); @@ -3624,6 +3677,54 @@ void ScrollLongName(void) ScrollText(flist_iSelectedEntry()-flist_iFirstEntry(), flist_SelectedItem()->d_name, 2, len, max_len, 1); } +void PrintFileName(char *name, int row, int maxinv) +{ + int len; + + char s[40]; + s[32] = 0; // set temporary string length to OSD line length + + len = strlen(name); // get name length + memset(s, ' ', 32); // clear line buffer + char *p = 0; + if ((fs_Options & SCANO_CORES) && len > 9 && !strncmp(name + len - 9, "_20", 3)) + { + p = name + len - 6; + len -= 9; + } + + if (len > 28) + { + len = 27; // trim display length if longer than 30 characters + s[28] = 22; + } + strncpy(s + 1, name, len); // display only name + + if (!cfg.rbf_hide_datecode && (fs_Options & SCANO_CORES)) + { + if (p) + { + int n = 19; + s[n++] = ' '; + s[n++] = p[0]; + s[n++] = p[1]; + s[n++] = '.'; + s[n++] = p[2]; + s[n++] = p[3]; + s[n++] = '.'; + s[n++] = p[4]; + s[n++] = p[5]; + } + else + { + strcpy(&s[19], " --.--.--"); + } + } + + OsdWrite(row, s, 1, 0, 0, maxinv); + +} + // print directory contents void PrintDirectory(void) { diff --git a/menu.h b/menu.h index d271d3e..d625b83 100644 --- a/menu.h +++ b/menu.h @@ -13,6 +13,7 @@ extern const char *config_chipset_msg[]; void HandleUI(void); void menu_key_set(unsigned int c); +void PrintFileName(char *name, int row, int maxinv); void PrintDirectory(void); void ScrollLongName(void); diff --git a/osd.cpp b/osd.cpp index 1f0913b..fdbcf2b 100644 --- a/osd.cpp +++ b/osd.cpp @@ -200,13 +200,13 @@ void OsdSetArrow(int a) arrow = a; } -void OsdWrite(unsigned char n, const char *s, unsigned char invert, unsigned char stipple, char usebg) +void OsdWrite(unsigned char n, const char *s, unsigned char invert, unsigned char stipple, char usebg, int maxinv) { - OsdWriteOffset(n, s, invert, stipple, 0, 0, usebg); + OsdWriteOffset(n, s, invert, stipple, 0, 0, usebg, maxinv); } // write a null-terminated string to the OSD buffer starting at line -void OsdWriteOffset(unsigned char n, const char *s, unsigned char invert, unsigned char stipple, char offset, char leftchar, char usebg) +void OsdWriteOffset(unsigned char n, const char *s, unsigned char invert, unsigned char stipple, char offset, char leftchar, char usebg, int maxinv) { //printf("OsdWriteOffset(%d)\n", n); unsigned short i; @@ -237,6 +237,7 @@ void OsdWriteOffset(unsigned char n, const char *s, unsigned char invert, unsign // send all characters in string to OSD while (1) { + if (invert && i / 8 >= maxinv) invert = 0; if (i == 0 && (n < osd_size)) { // Render sidestripe unsigned char j; diff --git a/osd.h b/osd.h index 3e05fae..ef61620 100644 --- a/osd.h +++ b/osd.h @@ -68,8 +68,8 @@ /*functions*/ void OsdSetTitle(const char *s, int arrow = 0); // arrow > 0 = display right arrow in bottom right, < 0 = display left arrow void OsdSetArrow(int arrow); -void OsdWrite(unsigned char n, const char *s="", unsigned char inver=0, unsigned char stipple=0, char usebg = 0); -void OsdWriteOffset(unsigned char n, const char *s, unsigned char inver, unsigned char stipple, char offset, char leftchar, char usebg = 0); // Used for scrolling "Exit" text downwards... +void OsdWrite(unsigned char n, const char *s="", unsigned char inver=0, unsigned char stipple=0, char usebg = 0, int maxinv = 32); +void OsdWriteOffset(unsigned char n, const char *s, unsigned char inver, unsigned char stipple, char offset, char leftchar, char usebg = 0, int maxinv = 32); // Used for scrolling "Exit" text downwards... void OsdClear(void); void OsdEnable(unsigned char mode); void InfoEnable(int x, int y, int width, int height); diff --git a/user_io.cpp b/user_io.cpp index aca522e..2683b4a 100644 --- a/user_io.cpp +++ b/user_io.cpp @@ -500,7 +500,6 @@ void user_io_init(const char *path) user_io_8bit_set_status(UIO_STATUS_RESET, UIO_STATUS_RESET); } - MiSTer_ini_parse(); parse_video_mode(); FileLoadConfig("Volume.dat", &vol_att, 1); vol_att &= 0x1F;