From c2c4b83925092873f8bbf49a6b987680625e218f Mon Sep 17 00:00:00 2001 From: Troy Date: Thu, 22 Dec 2022 11:19:59 -0500 Subject: [PATCH 1/5] miniIni lib added --- lib/minIni/minGlue.h | 15 + lib/minIni/minIni.cpp | 952 ++++++++++++++++++++++++++++++++++++++++++ lib/minIni/minIni.h | 166 ++++++++ platformio.ini | 1 + 4 files changed, 1134 insertions(+) create mode 100644 lib/minIni/minGlue.h create mode 100644 lib/minIni/minIni.cpp create mode 100644 lib/minIni/minIni.h diff --git a/lib/minIni/minGlue.h b/lib/minIni/minGlue.h new file mode 100644 index 0000000..79fc956 --- /dev/null +++ b/lib/minIni/minGlue.h @@ -0,0 +1,15 @@ +/* Glue functions for the minIni library to SdFat library */ + +#include + +extern SdFs SD; + +#define INI_READONLY 1 +#define INI_FILETYPE FsFile +#define ini_openread(filename,file) ((file)->open(SD.vol(), filename, O_RDONLY)) +#define ini_close(file) ((file)->close()) +#define ini_read(buffer,size,file) ((file)->fgets((buffer),(size)) > 0) + +#define INI_FILEPOS fspos_t +#define ini_tell(file,pos) ((file)->fgetpos(pos)) +#define ini_seek(file,pos) ((file)->fsetpos(pos)) diff --git a/lib/minIni/minIni.cpp b/lib/minIni/minIni.cpp new file mode 100644 index 0000000..a80c5c7 --- /dev/null +++ b/lib/minIni/minIni.cpp @@ -0,0 +1,952 @@ +/* minIni - Multi-Platform INI file parser, suitable for embedded systems + * + * These routines are in part based on the article "Multiplatform .INI Files" + * by Joseph J. Graf in the March 1994 issue of Dr. Dobb's Journal. + * + * Copyright (c) CompuPhase, 2008-2021 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * Version: $Id: minIni.c 53 2015-01-18 13:35:11Z thiadmer.riemersma@gmail.com $ + */ + +#if (defined _UNICODE || defined __UNICODE__ || defined UNICODE) && !defined INI_ANSIONLY +# if !defined UNICODE /* for Windows */ +# define UNICODE +# endif +# if !defined _UNICODE /* for C library */ +# define _UNICODE +# endif +#endif + +#define MININI_IMPLEMENTATION +#include "minIni.h" +#if defined NDEBUG + #define assert(e) +#else + #include +#endif + +#if !defined __T || defined INI_ANSIONLY + #include + #include + #include + #define TCHAR char + #define __T(s) s + #define _tcscat strcat + #define _tcschr strchr + #define _tcscmp strcmp + #define _tcscpy strcpy + #define _tcsicmp stricmp + #define _tcslen strlen + #define _tcsncmp strncmp + #define _tcsnicmp strnicmp + #define _tcsrchr strrchr + #define _tcstol strtol + #define _tcstod strtod + #define _totupper toupper + #define _stprintf sprintf + #define _tfgets fgets + #define _tfputs fputs + #define _tfopen fopen + #define _tremove remove + #define _trename rename +#endif + +#if defined __linux || defined __linux__ + #define __LINUX__ +#elif defined FREEBSD && !defined __FreeBSD__ + #define __FreeBSD__ +#elif defined(_MSC_VER) + #pragma warning(disable: 4996) /* for Microsoft Visual C/C++ */ +#endif +#if !defined strnicmp && !defined PORTABLE_STRNICMP + #if defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__ || defined __APPLE__ || defined __NetBSD__ || defined __DragonFly__ || defined __GNUC__ + #define strnicmp strncasecmp + #endif +#endif +#if !defined _totupper + #define _totupper toupper +#endif + +#if !defined INI_LINETERM + #if defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__ || defined __APPLE__ || defined __NetBSD__ || defined __DragonFly__ + #define INI_LINETERM __T("\n") + #else + #define INI_LINETERM __T("\r\n") + #endif +#endif +#if !defined INI_FILETYPE + #error Missing definition for INI_FILETYPE. +#endif + +#if !defined sizearray + #define sizearray(a) (sizeof(a) / sizeof((a)[0])) +#endif + +enum quote_option { + QUOTE_NONE, + QUOTE_ENQUOTE, + QUOTE_DEQUOTE, +}; + +#if defined PORTABLE_STRNICMP +int strnicmp(const TCHAR *s1, const TCHAR *s2, size_t n) +{ + while (n-- != 0 && (*s1 || *s2)) { + register int c1, c2; + c1 = *s1++; + if ('a' <= c1 && c1 <= 'z') + c1 += ('A' - 'a'); + c2 = *s2++; + if ('a' <= c2 && c2 <= 'z') + c2 += ('A' - 'a'); + if (c1 != c2) + return c1 - c2; + } + return 0; +} +#endif /* PORTABLE_STRNICMP */ + +static TCHAR *skipleading(const TCHAR *str) +{ + assert(str != NULL); + while ('\0' < *str && *str <= ' ') + str++; + return (TCHAR *)str; +} + +static TCHAR *skiptrailing(const TCHAR *str, const TCHAR *base) +{ + assert(str != NULL); + assert(base != NULL); + while (str > base && '\0' < *(str-1) && *(str-1) <= ' ') + str--; + return (TCHAR *)str; +} + +static TCHAR *striptrailing(TCHAR *str) +{ + TCHAR *ptr = skiptrailing(_tcschr(str, '\0'), str); + assert(ptr != NULL); + *ptr = '\0'; + return str; +} + +static TCHAR *ini_strncpy(TCHAR *dest, const TCHAR *source, size_t maxlen, enum quote_option option) +{ + size_t d, s; + + assert(maxlen>0); + assert(source != NULL && dest != NULL); + assert((dest < source || (dest == source && option != QUOTE_ENQUOTE)) || dest > source + strlen(source)); + if (option == QUOTE_ENQUOTE && maxlen < 3) + option = QUOTE_NONE; /* cannot store two quotes and a terminating zero in less than 3 characters */ + + switch (option) { + case QUOTE_NONE: + for (d = 0; d < maxlen - 1 && source[d] != '\0'; d++) + dest[d] = source[d]; + assert(d < maxlen); + dest[d] = '\0'; + break; + case QUOTE_ENQUOTE: + d = 0; + dest[d++] = '"'; + for (s = 0; source[s] != '\0' && d < maxlen - 2; s++, d++) { + if (source[s] == '"') { + if (d >= maxlen - 3) + break; /* no space to store the escape character plus the one that follows it */ + dest[d++] = '\\'; + } + dest[d] = source[s]; + } + dest[d++] = '"'; + dest[d] = '\0'; + break; + case QUOTE_DEQUOTE: + for (d = s = 0; source[s] != '\0' && d < maxlen - 1; s++, d++) { + if ((source[s] == '"' || source[s] == '\\') && source[s + 1] == '"') + s++; + dest[d] = source[s]; + } + dest[d] = '\0'; + break; + default: + assert(0); + } + + return dest; +} + +static TCHAR *cleanstring(TCHAR *string, enum quote_option *quotes) +{ + int isstring; + TCHAR *ep; + + assert(string != NULL); + assert(quotes != NULL); + + /* Remove a trailing comment */ + isstring = 0; + for (ep = string; *ep != '\0' && ((*ep != ';' && *ep != '#') || isstring); ep++) { + if (*ep == '"') { + if (*(ep + 1) == '"') + ep++; /* skip "" (both quotes) */ + else + isstring = !isstring; /* single quote, toggle isstring */ + } else if (*ep == '\\' && *(ep + 1) == '"') { + ep++; /* skip \" (both quotes */ + } + } + assert(ep != NULL && (*ep == '\0' || *ep == ';' || *ep == '#')); + *ep = '\0'; /* terminate at a comment */ + striptrailing(string); + /* Remove double quotes surrounding a value */ + *quotes = QUOTE_NONE; + if (*string == '"' && (ep = _tcschr(string, '\0')) != NULL && *(ep - 1) == '"') { + string++; + *--ep = '\0'; + *quotes = QUOTE_DEQUOTE; /* this is a string, so remove escaped characters */ + } + return string; +} + +static int getkeystring(INI_FILETYPE *fp, const TCHAR *Section, const TCHAR *Key, + int idxSection, int idxKey, TCHAR *Buffer, int BufferSize, + INI_FILEPOS *mark) +{ + TCHAR *sp, *ep; + int len, idx; + enum quote_option quotes; + TCHAR LocalBuffer[INI_BUFFERSIZE]; + + assert(fp != NULL); + /* Move through file 1 line at a time until a section is matched or EOF. If + * parameter Section is NULL, only look at keys above the first section. If + * idxSection is positive, copy the relevant section name. + */ + len = (Section != NULL) ? (int)_tcslen(Section) : 0; + if (len > 0 || idxSection >= 0) { + assert(idxSection >= 0 || Section != NULL); + idx = -1; + do { + do { + if (!ini_read(LocalBuffer, INI_BUFFERSIZE, fp)) + return 0; + sp = skipleading(LocalBuffer); + ep = _tcsrchr(sp, ']'); + } while (*sp != '[' || ep == NULL); + /* When arrived here, a section was found; now optionally skip leading and + * trailing whitespace. + */ + assert(sp != NULL && *sp == '['); + sp = skipleading(sp + 1); + assert(ep != NULL && *ep == ']'); + ep = skiptrailing(ep, sp); + } while ((((int)(ep-sp) != len || Section == NULL || _tcsnicmp(sp, Section, len) != 0) && ++idx != idxSection)); + if (idxSection >= 0) { + if (idx == idxSection) { + assert(ep != NULL); + *ep = '\0'; /* the end of the section name was found earlier */ + ini_strncpy(Buffer, sp, BufferSize, QUOTE_NONE); + return 1; + } + return 0; /* no more section found */ + } + } + + /* Now that the section has been found, find the entry. + * Stop searching upon leaving the section's area. + */ + assert(Key != NULL || idxKey >= 0); + len = (Key != NULL) ? (int)_tcslen(Key) : 0; + idx = -1; + do { + if (mark != NULL) + ini_tell(fp, mark); /* optionally keep the mark to the start of the line */ + if (!ini_read(LocalBuffer,INI_BUFFERSIZE,fp) || *(sp = skipleading(LocalBuffer)) == '[') + return 0; + sp = skipleading(LocalBuffer); + ep = _tcschr(sp, '='); /* Parse out the equal sign */ + if (ep == NULL) + ep = _tcschr(sp, ':'); + } while (*sp == ';' || *sp == '#' || ep == NULL + || ((len == 0 || (int)(skiptrailing(ep,sp)-sp) != len || _tcsnicmp(sp,Key,len) != 0) && ++idx != idxKey)); + if (idxKey >= 0) { + if (idx == idxKey) { + assert(ep != NULL); + assert(*ep == '=' || *ep == ':'); + *ep = '\0'; + striptrailing(sp); + ini_strncpy(Buffer, sp, BufferSize, QUOTE_NONE); + return 1; + } + return 0; /* no more key found (in this section) */ + } + + /* Copy up to BufferSize chars to buffer */ + assert(ep != NULL); + assert(*ep == '=' || *ep == ':'); + sp = skipleading(ep + 1); + sp = cleanstring(sp, "es); /* Remove a trailing comment */ + ini_strncpy(Buffer, sp, BufferSize, quotes); + return 1; +} + +/** ini_gets() + * \param Section the name of the section to search for + * \param Key the name of the entry to find the value of + * \param DefValue default string in the event of a failed read + * \param Buffer a pointer to the buffer to copy into + * \param BufferSize the maximum number of characters to copy + * \param Filename the name and full path of the .ini file to read from + * + * \return the number of characters copied into the supplied buffer + */ +int ini_gets(const TCHAR *Section, const TCHAR *Key, const TCHAR *DefValue, + TCHAR *Buffer, int BufferSize, const TCHAR *Filename) +{ + INI_FILETYPE fp; + int ok = 0; + + if (Buffer == NULL || BufferSize <= 0 || Key == NULL) + return 0; + if (ini_openread(Filename, &fp)) { + ok = getkeystring(&fp, Section, Key, -1, -1, Buffer, BufferSize, NULL); + (void)ini_close(&fp); + } + if (!ok) + ini_strncpy(Buffer, (DefValue != NULL) ? DefValue : __T(""), BufferSize, QUOTE_NONE); + return (int)_tcslen(Buffer); +} + +/** ini_getl() + * \param Section the name of the section to search for + * \param Key the name of the entry to find the value of + * \param DefValue the default value in the event of a failed read + * \param Filename the name of the .ini file to read from + * + * \return the value located at Key + */ +long ini_getl(const TCHAR *Section, const TCHAR *Key, long DefValue, const TCHAR *Filename) +{ + TCHAR LocalBuffer[64]; + int len = ini_gets(Section, Key, __T(""), LocalBuffer, sizearray(LocalBuffer), Filename); + return (len == 0) ? DefValue + : ((len >= 2 && _totupper((int)LocalBuffer[1]) == 'X') ? _tcstol(LocalBuffer, NULL, 16) + : _tcstol(LocalBuffer, NULL, 10)); +} + +#if defined INI_REAL +/** ini_getf() + * \param Section the name of the section to search for + * \param Key the name of the entry to find the value of + * \param DefValue the default value in the event of a failed read + * \param Filename the name of the .ini file to read from + * + * \return the value located at Key + */ +INI_REAL ini_getf(const TCHAR *Section, const TCHAR *Key, INI_REAL DefValue, const TCHAR *Filename) +{ + TCHAR LocalBuffer[64]; + int len = ini_gets(Section, Key, __T(""), LocalBuffer, sizearray(LocalBuffer), Filename); + return (len == 0) ? DefValue : ini_atof(LocalBuffer); +} +#endif + +/** ini_getbool() + * \param Section the name of the section to search for + * \param Key the name of the entry to find the value of + * \param DefValue default value in the event of a failed read; it should + * zero (0) or one (1). + * \param Filename the name and full path of the .ini file to read from + * + * A true boolean is found if one of the following is matched: + * - A string starting with 'y' or 'Y' + * - A string starting with 't' or 'T' + * - A string starting with '1' + * + * A false boolean is found if one of the following is matched: + * - A string starting with 'n' or 'N' + * - A string starting with 'f' or 'F' + * - A string starting with '0' + * + * \return the true/false flag as interpreted at Key + */ +int ini_getbool(const TCHAR *Section, const TCHAR *Key, int DefValue, const TCHAR *Filename) +{ + TCHAR LocalBuffer[2] = __T(""); + int ret; + + ini_gets(Section, Key, __T(""), LocalBuffer, sizearray(LocalBuffer), Filename); + LocalBuffer[0] = (TCHAR)_totupper((int)LocalBuffer[0]); + if (LocalBuffer[0] == 'Y' || LocalBuffer[0] == '1' || LocalBuffer[0] == 'T') + ret = 1; + else if (LocalBuffer[0] == 'N' || LocalBuffer[0] == '0' || LocalBuffer[0] == 'F') + ret = 0; + else + ret = DefValue; + + return(ret); +} + +/** ini_getsection() + * \param idx the zero-based sequence number of the section to return + * \param Buffer a pointer to the buffer to copy into + * \param BufferSize the maximum number of characters to copy + * \param Filename the name and full path of the .ini file to read from + * + * \return the number of characters copied into the supplied buffer + */ +int ini_getsection(int idx, TCHAR *Buffer, int BufferSize, const TCHAR *Filename) +{ + INI_FILETYPE fp; + int ok = 0; + + if (Buffer == NULL || BufferSize <= 0 || idx < 0) + return 0; + if (ini_openread(Filename, &fp)) { + ok = getkeystring(&fp, NULL, NULL, idx, -1, Buffer, BufferSize, NULL); + (void)ini_close(&fp); + } + if (!ok) + *Buffer = '\0'; + return (int)_tcslen(Buffer); +} + +/** ini_getkey() + * \param Section the name of the section to browse through, or NULL to + * browse through the keys outside any section + * \param idx the zero-based sequence number of the key to return + * \param Buffer a pointer to the buffer to copy into + * \param BufferSize the maximum number of characters to copy + * \param Filename the name and full path of the .ini file to read from + * + * \return the number of characters copied into the supplied buffer + */ +int ini_getkey(const TCHAR *Section, int idx, TCHAR *Buffer, int BufferSize, const TCHAR *Filename) +{ + INI_FILETYPE fp; + int ok = 0; + + if (Buffer == NULL || BufferSize <= 0 || idx < 0) + return 0; + if (ini_openread(Filename, &fp)) { + ok = getkeystring(&fp, Section, NULL, -1, idx, Buffer, BufferSize, NULL); + (void)ini_close(&fp); + } + if (!ok) + *Buffer = '\0'; + return (int)_tcslen(Buffer); +} + +/** ini_hassection() + * \param Section the name of the section to search for + * \param Filename the name of the .ini file to read from + * + * \return 1 if the section is found, 0 if not found + */ +int ini_hassection(const mTCHAR *Section, const mTCHAR *Filename) +{ + TCHAR LocalBuffer[32]; /* dummy buffer */ + INI_FILETYPE fp; + int ok = 0; + + if (ini_openread(Filename, &fp)) { + ok = getkeystring(&fp, Section, NULL, -1, 0, LocalBuffer, sizearray(LocalBuffer), NULL); + (void)ini_close(&fp); + } + return ok; +} + +/** ini_haskey() + * \param Section the name of the section to search for + * \param Key the name of the entry to find the value of + * \param Filename the name of the .ini file to read from + * + * \return 1 if the key is found, 0 if not found + */ +int ini_haskey(const mTCHAR *Section, const mTCHAR *Key, const mTCHAR *Filename) +{ + TCHAR LocalBuffer[32]; /* dummy buffer */ + INI_FILETYPE fp; + int ok = 0; + + if (ini_openread(Filename, &fp)) { + ok = getkeystring(&fp, Section, Key, -1, -1, LocalBuffer, sizearray(LocalBuffer), NULL); + (void)ini_close(&fp); + } + return ok; +} + + +#if !defined INI_NOBROWSE +/** ini_browse() + * \param Callback a pointer to a function that will be called for every + * setting in the INI file. + * \param UserData arbitrary data, which the function passes on the + * \c Callback function + * \param Filename the name and full path of the .ini file to read from + * + * \return 1 on success, 0 on failure (INI file not found) + * + * \note The \c Callback function must return 1 to continue + * browsing through the INI file, or 0 to stop. Even when the + * callback stops the browsing, this function will return 1 + * (for success). + */ +int ini_browse(INI_CALLBACK Callback, void *UserData, const TCHAR *Filename) +{ + TCHAR LocalBuffer[INI_BUFFERSIZE]; + int lenSec, lenKey; + enum quote_option quotes; + INI_FILETYPE fp; + + if (Callback == NULL) + return 0; + if (!ini_openread(Filename, &fp)) + return 0; + + LocalBuffer[0] = '\0'; /* copy an empty section in the buffer */ + lenSec = (int)_tcslen(LocalBuffer) + 1; + for ( ;; ) { + TCHAR *sp, *ep; + if (!ini_read(LocalBuffer + lenSec, INI_BUFFERSIZE - lenSec, &fp)) + break; + sp = skipleading(LocalBuffer + lenSec); + /* ignore empty strings and comments */ + if (*sp == '\0' || *sp == ';' || *sp == '#') + continue; + /* see whether we reached a new section */ + ep = _tcsrchr(sp, ']'); + if (*sp == '[' && ep != NULL) { + sp = skipleading(sp + 1); + ep = skiptrailing(ep, sp); + *ep = '\0'; + ini_strncpy(LocalBuffer, sp, INI_BUFFERSIZE, QUOTE_NONE); + lenSec = (int)_tcslen(LocalBuffer) + 1; + continue; + } + /* not a new section, test for a key/value pair */ + ep = _tcschr(sp, '='); /* test for the equal sign or colon */ + if (ep == NULL) + ep = _tcschr(sp, ':'); + if (ep == NULL) + continue; /* invalid line, ignore */ + *ep++ = '\0'; /* split the key from the value */ + striptrailing(sp); + ini_strncpy(LocalBuffer + lenSec, sp, INI_BUFFERSIZE - lenSec, QUOTE_NONE); + lenKey = (int)_tcslen(LocalBuffer + lenSec) + 1; + /* clean up the value */ + sp = skipleading(ep); + sp = cleanstring(sp, "es); /* Remove a trailing comment */ + ini_strncpy(LocalBuffer + lenSec + lenKey, sp, INI_BUFFERSIZE - lenSec - lenKey, quotes); + /* call the callback */ + if (!Callback(LocalBuffer, LocalBuffer + lenSec, LocalBuffer + lenSec + lenKey, UserData)) + break; + } + + (void)ini_close(&fp); + return 1; +} +#endif /* INI_NOBROWSE */ + +#if ! defined INI_READONLY +static void ini_tempname(TCHAR *dest, const TCHAR *source, int maxlength) +{ + TCHAR *p; + + ini_strncpy(dest, source, maxlength, QUOTE_NONE); + p = _tcschr(dest, '\0'); + assert(p != NULL); + *(p - 1) = '~'; +} + +static enum quote_option check_enquote(const TCHAR *Value) +{ + const TCHAR *p; + + /* run through the value, if it has trailing spaces, or '"', ';' or '#' + * characters, enquote it + */ + assert(Value != NULL); + for (p = Value; *p != '\0' && *p != '"' && *p != ';' && *p != '#'; p++) + /* nothing */; + return (*p != '\0' || (p > Value && *(p - 1) == ' ')) ? QUOTE_ENQUOTE : QUOTE_NONE; +} + +static void writesection(TCHAR *LocalBuffer, const TCHAR *Section, INI_FILETYPE *fp) +{ + if (Section != NULL && _tcslen(Section) > 0) { + TCHAR *p; + LocalBuffer[0] = '['; + ini_strncpy(LocalBuffer + 1, Section, INI_BUFFERSIZE - 4, QUOTE_NONE); /* -1 for '[', -1 for ']', -2 for '\r\n' */ + p = _tcschr(LocalBuffer, '\0'); + assert(p != NULL); + *p++ = ']'; + _tcscpy(p, INI_LINETERM); /* copy line terminator (typically "\n") */ + if (fp != NULL) + (void)ini_write(LocalBuffer, fp); + } +} + +static void writekey(TCHAR *LocalBuffer, const TCHAR *Key, const TCHAR *Value, INI_FILETYPE *fp) +{ + TCHAR *p; + enum quote_option option = check_enquote(Value); + ini_strncpy(LocalBuffer, Key, INI_BUFFERSIZE - 3, QUOTE_NONE); /* -1 for '=', -2 for '\r\n' */ + p = _tcschr(LocalBuffer, '\0'); + assert(p != NULL); + *p++ = '='; + ini_strncpy(p, Value, INI_BUFFERSIZE - (p - LocalBuffer) - 2, option); /* -2 for '\r\n' */ + p = _tcschr(LocalBuffer, '\0'); + assert(p != NULL); + _tcscpy(p, INI_LINETERM); /* copy line terminator (typically "\n") */ + if (fp != NULL) + (void)ini_write(LocalBuffer, fp); +} + +static int cache_accum(const TCHAR *string, int *size, int max) +{ + int len = (int)_tcslen(string); + if (*size + len >= max) + return 0; + *size += len; + return 1; +} + +static int cache_flush(TCHAR *buffer, int *size, + INI_FILETYPE *rfp, INI_FILETYPE *wfp, INI_FILEPOS *mark) +{ + int terminator_len = (int)_tcslen(INI_LINETERM); + int pos = 0, pos_prev = -1; + + (void)ini_seek(rfp, mark); + assert(buffer != NULL); + buffer[0] = '\0'; + assert(size != NULL); + assert(*size <= INI_BUFFERSIZE); + while (pos < *size && pos != pos_prev) { + pos_prev = pos; /* to guard against zero bytes in the INI file */ + (void)ini_read(buffer + pos, INI_BUFFERSIZE - pos, rfp); + while (pos < *size && buffer[pos] != '\0') + pos++; /* cannot use _tcslen() because buffer may not be zero-terminated */ + } + if (buffer[0] != '\0') { + assert(pos > 0 && pos <= INI_BUFFERSIZE); + if (pos == INI_BUFFERSIZE) + pos--; + buffer[pos] = '\0'; /* force zero-termination (may be left unterminated in the above while loop) */ + (void)ini_write(buffer, wfp); + } + ini_tell(rfp, mark); /* update mark */ + *size = 0; + /* return whether the buffer ended with a line termination */ + return (pos > terminator_len) && (_tcscmp(buffer + pos - terminator_len, INI_LINETERM) == 0); +} + +static int close_rename(INI_FILETYPE *rfp, INI_FILETYPE *wfp, const TCHAR *filename, TCHAR *buffer) +{ + (void)ini_close(rfp); + (void)ini_close(wfp); + (void)ini_tempname(buffer, filename, INI_BUFFERSIZE); + #if defined ini_remove || defined INI_REMOVE + (void)ini_remove(filename); + #endif + (void)ini_rename(buffer, filename); + return 1; +} + +/** ini_puts() + * \param Section the name of the section to write the string in + * \param Key the name of the entry to write, or NULL to erase all keys in the section + * \param Value a pointer to the buffer the string, or NULL to erase the key + * \param Filename the name and full path of the .ini file to write to + * + * \return 1 if successful, otherwise 0 + */ +int ini_puts(const TCHAR *Section, const TCHAR *Key, const TCHAR *Value, const TCHAR *Filename) +{ + INI_FILETYPE rfp; + INI_FILETYPE wfp; + INI_FILEPOS mark; + INI_FILEPOS head, tail; + TCHAR *sp, *ep; + TCHAR LocalBuffer[INI_BUFFERSIZE]; + int len, match, flag, cachelen; + + assert(Filename != NULL); + if (!ini_openread(Filename, &rfp)) { + /* If the .ini file doesn't exist, make a new file */ + if (Key != NULL && Value != NULL) { + if (!ini_openwrite(Filename, &wfp)) + return 0; + writesection(LocalBuffer, Section, &wfp); + writekey(LocalBuffer, Key, Value, &wfp); + (void)ini_close(&wfp); + } + return 1; + } + + /* If parameters Key and Value are valid (so this is not an "erase" request) + * and the setting already exists, there are two short-cuts to avoid rewriting + * the INI file. + */ + if (Key != NULL && Value != NULL) { + match = getkeystring(&rfp, Section, Key, -1, -1, LocalBuffer, sizearray(LocalBuffer), &head); + if (match) { + /* if the current setting is identical to the one to write, there is + * nothing to do. + */ + if (_tcscmp(LocalBuffer,Value) == 0) { + (void)ini_close(&rfp); + return 1; + } + /* if the new setting has the same length as the current setting, and the + * glue file permits file read/write access, we can modify in place. + */ + #if defined ini_openrewrite || defined INI_OPENREWRITE + /* we already have the start of the (raw) line, get the end too */ + ini_tell(&rfp, &tail); + /* create new buffer (without writing it to file) */ + writekey(LocalBuffer, Key, Value, NULL); + if (_tcslen(LocalBuffer) == (size_t)(tail - head)) { + /* length matches, close the file & re-open for read/write, then + * write at the correct position + */ + (void)ini_close(&rfp); + if (!ini_openrewrite(Filename, &wfp)) + return 0; + (void)ini_seek(&wfp, &head); + (void)ini_write(LocalBuffer, &wfp); + (void)ini_close(&wfp); + return 1; + } + #endif + } + /* key not found, or different value & length -> proceed */ + } else if (Key != NULL && Value == NULL) { + /* Conversely, for a request to delete a setting; if that setting isn't + present, just return */ + match = getkeystring(&rfp, Section, Key, -1, -1, LocalBuffer, sizearray(LocalBuffer), NULL); + if (!match) { + (void)ini_close(&rfp); + return 1; + } + /* key found -> proceed to delete it */ + } + + /* Get a temporary file name to copy to. Use the existing name, but with + * the last character set to a '~'. + */ + (void)ini_close(&rfp); + ini_tempname(LocalBuffer, Filename, INI_BUFFERSIZE); + if (!ini_openwrite(LocalBuffer, &wfp)) + return 0; + /* In the case of (advisory) file locks, ini_openwrite() may have been blocked + * on the open, and after the block is lifted, the original file may have been + * renamed, which is why the original file was closed and is now reopened */ + if (!ini_openread(Filename, &rfp)) { + /* If the .ini file doesn't exist any more, make a new file */ + assert(Key != NULL && Value != NULL); + writesection(LocalBuffer, Section, &wfp); + writekey(LocalBuffer, Key, Value, &wfp); + (void)ini_close(&wfp); + return 1; + } + + (void)ini_tell(&rfp, &mark); + cachelen = 0; + + /* Move through the file one line at a time until a section is + * matched or until EOF. Copy to temp file as it is read. + */ + len = (Section != NULL) ? (int)_tcslen(Section) : 0; + if (len > 0) { + do { + if (!ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp)) { + /* Failed to find section, so add one to the end */ + flag = cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark); + if (Key!=NULL && Value!=NULL) { + if (!flag) + (void)ini_write(INI_LINETERM, &wfp); /* force a new line behind the last line of the INI file */ + writesection(LocalBuffer, Section, &wfp); + writekey(LocalBuffer, Key, Value, &wfp); + } + return close_rename(&rfp, &wfp, Filename, LocalBuffer); /* clean up and rename */ + } + /* Check whether this line is a section */ + sp = skipleading(LocalBuffer); + ep = _tcsrchr(sp, ']'); + match = (*sp == '[' && ep != NULL); + if (match) { + /* A section was found, skip leading and trailing whitespace */ + assert(sp != NULL && *sp == '['); + sp = skipleading(sp + 1); + assert(ep != NULL && *ep == ']'); + ep = skiptrailing(ep, sp); + match = ((int)(ep-sp) == len && _tcsnicmp(sp, Section, len) == 0); + } + /* Copy the line from source to dest, but not if this is the section that + * we are looking for and this section must be removed + */ + if (!match || Key != NULL) { + if (!cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE)) { + cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark); + (void)ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp); + cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE); + } + } + } while (!match); + } + cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark); + /* when deleting a section, the section head that was just found has not been + * copied to the output file, but because this line was not "accumulated" in + * the cache, the position in the input file was reset to the point just + * before the section; this must now be skipped (again) + */ + if (Key == NULL) { + (void)ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp); + (void)ini_tell(&rfp, &mark); + } + + /* Now that the section has been found, find the entry. Stop searching + * upon leaving the section's area. Copy the file as it is read + * and create an entry if one is not found. + */ + len = (Key != NULL) ? (int)_tcslen(Key) : 0; + for( ;; ) { + if (!ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp)) { + /* EOF without an entry so make one */ + flag = cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark); + if (Key!=NULL && Value!=NULL) { + if (!flag) + (void)ini_write(INI_LINETERM, &wfp); /* force a new line behind the last line of the INI file */ + writekey(LocalBuffer, Key, Value, &wfp); + } + return close_rename(&rfp, &wfp, Filename, LocalBuffer); /* clean up and rename */ + } + sp = skipleading(LocalBuffer); + ep = _tcschr(sp, '='); /* Parse out the equal sign */ + if (ep == NULL) + ep = _tcschr(sp, ':'); + match = (ep != NULL && len > 0 && (int)(skiptrailing(ep,sp)-sp) == len && _tcsnicmp(sp,Key,len) == 0); + if ((Key != NULL && match) || *sp == '[') + break; /* found the key, or found a new section */ + /* copy other keys in the section */ + if (Key == NULL) { + (void)ini_tell(&rfp, &mark); /* we are deleting the entire section, so update the read position */ + } else { + if (!cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE)) { + cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark); + (void)ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp); + cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE); + } + } + } + /* the key was found, or we just dropped on the next section (meaning that it + * wasn't found); in both cases we need to write the key, but in the latter + * case, we also need to write the line starting the new section after writing + * the key + */ + flag = (*sp == '['); + cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark); + if (Key != NULL && Value != NULL) + writekey(LocalBuffer, Key, Value, &wfp); + /* cache_flush() reset the "read pointer" to the start of the line with the + * previous key or the new section; read it again (because writekey() destroyed + * the buffer) + */ + (void)ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp); + if (flag) { + /* the new section heading needs to be copied to the output file */ + cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE); + } else { + /* forget the old key line */ + (void)ini_tell(&rfp, &mark); + } + /* Copy the rest of the INI file */ + while (ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp)) { + if (!cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE)) { + cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark); + (void)ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp); + cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE); + } + } + cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark); + return close_rename(&rfp, &wfp, Filename, LocalBuffer); /* clean up and rename */ +} + +/* Ansi C "itoa" based on Kernighan & Ritchie's "Ansi C" book. */ +#define ABS(v) ((v) < 0 ? -(v) : (v)) + +static void strreverse(TCHAR *str) +{ + int i, j; + for (i = 0, j = (int)_tcslen(str) - 1; i < j; i++, j--) { + TCHAR t = str[i]; + str[i] = str[j]; + str[j] = t; + } +} + +static void long2str(long value, TCHAR *str) +{ + int i = 0; + long sign = value; + + /* generate digits in reverse order */ + do { + int n = (int)(value % 10); /* get next lowest digit */ + str[i++] = (TCHAR)(ABS(n) + '0'); /* handle case of negative digit */ + } while (value /= 10); /* delete the lowest digit */ + if (sign < 0) + str[i++] = '-'; + str[i] = '\0'; + + strreverse(str); +} + +/** ini_putl() + * \param Section the name of the section to write the value in + * \param Key the name of the entry to write + * \param Value the value to write + * \param Filename the name and full path of the .ini file to write to + * + * \return 1 if successful, otherwise 0 + */ +int ini_putl(const TCHAR *Section, const TCHAR *Key, long Value, const TCHAR *Filename) +{ + TCHAR LocalBuffer[32]; + long2str(Value, LocalBuffer); + return ini_puts(Section, Key, LocalBuffer, Filename); +} + +#if defined INI_REAL +/** ini_putf() + * \param Section the name of the section to write the value in + * \param Key the name of the entry to write + * \param Value the value to write + * \param Filename the name and full path of the .ini file to write to + * + * \return 1 if successful, otherwise 0 + */ +int ini_putf(const TCHAR *Section, const TCHAR *Key, INI_REAL Value, const TCHAR *Filename) +{ + TCHAR LocalBuffer[64]; + ini_ftoa(LocalBuffer, Value); + return ini_puts(Section, Key, LocalBuffer, Filename); +} +#endif /* INI_REAL */ +#endif /* !INI_READONLY */ diff --git a/lib/minIni/minIni.h b/lib/minIni/minIni.h new file mode 100644 index 0000000..8a72462 --- /dev/null +++ b/lib/minIni/minIni.h @@ -0,0 +1,166 @@ +/* minIni - Multi-Platform INI file parser, suitable for embedded systems + * + * Copyright (c) CompuPhase, 2008-2021 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * Version: $Id: minIni.h 53 2015-01-18 13:35:11Z thiadmer.riemersma@gmail.com $ + */ +#ifndef MININI_H +#define MININI_H + +#include "minGlue.h" + +#if (defined _UNICODE || defined __UNICODE__ || defined UNICODE) && !defined INI_ANSIONLY + #include + #define mTCHAR TCHAR +#else + /* force TCHAR to be "char", but only for minIni */ + #define mTCHAR char +#endif + +#if !defined INI_BUFFERSIZE + #define INI_BUFFERSIZE 512 +#endif + +#if defined __cplusplus + extern "C" { +#endif + +int ini_getbool(const mTCHAR *Section, const mTCHAR *Key, int DefValue, const mTCHAR *Filename); +long ini_getl(const mTCHAR *Section, const mTCHAR *Key, long DefValue, const mTCHAR *Filename); +int ini_gets(const mTCHAR *Section, const mTCHAR *Key, const mTCHAR *DefValue, mTCHAR *Buffer, int BufferSize, const mTCHAR *Filename); +int ini_getsection(int idx, mTCHAR *Buffer, int BufferSize, const mTCHAR *Filename); +int ini_getkey(const mTCHAR *Section, int idx, mTCHAR *Buffer, int BufferSize, const mTCHAR *Filename); + +int ini_hassection(const mTCHAR *Section, const mTCHAR *Filename); +int ini_haskey(const mTCHAR *Section, const mTCHAR *Key, const mTCHAR *Filename); + +#if defined INI_REAL +INI_REAL ini_getf(const mTCHAR *Section, const mTCHAR *Key, INI_REAL DefValue, const mTCHAR *Filename); +#endif + +#if !defined INI_READONLY +int ini_putl(const mTCHAR *Section, const mTCHAR *Key, long Value, const mTCHAR *Filename); +int ini_puts(const mTCHAR *Section, const mTCHAR *Key, const mTCHAR *Value, const mTCHAR *Filename); +#if defined INI_REAL +int ini_putf(const mTCHAR *Section, const mTCHAR *Key, INI_REAL Value, const mTCHAR *Filename); +#endif +#endif /* INI_READONLY */ + +#if !defined INI_NOBROWSE +typedef int (*INI_CALLBACK)(const mTCHAR *Section, const mTCHAR *Key, const mTCHAR *Value, void *UserData); +int ini_browse(INI_CALLBACK Callback, void *UserData, const mTCHAR *Filename); +#endif /* INI_NOBROWSE */ + +#if defined __cplusplus + } +#endif + + +#if defined __cplusplus + +#if defined __WXWINDOWS__ + #include "wxMinIni.h" +#else + #include + + /* The C++ class in minIni.h was contributed by Steven Van Ingelgem. */ + class minIni + { + public: + minIni(const std::string& filename) : iniFilename(filename) + { } + + bool getbool(const std::string& Section, const std::string& Key, bool DefValue=false) const + { return ini_getbool(Section.c_str(), Key.c_str(), int(DefValue), iniFilename.c_str()) != 0; } + + long getl(const std::string& Section, const std::string& Key, long DefValue=0) const + { return ini_getl(Section.c_str(), Key.c_str(), DefValue, iniFilename.c_str()); } + + int geti(const std::string& Section, const std::string& Key, int DefValue=0) const + { return static_cast(this->getl(Section, Key, long(DefValue))); } + + std::string gets(const std::string& Section, const std::string& Key, const std::string& DefValue="") const + { + char buffer[INI_BUFFERSIZE]; + ini_gets(Section.c_str(), Key.c_str(), DefValue.c_str(), buffer, INI_BUFFERSIZE, iniFilename.c_str()); + return buffer; + } + + std::string getsection(int idx) const + { + char buffer[INI_BUFFERSIZE]; + ini_getsection(idx, buffer, INI_BUFFERSIZE, iniFilename.c_str()); + return buffer; + } + + std::string getkey(const std::string& Section, int idx) const + { + char buffer[INI_BUFFERSIZE]; + ini_getkey(Section.c_str(), idx, buffer, INI_BUFFERSIZE, iniFilename.c_str()); + return buffer; + } + + bool hassection(const std::string& Section) const + { return ini_hassection(Section.c_str(), iniFilename.c_str()) != 0; } + + bool haskey(const std::string& Section, const std::string& Key) const + { return ini_haskey(Section.c_str(), Key.c_str(), iniFilename.c_str()) != 0; } + +#if defined INI_REAL + INI_REAL getf(const std::string& Section, const std::string& Key, INI_REAL DefValue=0) const + { return ini_getf(Section.c_str(), Key.c_str(), DefValue, iniFilename.c_str()); } +#endif + +#if ! defined INI_READONLY + bool put(const std::string& Section, const std::string& Key, long Value) + { return ini_putl(Section.c_str(), Key.c_str(), Value, iniFilename.c_str()) != 0; } + + bool put(const std::string& Section, const std::string& Key, int Value) + { return ini_putl(Section.c_str(), Key.c_str(), (long)Value, iniFilename.c_str()) != 0; } + + bool put(const std::string& Section, const std::string& Key, bool Value) + { return ini_putl(Section.c_str(), Key.c_str(), (long)Value, iniFilename.c_str()) != 0; } + + bool put(const std::string& Section, const std::string& Key, const std::string& Value) + { return ini_puts(Section.c_str(), Key.c_str(), Value.c_str(), iniFilename.c_str()) != 0; } + + bool put(const std::string& Section, const std::string& Key, const char* Value) + { return ini_puts(Section.c_str(), Key.c_str(), Value, iniFilename.c_str()) != 0; } + +#if defined INI_REAL + bool put(const std::string& Section, const std::string& Key, INI_REAL Value) + { return ini_putf(Section.c_str(), Key.c_str(), Value, iniFilename.c_str()) != 0; } +#endif + + bool del(const std::string& Section, const std::string& Key) + { return ini_puts(Section.c_str(), Key.c_str(), 0, iniFilename.c_str()) != 0; } + + bool del(const std::string& Section) + { return ini_puts(Section.c_str(), 0, 0, iniFilename.c_str()) != 0; } +#endif + +#if !defined INI_NOBROWSE + bool browse(INI_CALLBACK Callback, void *UserData) const + { return ini_browse(Callback, UserData, iniFilename.c_str()) != 0; } +#endif + + private: + std::string iniFilename; + }; + +#endif /* __WXWINDOWS__ */ +#endif /* __cplusplus */ + +#endif /* MININI_H */ diff --git a/platformio.ini b/platformio.ini index bca0747..ae59c0b 100644 --- a/platformio.ini +++ b/platformio.ini @@ -7,6 +7,7 @@ default_envs = STM32F1 framework = arduino lib_deps = greiman/SdFat @ 2.2.0 + miniIni upload_protocol = stlink ; Different gcc versions produce much different binaries in terms of speed. platform_packages = platformio/toolchain-gccarmnoneeabi@1.90301.200702 From 5bad53008aee771aff1e5633abade36323cc7cec Mon Sep 17 00:00:00 2001 From: Troy Date: Thu, 22 Dec 2022 17:45:20 -0500 Subject: [PATCH 2/5] bluescsi.ini support enabled for some features MegaSTE Mode Per SCSI device Product/Vendor/Revision bunch of text refactoring for brievity and byteshaving some reorg of the SD card info printed in the log other little bits here and there --- src/BlueSCSI.cpp | 273 ++++++++++++++++++++++++----------------------- src/BlueSCSI.h | 33 ++++-- 2 files changed, 166 insertions(+), 140 deletions(-) diff --git a/src/BlueSCSI.cpp b/src/BlueSCSI.cpp index 922e356..6d4ae89 100644 --- a/src/BlueSCSI.cpp +++ b/src/BlueSCSI.cpp @@ -52,6 +52,7 @@ #include "scsi_sense.h" #include "scsi_status.h" #include "scsi_mode.h" +#include #ifdef USE_STM32_DMA #warning "warning USE_STM32_DMA" @@ -64,16 +65,10 @@ FsFile LOG_FILE; volatile bool m_isBusReset = false; // Bus reset volatile bool m_resetJmp = false; // Call longjmp on reset jmp_buf m_resetJmpBuf; - byte scsi_id_mask; // Mask list of responding SCSI IDs -byte m_id; // Currently responding SCSI-ID -byte m_lun; // Logical unit number currently responding -byte m_sts; // Status byte -byte m_msg; // Message bytes byte m_buf[MAX_BLOCKSIZE]; // General purpose buffer byte m_scsi_buf[SCSI_BUF_SIZE]; // Buffer for SCSI READ/WRITE Buffer -unsigned m_scsi_buf_size = 0; -byte m_msb[256]; // Command storage bytes + SCSI_DEVICE scsi_device_list[NUM_SCSIID][NUM_SCSILUN]; // Maximum number SCSI_INQUIRY_DATA default_hdd, default_optical; @@ -112,7 +107,7 @@ static void LBAtoMSF(const uint32_t lba, byte *msf); static void flashError(const unsigned error); void onBusReset(void); -void initFileLog(int); +void initFileLog(void); void finalizeFileLog(void); void findDriveImages(FsFile root); @@ -132,67 +127,106 @@ inline byte readIO(void) return bret; } -// If config file exists, read the first three lines and copy the contents. -// File must be well formed or you will get junk in the SCSI Vendor fields. -void readSCSIDeviceConfig(SCSI_DEVICE *dev) { - FsFile config_file = SD.open("scsi-config.txt", O_RDONLY); - if (!config_file.isOpen()) { +// Read config file for per device settings +void readSCSIDeviceConfig(uint8_t scsi_id, SCSI_DEVICE *dev) { + SCSI_INQUIRY_DATA *iq = &dev->inquiry_block; + char section[6] = {'S', 'C', 'S', 'I', 0, 0}; + FsFile config_file; + char *buf = (char *)&m_scsi_buf; + + // check for bluescsi.ini + if(!SD.exists(BLUESCSI_INI)) { return; } - SCSI_INQUIRY_DATA *iq = dev->inquiry_block; - char vendor[9]; - memset(vendor, 0, sizeof(vendor)); - config_file.readBytes(vendor, sizeof(vendor)); - LOG_FILE.print("SCSI VENDOR: "); - LOG_FILE.println(vendor); - memcpy(&iq->vendor, vendor, 8); + // create section name from id + section[4] = INT_TO_CHAR(scsi_id); - char product[17]; - memset(product, 0, sizeof(product)); - config_file.readBytes(product, sizeof(product)); - LOG_FILE.print("SCSI PRODUCT: "); - LOG_FILE.println(product); - memcpy(&iq->product, product, 16); + switch(ini_getl(section, "type", 99, BLUESCSI_INI)) + { + case 0: + dev->m_type = SCSI_DEVICE_HDD; + memcpy(iq, &default_hdd, sizeof(default_hdd)); + LOG_FILE.println("Forced HDD"); + break; - char version[5]; - memset(version, 0, sizeof(version)); - config_file.readBytes(version, sizeof(version)); - LOG_FILE.print("SCSI VERSION: "); - LOG_FILE.println(version); - memcpy(&iq->revision, version, 4); - config_file.close(); + case 2: + dev->m_type = SCSI_DEVICE_OPTICAL; + memcpy(iq, &default_optical, sizeof(default_optical)); + LOG_FILE.println("Forced Optical"); + break; + + case 99: + // default, do nothing at all + break; + + default: + LOG_FILE.println("Unsupported override type"); + } + + if(ini_gets(section, "vendor", NULL, buf, SCSI_BUF_SIZE, BLUESCSI_INI)) { + memcpy(iq->vendor, buf, SCSI_VENDOR_LENGTH); + LOG_FILE.print("vendor:"); + LOG_FILE.println(buf); + } + + if(ini_gets(section, "product", NULL, buf, SCSI_BUF_SIZE, BLUESCSI_INI)) { + memcpy(iq->product, buf, SCSI_PRODUCT_LENGTH); + LOG_FILE.print("product:"); + LOG_FILE.println(buf); + } + + if(ini_gets(section, "revision", NULL, buf, SCSI_BUF_SIZE, BLUESCSI_INI)) { + memcpy(iq->revision, buf, SCSI_REVISION_LENGTH); + LOG_FILE.print("revision:"); + LOG_FILE.println(buf); + } } // read SD information and print to logfile -void readSDCardInfo() +void readSDCardInfo(int success_mhz) { cid_t sd_cid; + LOG_FILE.println("SDCard Info:"); + LOG_FILE.print(" Format:"); + switch(SD.vol()->fatType()) { + case FAT_TYPE_EXFAT: + LOG_FILE.println("exFAT"); + break; + default: + LOG_FILE.print("FAT32/16/12 - exFAT may improve performance"); + } + LOG_FILE.print("SPI speed: "); + LOG_FILE.print(success_mhz); + LOG_FILE.println("Mhz"); + LOG_FILE.print(" Max Filename Length:"); + LOG_FILE.println(MAX_FILE_PATH); + if(SD.card()->readCID(&sd_cid)) { - LOG_FILE.print("Sd MID:"); + LOG_FILE.print(" MID:"); LOG_FILE.print(sd_cid.mid, 16); LOG_FILE.print(" OID:"); LOG_FILE.print(sd_cid.oid[0]); LOG_FILE.println(sd_cid.oid[1]); - LOG_FILE.print("Sd Name:"); + LOG_FILE.print(" Name:"); LOG_FILE.print(sd_cid.pnm[0]); LOG_FILE.print(sd_cid.pnm[1]); LOG_FILE.print(sd_cid.pnm[2]); LOG_FILE.print(sd_cid.pnm[3]); - LOG_FILE.println(sd_cid.pnm[4]); + LOG_FILE.print(sd_cid.pnm[4]); - LOG_FILE.print("Sd Date:"); + LOG_FILE.print(" Date:"); LOG_FILE.print(sd_cid.mdtMonth()); LOG_FILE.print("/"); LOG_FILE.println(sd_cid.mdtYear()); - LOG_FILE.print("Sd Serial:"); + LOG_FILE.print(" Serial:"); LOG_FILE.println(sd_cid.psn()); - LOG_FILE.sync(); } + LOG_FILE.sync(); } bool VerifyISOPVD(SCSI_DEVICE *dev, unsigned sector_size, bool mode2) @@ -202,13 +236,13 @@ bool VerifyISOPVD(SCSI_DEVICE *dev, unsigned sector_size, bool mode2) if(mode2) seek += 8; bool ret = false; - dev->m_file->seekSet(seek); - dev->m_file->read(m_buf, 2048); + dev->m_file.seekSet(seek); + dev->m_file.read(m_buf, 2048); ret = ((m_buf[0] == 1 && !strncmp((char *)&m_buf[1], "CD001", 5) && m_buf[6] == 1) || (m_buf[8] == 1 && !strncmp((char *)&m_buf[9], "CDROM", 5) && m_buf[14] == 1)); - dev->m_file->rewind(); + dev->m_file.rewind(); return ret; } @@ -220,18 +254,19 @@ bool hddimageOpen(SCSI_DEVICE *dev, FsFile *file,int id,int lun,int blocksize) { dev->m_fileSize= 0; dev->m_sector_offset = 0; + dev->flags = 0; dev->m_blocksize = blocksize; dev->m_rawblocksize = blocksize; - dev->m_file = file; - if(!dev->m_file->isOpen()) { goto failed; } + dev->m_file = *file; + if(!dev->m_file.isOpen()) { goto failed; } - dev->m_fileSize = dev->m_file->size(); + dev->m_fileSize = dev->m_file.size(); if(dev->m_fileSize < 1) { LOG_FILE.println(" - file is 0 bytes, can not use."); goto failed; } - if(!dev->m_file->isContiguous()) + if(!dev->m_file.isContiguous()) { LOG_FILE.println(" - file is fragmented, see https://github.com/erichelgeson/BlueSCSI/wiki/Image-File-Fragmentation"); } @@ -243,19 +278,18 @@ bool hddimageOpen(SCSI_DEVICE *dev, FsFile *file,int id,int lun,int blocksize) // Borrowed from PCEM if(VerifyISOPVD(dev, CDROM_COMMON_SECTORSIZE, false)) { dev->m_rawblocksize = CDROM_COMMON_SECTORSIZE; - dev->m_mode2 = false; + SET_DEVICE_FLAG(dev->flags, SCSI_DEVICE_FLAG_OPTICAL_MODE2); } else if(VerifyISOPVD(dev, CDROM_RAW_SECTORSIZE, false)) { dev->m_rawblocksize = CDROM_RAW_SECTORSIZE; - dev->m_mode2 = false; - dev->m_raw = true; + SET_DEVICE_FLAG(dev->flags, SCSI_DEVICE_FLAG_OPTICAL_RAW); dev->m_sector_offset = 16; } else if(VerifyISOPVD(dev, 2336, true)) { dev->m_rawblocksize = 2336; - dev->m_mode2 = true; + SET_DEVICE_FLAG(dev->flags, SCSI_DEVICE_FLAG_OPTICAL_MODE2); } else if(VerifyISOPVD(dev, CDROM_RAW_SECTORSIZE, true)) { dev->m_rawblocksize = CDROM_RAW_SECTORSIZE; - dev->m_mode2 = true; - dev->m_raw = true; + SET_DEVICE_FLAG(dev->flags, SCSI_DEVICE_FLAG_OPTICAL_MODE2); + SET_DEVICE_FLAG(dev->flags, SCSI_DEVICE_FLAG_OPTICAL_RAW); dev->m_sector_offset = 24; } else { // Last ditch effort @@ -264,7 +298,7 @@ bool hddimageOpen(SCSI_DEVICE *dev, FsFile *file,int id,int lun,int blocksize) goto failed; } - dev->m_raw = true; + SET_DEVICE_FLAG(dev->flags, SCSI_DEVICE_FLAG_OPTICAL_RAW); if(!(dev->m_fileSize % CDROM_COMMON_SECTORSIZE)) { // try a multiple of 2048 @@ -291,17 +325,17 @@ bool hddimageOpen(SCSI_DEVICE *dev, FsFile *file,int id,int lun,int blocksize) LOG_FILE.println("MiB"); if(dev->m_type == SCSI_DEVICE_OPTICAL) { - LOG_FILE.print(" MODE2:");LOG_FILE.print(dev->m_mode2); - LOG_FILE.print(" BlockSize:");LOG_FILE.println(dev->m_rawblocksize); + LOG_FILE.print(" MODE2:");LOG_FILE.print(IS_MODE2(dev->flags)); + LOG_FILE.print(" BlockSize:");LOG_FILE.println(IS_RAW(dev->flags)); } return true; // File opened failed: - dev->m_file->close(); + dev->m_file.close(); dev->m_fileSize = dev->m_blocksize = 0; // no file - delete dev->m_file; - dev->m_file = NULL; + //delete dev->m_file; + //dev->m_file = NULL; return false; } @@ -326,15 +360,6 @@ void setup() scsi_command_table[i] = onUnimplemented; } - // zero all SCSI device structs - for(unsigned id = 0; id < NUM_SCSIID; id++) - { - for(unsigned lun = 0; lun < NUM_SCSILUN; lun++) - { - memset(&scsi_device_list[id][lun], 0, sizeof(SCSI_DEVICE)); - } - } - // SCSI commands that just need to return ok scsi_command_table[SCSI_FORMAT_UNIT4] = onNOP; scsi_command_table[SCSI_FORMAT_UNIT6] = onNOP; @@ -483,22 +508,26 @@ void setup() if(!sd_ready) { #if DEBUG > 0 - Serial.println("SD initialization failed!"); + Serial.println("SD Init failed!"); #endif flashError(ERROR_NO_SDCARD); } - initFileLog(mhz); - readSDCardInfo(); + initFileLog(); + readSDCardInfo(mhz); //HD image file open scsi_id_mask = 0x00; - // Look for this file to enable MSTE_MODE - if(SD.exists("MSTE_MODE")) { + if(ini_getl("SCSI", "megastemode", 0, BLUESCSI_INI)) + { LOG_FILE.println("MSTE_MODE - IDs treated as LUNs"); megaste_mode = true; } + if(SD.exists("scsi-config.txt")) { + LOG_FILE.println("scsi-config.txt is deprecated, use bluescsi.ini"); + } + // Iterate over the root path in the SD card looking for candidate image files. FsFile root; @@ -540,7 +569,7 @@ void setup() void findDriveImages(FsFile root) { bool image_ready; - FsFile *file = NULL; + FsFile file; char path_name[MAX_FILE_PATH+1]; root.getName(path_name, sizeof(path_name)); SD.chdir(path_name); @@ -564,14 +593,11 @@ void findDriveImages(FsFile root) { } // Valid file, open for reading/writing. - file = new FsFile(SD.open(name, O_RDWR)); - if(file && file->isFile()) { + file = SD.open(name, O_RDWR); + if(file && file.isFile()) { SCSI_DEVICE_TYPE device_type; if(tolower(name[1]) != 'd') { - file->close(); - delete file; - LOG_FILE.print("Not an image: "); - LOG_FILE.println(name); + file.close(); continue; } @@ -581,10 +607,7 @@ void findDriveImages(FsFile root) { case 'c': device_type = SCSI_DEVICE_OPTICAL; break; default: - file->close(); - delete file; - LOG_FILE.print("Not an image: "); - LOG_FILE.println(name); + file.close(); continue; } @@ -597,7 +620,7 @@ void findDriveImages(FsFile root) { // We only require the minimum and read in the next if provided. int file_name_length = strlen(name); if(file_name_length > 2) { // HD[N] - int tmp_id = name[HDIMG_ID_POS] - '0'; + int tmp_id = CHAR_TO_INT(name[HDIMG_ID_POS]); // If valid id, set it, else use default if(tmp_id > -1 && tmp_id < 8) { @@ -609,7 +632,7 @@ void findDriveImages(FsFile root) { } if(file_name_length > 3) { // HDN[N] - int tmp_lun = name[HDIMG_LUN_POS] - '0'; + int tmp_lun = CHAR_TO_INT(name[HDIMG_LUN_POS]); // If valid lun, set it, else use default if(tmp_lun == 0 || tmp_lun == 1) { @@ -622,11 +645,11 @@ void findDriveImages(FsFile root) { int blk1 = 0, blk2, blk3, blk4 = 0; if(file_name_length > 8) { // HD00_[111] - blk1 = name[HDIMG_BLK_POS] - '0'; - blk2 = name[HDIMG_BLK_POS+1] - '0'; - blk3 = name[HDIMG_BLK_POS+2] - '0'; + blk1 = CHAR_TO_INT(name[HDIMG_BLK_POS]); + blk2 = CHAR_TO_INT(name[HDIMG_BLK_POS+1]); + blk3 = CHAR_TO_INT(name[HDIMG_BLK_POS+2]); if(file_name_length > 9) // HD00_NNN[1] - blk4 = name[HDIMG_BLK_POS+3] - '0'; + blk4 = CHAR_TO_INT(name[HDIMG_BLK_POS+3]); } if(blk1 == 2 && blk2 == 5 && blk3 == 6) { blk = 256; @@ -641,7 +664,7 @@ void findDriveImages(FsFile root) { LOG_FILE.print(" - "); LOG_FILE.print(name); dev->m_type = device_type; - image_ready = hddimageOpen(dev, file, id, lun, blk); + image_ready = hddimageOpen(dev, &file, id, lun, blk); if(image_ready) { // Marked as a responsive ID scsi_id_mask |= 1<inquiry_block = &default_hdd; + dev->inquiry_block = default_hdd; break; case SCSI_DEVICE_OPTICAL: // default SCSI CDROM - dev->inquiry_block = &default_optical; + dev->inquiry_block = default_optical; break; } - readSCSIDeviceConfig(dev); + readSCSIDeviceConfig(id, dev); } } } @@ -671,32 +694,14 @@ void findDriveImages(FsFile root) { /* * Setup initialization logfile */ -void initFileLog(int success_mhz) { +void initFileLog() { LOG_FILE = SD.open(LOG_FILENAME, O_WRONLY | O_CREAT | O_TRUNC); - LOG_FILE.println("BlueSCSI <-> SD - https://github.com/erichelgeson/BlueSCSI"); + LOG_FILE.println("BlueSCSI https://github.com/erichelgeson/BlueSCSI"); LOG_FILE.print("VER: "); LOG_FILE.print(VERSION); LOG_FILE.println(BUILD_TAGS); LOG_FILE.print("DEBUG:"); - LOG_FILE.print(DEBUG); - LOG_FILE.print(" SDFAT_FILE_TYPE:"); - LOG_FILE.println(SDFAT_FILE_TYPE); - LOG_FILE.print("SdFat version: "); - LOG_FILE.println(SD_FAT_VERSION_STR); - LOG_FILE.print("Sd Format: "); - switch(SD.vol()->fatType()) { - case FAT_TYPE_EXFAT: - LOG_FILE.println("exFAT"); - break; - default: - LOG_FILE.print("FAT 32/16/12 - Consider formatting the SD Card with exFAT for improved performance."); - } - LOG_FILE.print("SPI speed: "); - LOG_FILE.print(success_mhz); - LOG_FILE.println("Mhz"); - LOG_FILE.print("SdFat Max FileName Length: "); - LOG_FILE.println(MAX_FILE_PATH); - LOG_FILE.println("Initialized SD Card - let's go!"); + LOG_FILE.println(DEBUG); LOG_FILE.sync(); } @@ -730,7 +735,7 @@ void finalizeFileLog() { } LOG_FILE.println(":"); } - LOG_FILE.println("Finished initialization of SCSI Devices - Entering main loop."); + LOG_FILE.println("Finished configuration - Starting BlueSCSI"); LOG_FILE.sync(); #if DEBUG < 2 LOG_FILE.close(); @@ -948,7 +953,7 @@ void writeDataPhaseSD(SCSI_DEVICE *dev, uint32_t adds, uint32_t len) SCSI_PHASE_CHANGE(SCSI_PHASE_DATAIN); //Bus settle delay 400ns, file.seek() measured at over 1000ns. uint64_t pos = (uint64_t)adds * dev->m_rawblocksize; - dev->m_file->seekSet(pos); + dev->m_file.seekSet(pos); #ifdef XCVR TRANSCEIVER_IO_SET(vTR_DBP,TR_OUTPUT) #endif @@ -957,7 +962,7 @@ void writeDataPhaseSD(SCSI_DEVICE *dev, uint32_t adds, uint32_t len) for(uint32_t i = 0; i < len; i++) { // Asynchronous reads will make it faster ... m_resetJmp = false; - dev->m_file->read(m_buf, dev->m_rawblocksize); + dev->m_file.read(m_buf, dev->m_rawblocksize); enableResetJmp(); writeDataLoop(dev->m_blocksize, &m_buf[dev->m_sector_offset]); @@ -1029,18 +1034,18 @@ void readDataPhaseSD(SCSI_DEVICE *dev, uint32_t adds, uint32_t len) //Bus settle delay 400ns, file.seek() measured at over 1000ns. uint64_t pos = (uint64_t)adds * dev->m_blocksize; - dev->m_file->seekSet(pos); + dev->m_file.seekSet(pos); for(uint32_t i = 0; i < len; i++) { m_resetJmp = true; readDataLoop(dev->m_blocksize, m_buf); m_resetJmp = false; - dev->m_file->write(m_buf, dev->m_blocksize); + dev->m_file.write(m_buf, dev->m_blocksize); // If a reset happened while writing, break and let the flush happen before it is handled. if (m_isBusReset) { break; } } - dev->m_file->flush(); + dev->m_file.flush(); enableResetJmp(); } @@ -1055,7 +1060,7 @@ void verifyDataPhaseSD(SCSI_DEVICE *dev, uint32_t adds, uint32_t len) //Bus settle delay 400ns, file.seek() measured at over 1000ns. uint64_t pos = (uint64_t)adds * dev->m_blocksize; - dev->m_file->seekSet(pos); + dev->m_file.seekSet(pos); for(uint32_t i = 0; i < len; i++) { readDataLoop(dev->m_blocksize, m_buf); // This has just gone through the transfer to make things work, a compare would go here. @@ -1079,6 +1084,12 @@ void MsgIn2(int msg) */ void loop() { + byte m_id = 0; // Currently responding SCSI-ID + byte m_lun = 0xff; // Logical unit number currently responding + byte m_sts = 0; // Status byte + byte m_msg = 0; // Message bytes + byte m_msb[256]; // Command storage bytes + #ifdef XCVR // Reset all DB and Target pins, switch transceivers to input // Precaution against bugs or jumps which don't clean up properly @@ -1088,9 +1099,6 @@ void loop() TRANSCEIVER_IO_SET(vTR_INITIATOR,TR_INPUT) #endif - //int msg = 0; - m_msg = 0; - m_lun = 0xff; SCSI_DEVICE *dev = (SCSI_DEVICE *)0; // HDD image for current SCSI-ID, LUN do {} while( SCSI_IN(vBSY) || !SCSI_IN(vSEL) || SCSI_IN(vRST)); @@ -1255,16 +1263,16 @@ void loop() LOGN("onInquiry - InvalidLUN"); dev = &(scsi_device_list[m_id][0]); - byte temp = dev->inquiry_block->raw[0]; + byte temp = dev->inquiry_block.raw[0]; // If the LUN is invalid byte 0 of inquiry block needs to be 7fh - dev->inquiry_block->raw[0] = 0x7f; + dev->inquiry_block.raw[0] = 0x7f; // only write back what was asked for - writeDataPhase(cmd[4], dev->inquiry_block->raw); + writeDataPhase(cmd[4], dev->inquiry_block.raw); // return it back to normal if it was altered - dev->inquiry_block->raw[0] = temp; + dev->inquiry_block.raw[0] = temp; } else if(cmd[0] == SCSI_REQUEST_SENSE) { @@ -1290,7 +1298,7 @@ void loop() } dev = &(scsi_device_list[m_id][m_lun]); - if(!dev->m_file) + if(!dev->m_file.isOpen()) { dev->m_senseKey = SCSI_SENSE_ILLEGAL_REQUEST; dev->m_additional_sense_code = SCSI_ASC_LOGICAL_UNIT_NOT_SUPPORTED; @@ -1359,7 +1367,7 @@ static byte onNOP(SCSI_DEVICE *dev, const byte *cdb) */ byte onInquiry(SCSI_DEVICE *dev, const byte *cdb) { - writeDataPhase(cdb[4] < 47 ? cdb[4] : 47, dev->inquiry_block->raw); + writeDataPhase(cdb[4] < 47 ? cdb[4] : 47, dev->inquiry_block.raw); return SCSI_STATUS_GOOD; } @@ -1891,7 +1899,7 @@ byte onWriteBuffer(SCSI_DEVICE *dev, const byte *cdb) byte onReadBuffer(SCSI_DEVICE *dev, const byte *cdb) { byte mode = cdb[1] & 7; - uint32_t allocLength = ((uint32_t)cdb[6] << 16) | ((uint32_t)cdb[7] << 8) | cdb[8]; + unsigned m_scsi_buf_size = 0; LOGN("-ReadBuffer"); LOGHEXN(mode); @@ -1911,6 +1919,7 @@ byte onReadBuffer(SCSI_DEVICE *dev, const byte *cdb) writeDataPhase(4 + m_scsi_buf_size, m_buf); #if DEBUG > 0 + uint32_t allocLength = ((uint32_t)cdb[6] << 16) | ((uint32_t)cdb[7] << 8) | cdb[8]; for (unsigned i = 0; i < allocLength; i++) { LOGHEX(m_scsi_buf[i]);LOG(" "); } diff --git a/src/BlueSCSI.h b/src/BlueSCSI.h index 1d6eaff..6f45cca 100644 --- a/src/BlueSCSI.h +++ b/src/BlueSCSI.h @@ -15,6 +15,11 @@ #define SCSI_BUF_SIZE 512 // Size of the SCSI Buffer #define HDD_BLOCK_SIZE 512 #define OPTICAL_BLOCK_SIZE 2048 +#define BLUESCSI_INI "bluescsi.ini" + +#define SCSI_VENDOR_LENGTH 8 +#define SCSI_PRODUCT_LENGTH 16 +#define SCSI_REVISION_LENGTH 4 // HDD format #define MAX_BLOCKSIZE 4096 // Maximum BLOCK size @@ -32,6 +37,18 @@ enum SCSI_DEVICE_TYPE SCSI_DEVICE_OPTICAL, }; +#define SCSI_DEVICE_FLAG_OPTICAL_MODE2 0x1 +#define SCSI_DEVICE_FLAG_OPTICAL_RAW 0x2 + +#define SET_DEVICE_FLAG(var, flag) (var |= flag) +#define UNSET_DEVICE_FLAG(var, flag) (var &= ~flag) +#define IS_DEVICE_FLAG_SET(var, flag) ((var & flag) == flag) +#define IS_RAW(var) IS_DEVICE_FLAG_SET(var, SCSI_DEVICE_FLAG_OPTICAL_RAW) +#define IS_MODE2(var) IS_DEVICE_FLAG_SET(var, SCSI_DEVICE_FLAG_OPTICAL_MODE2) + +#define INT_TO_CHAR(var) var+'0' +#define CHAR_TO_INT(var) var-'0' + #define CDROM_RAW_SECTORSIZE 2352 #define CDROM_COMMON_SECTORSIZE 2048 @@ -124,7 +141,7 @@ enum SCSI_DEVICE_TYPE // SCSI output pin control: opendrain active LOW (direct pin drive) #define SCSI_OUT(VPIN,ACTIVE) { GPIOREG(VPIN)->BSRR = BITMASK(VPIN)<<((ACTIVE)?16:0); } -// SCSI input pin check (inactive=0,avtive=1) +// SCSI input pin check (inactive=0,active=1) #define SCSI_IN(VPIN) ((~GPIOREG(VPIN)->IDR>>(VPIN&15))&1) #define NOP(x) for(unsigned _nopcount = x; _nopcount; _nopcount--) { asm("NOP"); } @@ -231,7 +248,8 @@ enum SCSI_DEVICE_TYPE */ // Parity bit generation -#define PTY(V) (1^((V)^((V)>>1)^((V)>>2)^((V)>>3)^((V)>>4)^((V)>>5)^((V)>>6)^((V)>>7))&1) +//#define PTY(V) (1^((V)^((V)>>1)^((V)>>2)^((V)>>3)^((V)>>4)^((V)>>5)^((V)>>6)^((V)>>7))&1) +#define PTY(n) ((1 ^ (n) ^ ((n)>>1) ^ ((n)>>2) ^ ((n)>>3) ^ ((n)>>4) ^ ((n)>>5) ^ ((n)>>6) ^ ((n)>>7)) & 1) // Data byte to BSRR register setting value conversion table // BSRR[31:24] = DB[7:0] @@ -263,7 +281,7 @@ uint32_t db_bsrr[256]; -struct SCSI_INQUIRY_DATA +typedef struct _SCSI_INQUIRY_DATA { union { @@ -306,23 +324,22 @@ struct SCSI_INQUIRY_DATA // raw bytes byte raw[64]; }; -}; +} SCSI_INQUIRY_DATA; // HDD image typedef __attribute__((aligned(4))) struct _SCSI_DEVICE { - FsFile *m_file; // File object + FsFile m_file; // File object uint64_t m_fileSize; // File size uint16_t m_blocksize; // SCSI BLOCK size uint16_t m_rawblocksize; // OPTICAL raw sector size uint8_t m_type; // SCSI device type uint32_t m_blockcount; // blockcount - bool m_raw; // Raw disk - SCSI_INQUIRY_DATA *inquiry_block; // SCSI information + SCSI_INQUIRY_DATA inquiry_block; // SCSI information uint8_t m_senseKey; // Sense key uint16_t m_additional_sense_code; // ASC/ASCQ - bool m_mode2; // MODE2 CDROM uint8_t m_sector_offset; // optical sector offset for missing sync header + uint8_t flags; // various device flags } SCSI_DEVICE; static byte cdb_len_lookup[] = { From 2d0b46629614b4d41699ef267daacf8d8c31f322 Mon Sep 17 00:00:00 2001 From: Troy Date: Wed, 28 Dec 2022 11:30:07 -0500 Subject: [PATCH 3/5] remove miniIni from PIO lib_deps --- platformio.ini | 1 - 1 file changed, 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index ae59c0b..bca0747 100644 --- a/platformio.ini +++ b/platformio.ini @@ -7,7 +7,6 @@ default_envs = STM32F1 framework = arduino lib_deps = greiman/SdFat @ 2.2.0 - miniIni upload_protocol = stlink ; Different gcc versions produce much different binaries in terms of speed. platform_packages = platformio/toolchain-gccarmnoneeabi@1.90301.200702 From c901efb9292e7addee2413cf81f75d502e4cff1f Mon Sep 17 00:00:00 2001 From: Troy Date: Wed, 28 Dec 2022 15:16:21 -0500 Subject: [PATCH 4/5] fixed up CI/CD to work with ext libs better --- .github/workflows/main.yml | 5 +---- src/BlueSCSI.cpp | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 65ab15e..2b8e3d9 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -27,8 +27,5 @@ jobs: python -m pip install --upgrade pip pip install --upgrade platformio - - name: Install library dependencies - run: pio lib -g install 1 - - name: Run PlatformIO - run: pio ci --project-conf platformio.ini . + run: pio run -e STM32F1 -e STM32F1-USB -e STM32F1-XCVR -e STM32F1-USB-96MHz -e STM32F1-USB-128MHz diff --git a/src/BlueSCSI.cpp b/src/BlueSCSI.cpp index 6d4ae89..3d2b4cb 100644 --- a/src/BlueSCSI.cpp +++ b/src/BlueSCSI.cpp @@ -52,7 +52,7 @@ #include "scsi_sense.h" #include "scsi_status.h" #include "scsi_mode.h" -#include +#include "minIni.h" #ifdef USE_STM32_DMA #warning "warning USE_STM32_DMA" From c5eff4f5fd45af48d9fb9b31396ff7c04f5836b5 Mon Sep 17 00:00:00 2001 From: Troy Date: Wed, 28 Dec 2022 22:16:54 -0500 Subject: [PATCH 5/5] megastemode renamed to maplunstoids in inifile --- src/BlueSCSI.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/BlueSCSI.cpp b/src/BlueSCSI.cpp index 3d2b4cb..b20b9e7 100644 --- a/src/BlueSCSI.cpp +++ b/src/BlueSCSI.cpp @@ -74,7 +74,7 @@ SCSI_INQUIRY_DATA default_hdd, default_optical; // Enables SCSI IDs to be representing as LUNs on SCSI ID 0 // This supports a specific case for the Atari MegaSTE internal SCSI adapter -bool megaste_mode = false; +bool ids_as_luns = false; // function table byte (*scsi_command_table[MAX_SCSI_COMMAND])(SCSI_DEVICE *dev, const byte *cdb); @@ -518,10 +518,10 @@ void setup() //HD image file open scsi_id_mask = 0x00; - if(ini_getl("SCSI", "megastemode", 0, BLUESCSI_INI)) + if(ini_getl("SCSI", "MapLunsToIDs", 0, BLUESCSI_INI)) { - LOG_FILE.println("MSTE_MODE - IDs treated as LUNs"); - megaste_mode = true; + LOG_FILE.println("IDs treated as LUNs for ID0"); + ids_as_luns = true; } if(SD.exists("scsi-config.txt")) { @@ -1229,7 +1229,7 @@ void loop() if(m_lun > MAX_SCSILUN) { m_lun = (cmd[1] & 0xe0) >> 5; - if(megaste_mode) + if(ids_as_luns) { // if this mode is enabled we are going to substitute all SCSI IDs as LUNs on ID0 // this is because the MegaSTE internal adapter only supports ID0. This lets multiple