Compare commits

...

98 Commits

Author SHA1 Message Date
Eric Helgeson
bf5823468a Add 50pin 1.1 case back, was accidentally removed in 57ff0cd3b4 2024-02-22 07:30:57 -06:00
Eric Helgeson
2baa0155e1
Merge pull request #262 from dotsam/better-logging
Reformatted Logging
2024-02-17 15:59:33 -06:00
Sam Edwards
3a9db99723 Changing indentation on log lines 2024-02-17 11:23:17 -08:00
Sam Edwards
70eda86484 Ensure log output is correct with used IDs 2024-02-17 11:23:17 -08:00
Sam Edwards
9d4207ea14 Only read INI per-device config once in "finalize" function, include filenames in output 2024-02-17 11:23:17 -08:00
Sam Edwards
1d49003fe1 Clean up logging in setup functions 2024-02-17 11:22:27 -08:00
Sam Edwards
0a30396c3b Make better use of macros, functions, and dynamic char array lengths 2024-02-17 11:21:26 -08:00
Sam Edwards
ba06827814 Whitespace/Type cleanup 2024-02-17 11:21:26 -08:00
Eric Helgeson
a45af3edec
Merge pull request #261 from WilliamLeara/fix_typographical_errors
fix typographical mistakes in comments
2024-02-17 12:05:27 -06:00
William Leara
0be37ccde0 fix typographical mistakes in comments
Also, fix up some white-space issues.  No functional change here.
2024-02-14 13:31:35 -06:00
Eric Helgeson
e236b5b054
Merge pull request #252 from dotsam/easy-leds
Easier to change LEDs
2024-02-09 20:11:36 -06:00
Sam Edwards
47179c5fd0
Easier to change LEDs
- For building for boards with different LEDs and configurations
 - Define mode for LED
 - Update GPIO macros for port C
 - Use macros to generate bits for registers
2024-02-09 17:42:07 -08:00
Eric Helgeson
59c858332a dev 2023-11-16 21:39:00 -06:00
Eric Helgeson
dddb7bfc1c v1.1-20231116 2023-11-16 21:38:41 -06:00
Eric Helgeson
8b79df00ba
Merge pull request #257 from erichelgeson/eric/toolbox
BlueSCSI Toolbox
2023-11-16 21:35:26 -06:00
Eric Helgeson
7c9428131b Update commands to match v2 2023-11-16 21:30:15 -06:00
Eric Helgeson
e35bae560c constant for block size 2023-11-16 21:30:15 -06:00
Eric Helgeson
13d7b985b7 Reuse m_buf and allow for 100 files 2023-11-16 21:30:15 -06:00
Eric Helgeson
27b7427301 hide hidden files 2023-11-16 21:30:15 -06:00
Eric Helgeson
98162fcd84 Fix issue with large files MSB being overwritten 2023-11-16 21:30:10 -06:00
Eric Helgeson
2be810e2ca 68k app 2023-10-24 17:17:12 -05:00
Eric Helgeson
4f7c0fe2c2
Merge pull request #253 from dotsam/compiler-warnings
Fix some compiler warnings
2023-08-13 10:22:33 -05:00
Sam Edwards
458617a827
Fix some compiler warnings
- Fix syntax of a cast to a uint32
 - Remove defines that are already made by the base platform
2023-08-11 11:47:34 -07:00
Eric Helgeson
810eae9be3
Merge pull request #251 from dotsam/fix-debug
Ensure allocLength is defined when needed in onReadBuffer
2023-08-10 20:37:08 -05:00
Sam Edwards
d67fa80cf0
Ensure allocLength is defined when needed in onReadBuffer 2023-08-10 16:57:06 -07:00
Eric Helgeson
9e746ba145 Back to snapshot 2023-07-08 12:06:50 -05:00
Eric Helgeson
e0d115f33c v1.1-20230708 2023-07-08 11:53:38 -05:00
Eric Helgeson
27d13192b0 Ignore kicad backup dir 2023-07-08 11:45:08 -05:00
Eric Helgeson
43335afbdb Use fork of SdFat that supports gpt partitions so users do not have to format their cards with mbr. Thanks @PetteriAimonen for the patch. 2023-04-01 11:24:11 -05:00
Troy
ad4737f384 INQUIRY supports small transfer sizes now
this fixes some Apple II SCSI cards like RAMFast and CMS
2023-04-01 11:23:53 -05:00
Eric Helgeson
927f8101fa Allow optical files that are set to RO on the SD card to be used 2023-04-01 11:20:19 -05:00
Eric Helgeson
142117c83a Merge remote-tracking branch 'jokker/troy/inifile' 2023-04-01 11:13:05 -05:00
Troy
c5eff4f5fd megastemode renamed to maplunstoids in inifile 2022-12-28 22:16:54 -05:00
Troy
c901efb929 fixed up CI/CD to work with ext libs better 2022-12-28 15:16:21 -05:00
Troy
2d0b466296 remove miniIni from PIO lib_deps 2022-12-28 11:30:07 -05:00
Eric Helgeson
075e21d981
Merge pull request #208 from erichelgeson/eric/clarifyType
Clarify the bluepill must be the C8T6 and not a C6T6
2022-12-27 16:38:11 -06:00
Eric Helgeson
71b1d3ca31 Clarify the bluepill must be the C8T6 and not a C6T6 2022-12-27 15:37:05 -06:00
Troy
5bad53008a 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
2022-12-22 17:45:20 -05:00
Troy
c2c4b83925 miniIni lib added 2022-12-22 11:19:59 -05:00
Eric Helgeson
5506a90042 Back to snapshot 2022-12-22 08:55:46 -06:00
Eric Helgeson
b117ebb39d v1.1-20221203 2022-12-03 16:14:13 -06:00
Eric Helgeson
139a510ee7
Merge pull request #201 from erichelgeson/eric/fragmented
Warn user if file is fragmented
2022-12-03 16:04:45 -06:00
Eric Helgeson
7ee2c44c6a Warn user if file is fragmented
See: https://github.com/greiman/SdFat/issues/256#issuecomment-778795554
- performance can be impacted if the file is fragmented on the SD card.
2022-12-03 15:22:07 -06:00
Eric Helgeson
f4d7cdfa92
Merge pull request #196 from mynameistroy/troy/megaste_mode
MegaSTE mode added for using IDs as LUNs
2022-12-01 14:28:58 -06:00
Eric Helgeson
a8903d42f2
Merge pull request #194 from mynameistroy/troy/cdb_length_fix
added a full lookup table for cdb length
2022-12-01 14:28:50 -06:00
Troy
0ae77a7b48 cleaned things up and added a log message 2022-11-30 21:42:38 -05:00
Eric Helgeson
726d72c09b
Merge pull request #186 from erichelgeson/eric/spiTake3
Revert "We only need to test 50 and 25 as the rest are just divided and rounded to full and half."
2022-11-22 16:51:21 -06:00
Eric Helgeson
dc0bce859c Revert "We only need to test 50 and 25 as the rest are just divided and rounded to full and half."
This reverts commit 1cfaf00594.
2022-11-22 16:50:07 -06:00
Troy
dba1860856 MegaSTE mode added for using IDs as LUNs 2022-11-13 18:08:41 -05:00
Troy
6ec75300c4 added a full lookup table for cdb length
this fixes the issue of 16 byte cdb commands
from causing problems by not being detected correctly
2022-11-06 12:20:30 -05:00
Eric Helgeson
5bb2dee71f
Merge pull request #187 from erichelgeson/eric/renameSTL
Rename file to be more clear
2022-10-14 16:20:32 -05:00
Eric Helgeson
bb4b688cad Rename file to be more clear 2022-10-14 16:20:04 -05:00
Eric Helgeson
44b6270ef8
Merge pull request #172 from lausvi/main
external-db25 3D-printed case remix
2022-10-14 16:08:32 -05:00
Eric Helgeson
30cf64ff83
Merge pull request #185 from command-tab/patch-1
Fix typo in README.adoc
2022-10-14 16:06:35 -05:00
Collin Allen
d3ef149aa3
Fix typo in README.adoc
Gerbers was misspelled as Grebers
2022-10-14 12:18:09 -07:00
Eric Helgeson
e930ecfcde
Merge pull request #183 from mynameistroy/troy/myst_fix
Fix for incorrect response to READ_DVD_STRUCTURE
2022-10-13 14:53:50 -05:00
Troy
847456203f Cleaned up SDfs logging 2022-10-12 21:15:18 -04:00
Troy
fb3a266c86 Report error for READ_DVD_STRUCTURE
fixes issues with drivers getting confused about the optical image file
2022-10-12 21:08:47 -04:00
Ville Laustela
330c3edd91 external-3D-printed-case-remix 2022-09-20 19:11:43 +03:00
Ville Laustela
57ff0cd3b4 external-3D-printed-case-remix 2022-09-20 19:07:56 +03:00
Eric Helgeson
452930940c Back to snapshot 2022-09-18 15:30:42 -05:00
Eric Helgeson
7c6f9aef75 v1.1-20220917 2022-09-17 09:53:00 -05:00
Mike
a7af02057f Add apostrophe to log message 2022-09-17 09:53:00 -05:00
Eric Helgeson
19f6b428a1
Merge pull request #151 from erichelgeson/eric/longFileNames
Allow for file names to be up to 64 chars
2022-09-17 09:42:04 -05:00
Eric Helgeson
b0a47bc376 Allow for file names to be up to 64 chars 2022-09-17 09:37:32 -05:00
Eric Helgeson
dc9552410f
Merge pull request #130 from mynameistroy/troy/optical
CD/DVD emulation
2022-09-13 20:46:54 -05:00
Troy
67d3909dd9 Cleaned up MODE_SELECT blocksize request
OnReadBuffer uses generic buffer and only transfers actual length
2022-09-11 18:32:29 -04:00
Troy
3f279230d9 cleanup Apple Mode Page handling 2022-09-08 22:02:55 -04:00
Troy
331cd96ac5 minor logging cleanup 2022-09-06 22:46:38 -04:00
Troy
3952181d4f Clean up some remaining pinMode => gpio_mode 2022-09-06 22:45:26 -04:00
Eric Helgeson
c12aa478d5
Merge pull request #161 from erichelgeson/eric/kay_stl
Add Kay's STL
2022-08-25 18:50:12 -05:00
Eric Helgeson
9831c38237 Add Kay's STL 2022-08-25 18:47:59 -05:00
Troy
94a5e711e3 MODE SELECT supports CDROM 512/2048 sector toggle
CDROM devices return a DBD properly
CDROM Error Mode Page has a default retry of 1
More streamlining of debug logging
2022-08-17 21:15:15 -04:00
Eric Helgeson
6b2152d1f7
Merge pull request #152 from erichelgeson/eric/SDFat2.2.0
Upgrade SdFat from 2.0.6 to 2.2.0
2022-08-03 09:07:23 -05:00
Eric Helgeson
a06e840e39 Upgrade SdFat from 2.0.6 to 2.2.0
No change in perf
2022-07-26 18:28:19 -05:00
Troy
32453b9886 added missing set of raw sector size 2022-07-24 23:11:15 -04:00
Troy
3a3d68cf99 alternative sector size supported
this let's .BIN files get used at the very least, maybe more depending
on how some of the other optical formats look
reverted a small SCSI phase change that causes problems
2022-07-22 20:38:59 -04:00
Troy
30b794e03d merged in latest HEAD, cleaned up some warnings 2022-07-17 11:49:08 -04:00
Troy
2611ec885b out of phase error fixed, SGI Indy works now
basic determination of arbitration
2022-07-17 11:26:07 -04:00
Troy
953309be30 ISO-9660 raw image support for CD/DVD emulation 2022-07-17 11:26:05 -04:00
Troy
b00dac7339 more code shuffling 2022-07-17 11:20:58 -04:00
Troy
b53524e6c7 code layout adjustments 2022-07-17 11:20:55 -04:00
Eric Helgeson
16c0cfd57a
Merge pull request #144 from erichelgeson/eric/minorFixes
Minor Updates and Fixes
2022-07-16 15:05:34 -05:00
Eric Helgeson
40e4590686 Product back to BLUESCSI F1 2022-07-16 15:02:19 -05:00
Eric Helgeson
d4f86ddaed LED on/off is around all commands, no need to have it here. 2022-07-16 15:02:19 -05:00
Eric Helgeson
ff8990e5c5 Test unit ready is a nop and not defined 2022-07-16 15:02:19 -05:00
Eric Helgeson
173cc6126a Turn warnings on 2022-07-16 15:02:19 -05:00
Eric Helgeson
2a95bc35ff
Merge pull request #142 from mynameistroy/troy/phase_fix
SCSI Phase handling improved for SCSI-2
2022-07-16 15:02:02 -05:00
Eric Helgeson
219e3d0f23
Merge pull request #141 from mynameistroy/troy/lun_fix
stop invalid LUNs from reading unallocated structs
2022-07-16 15:01:55 -05:00
Eric Helgeson
2bd79bb487
Merge pull request #140 from mynameistroy/troy/icd
Support for Atari ST ICD commands
2022-07-16 15:01:42 -05:00
Eric Helgeson
53ad02384d
Merge branch 'main' into troy/icd 2022-07-16 15:01:35 -05:00
Eric Helgeson
e26e41dcbd
Merge pull request #143 from erichelgeson/eric/pinSDFat
Pin SdFat to 2.0.6
2022-07-16 13:40:32 -05:00
Eric Helgeson
2f8dd8a3fe Pin SdFat to 2.0.6 to allow CI to run 2022-07-16 13:13:34 -05:00
Troy
5d80b8adbf added proper define for ICD command 2022-07-13 17:58:59 -04:00
Troy
e5d78139de SCSI Phase handling improved for SCSI-2 2022-07-03 22:13:25 -04:00
Troy
0895f00094 stop invalid LUNs from reading unallocated structs 2022-07-03 15:39:17 -04:00
Troy
58e880a9e1 Support for Atari ST ICD commands 2022-06-29 21:36:33 -04:00
Eric Helgeson
54500e18b8 Back to snapshot 2022-06-26 10:57:03 -05:00
20 changed files with 2604 additions and 734 deletions

View File

@ -27,8 +27,5 @@ jobs:
python -m pip install --upgrade pip python -m pip install --upgrade pip
pip install --upgrade platformio pip install --upgrade platformio
- name: Install library dependencies
run: pio lib -g install 1
- name: Run PlatformIO - 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

1
.gitignore vendored
View File

@ -3,3 +3,4 @@
.vscode/ .vscode/
workspace.code-workspace workspace.code-workspace
dist/ dist/
hw/*/*-backups/

View File

@ -1,6 +1,6 @@
# Mounts # Mounts
## Desktop ## Desktop
Provides mouting holes for the BlueSCSI along with side and bottom holes for common mounting in computers. Provides mouting holes for the BlueSCSI along with side and bottom holes for common mounting in computers.
@ -10,6 +10,8 @@ Please pre-tap any screw holes before mounting.
Print with supports for front overhangs. Tight fit to hold everything together. Print with supports for front overhangs. Tight fit to hold everything together.
Remix = a slightly modified version with light-pipes for the LEDs and some geometry fixes.
# License # License
BlueSCSI 3D files © 2021 by Eric Helgeson is licensed under Attribution-NonCommercial 4.0 International BlueSCSI 3D files © 2021 by Eric Helgeson is licensed under Attribution-NonCommercial 4.0 International

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

View File

@ -10,7 +10,7 @@ BlueSCSI & ArdSCSino are hardware that reproduces SCSI devices (hard disks) with
* Enable/Disable Passive SCSI termination * Enable/Disable Passive SCSI termination
* An alternative power source if not able to be powered by the SCSI bus * An alternative power source if not able to be powered by the SCSI bus
* Documentation * Documentation
* Open Hardware (KiCad & Grebers) * Open Hardware (KiCad & Gerbers)
`ArdSCSino-stm32` created by https://github.com/ztto/ArdSCSino-stm32[ztto] is the STM32 version of `ArdSCSino` `ArdSCSino-stm32` created by https://github.com/ztto/ArdSCSino-stm32[ztto] is the STM32 version of `ArdSCSino`

View File

@ -27,6 +27,8 @@ https://www.mouser.com/ProjectManager/ProjectDetail.aspx?AccessID=c5cc83feff
Buy from a place where returns are easy. Ensure the photo in the listing shows a chip that says STM32 on it. Buy from a place where returns are easy. Ensure the photo in the listing shows a chip that says STM32 on it.
The BluePill must be a STM32F103**C8T6** - a C6T6 will not work. Check the listings closely.
https://www.amazon.com/s?k=stm32f103c8t6 https://www.amazon.com/s?k=stm32f103c8t6
https://www.ebay.com/sch/i.html?_nkw=stm32f103c8t6 https://www.ebay.com/sch/i.html?_nkw=stm32f103c8t6

15
lib/minIni/minGlue.h Normal file
View File

@ -0,0 +1,15 @@
/* Glue functions for the minIni library to SdFat library */
#include <SdFat.h>
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))

952
lib/minIni/minIni.cpp Normal file
View File

@ -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 <assert.h>
#endif
#if !defined __T || defined INI_ANSIONLY
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#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, &quotes); /* 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, &quotes); /* 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 */

166
lib/minIni/minIni.h Normal file
View File

@ -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 <tchar.h>
#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 <string>
/* 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<int>(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 */

View File

@ -6,15 +6,12 @@ default_envs = STM32F1
[env] [env]
framework = arduino framework = arduino
lib_deps = lib_deps =
greiman/SdFat @ ^2.0.6 SdFat=https://github.com/BlueSCSI/SdFat#2.2.0-gpt
upload_protocol = stlink upload_protocol = stlink
; Different gcc versions produce much different binaries in terms of speed. ; Different gcc versions produce much different binaries in terms of speed.
platform_packages = platformio/toolchain-gccarmnoneeabi@1.90301.200702 platform_packages = platformio/toolchain-gccarmnoneeabi@1.90301.200702
build_flags = build_flags =
-w
-DARDUINO_GENERIC_STM32F103C
-DARDUINO_LIB_DISCOVERY_PHASE -DARDUINO_LIB_DISCOVERY_PHASE
-DARDUINO=10813
-DARDUINO_ARCH_STM32 -DARDUINO_ARCH_STM32
-DDEBUG_LEVEL=DEBUG_NONE -DDEBUG_LEVEL=DEBUG_NONE
-O2 -O2
@ -67,7 +64,7 @@ board_build.mcu = stm32f103c8t6
board_build.core = maple board_build.core = maple
framework = arduino framework = arduino
lib_deps = lib_deps =
greiman/SdFat @ ^2.0.6 greiman/SdFat @ 2.2.0
upload_protocol = dfu upload_protocol = dfu
; Different gcc versions produce much different binaries in terms of speed. ; Different gcc versions produce much different binaries in terms of speed.
platform_packages = platformio/toolchain-gccarmnoneeabi@1.90301.200702 platform_packages = platformio/toolchain-gccarmnoneeabi@1.90301.200702
@ -79,10 +76,7 @@ build_flags =
-D USB_MANUFACTURER="Unknown" -D USB_MANUFACTURER="Unknown"
-D USB_PRODUCT="\"BLUEPILL_F103C8\"" -D USB_PRODUCT="\"BLUEPILL_F103C8\""
-D HAL_PCD_MODULE_ENABLED -D HAL_PCD_MODULE_ENABLED
-w
-DARDUINO_GENERIC_STM32F103C
-DARDUINO_LIB_DISCOVERY_PHASE -DARDUINO_LIB_DISCOVERY_PHASE
-DARDUINO=10813
-DARDUINO_ARCH_STM32 -DARDUINO_ARCH_STM32
-DDEBUG_LEVEL=DEBUG_NONE -DDEBUG_LEVEL=DEBUG_NONE
-O2 -O2

File diff suppressed because it is too large Load Diff

View File

@ -6,7 +6,7 @@
// SCSI config // SCSI config
#define MAX_SCSIID 7 // Maximum number of supported SCSI-IDs (The minimum is 0) #define MAX_SCSIID 7 // Maximum number of supported SCSI-IDs (The minimum is 0)
#define MAX_SCSILUN 1 // Maximum number of LUNs supported (The minimum is 0) #define MAX_SCSILUN 8 // Maximum number of LUNs supported (The minimum is 0)
#define NUM_SCSIID MAX_SCSIID // Number of enabled SCSI IDs #define NUM_SCSIID MAX_SCSIID // Number of enabled SCSI IDs
#define NUM_SCSILUN 1 // Number of enabled LUNs #define NUM_SCSILUN 1 // Number of enabled LUNs
#define READ_PARITY_CHECK 0 // Perform read parity check (unverified) #define READ_PARITY_CHECK 0 // Perform read parity check (unverified)
@ -15,6 +15,11 @@
#define SCSI_BUF_SIZE 512 // Size of the SCSI Buffer #define SCSI_BUF_SIZE 512 // Size of the SCSI Buffer
#define HDD_BLOCK_SIZE 512 #define HDD_BLOCK_SIZE 512
#define OPTICAL_BLOCK_SIZE 2048 #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 // HDD format
#define MAX_BLOCKSIZE 4096 // Maximum BLOCK size #define MAX_BLOCKSIZE 4096 // Maximum BLOCK size
@ -26,6 +31,29 @@
#define ERROR_FALSE_INIT 3 #define ERROR_FALSE_INIT 3
#define ERROR_NO_SDCARD 5 #define ERROR_NO_SDCARD 5
enum SCSI_DEVICE_TYPE
{
SCSI_DEVICE_HDD,
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
#define MAX_SCSI_COMMAND 0xff
#define SCSI_COMMAND_HANDLER(x) static byte x(SCSI_DEVICE *dev, const byte *cdb)
#if DEBUG #if DEBUG
#define LOG(XX) Serial.print(XX) #define LOG(XX) Serial.print(XX)
@ -71,8 +99,6 @@
#define IO PB7 // SCSI:I/O #define IO PB7 // SCSI:I/O
#define SD_CS PA4 // SDCARD:CS #define SD_CS PA4 // SDCARD:CS
#define LED PC13 // LED
#define LED2 PA0 // External LED
// Image Set Selector // Image Set Selector
#ifdef XCVR #ifdef XCVR
@ -88,17 +114,29 @@
#define PBREG GPIOB->regs #define PBREG GPIOB->regs
#define PCREG GPIOC->regs #define PCREG GPIOC->regs
// LED control
#define LED_ON() PCREG->BSRR = 0b00100000000000000000000000000000; PAREG->BSRR = 0b00000000000000000000000000000001;
#define LED_OFF() PCREG->BSRR = 0b00000000000000000010000000000000; PAREG->BSRR = 0b00000000000000010000000000000000;
// Virtual pin (Arduio compatibility is slow, so make it MCU-dependent) // Virtual pin (Arduio compatibility is slow, so make it MCU-dependent)
#define PA(BIT) (BIT) #define PA(BIT) (BIT)
#define PB(BIT) (BIT+16) #define PB(BIT) (BIT+16)
#define PC(BIT) (BIT+32)
// Virtual pin decoding // Virtual pin decoding
#define GPIOREG(VPIN) ((VPIN)>=16?PBREG:PAREG) #define GPIOREG(VPIN) ((VPIN)>=16?((VPIN)>=32?PCREG:PBREG):PAREG)
#define BITMASK(VPIN) (1<<((VPIN)&15)) #define BITMASK(VPIN) (1<<((VPIN)&15))
// Built-in LED
#define LED PC13
#define vLED PC(13)
#define LED_MODE GPIO_OUTPUT_OD
// External LED
#define LED2 PA0
#define vLED2 PA(0)
#define LED2_MODE GPIO_OUTPUT_PP
// LED control
#define LED_ON() GPIOREG(vLED)->BSRR = BITMASK(vLED) << (LED_MODE == GPIO_OUTPUT_PP ? 0 : 16); GPIOREG(vLED2)->BSRR = BITMASK(vLED2) << (LED2_MODE == GPIO_OUTPUT_PP ? 0 : 16);
#define LED_OFF() GPIOREG(vLED)->BSRR = BITMASK(vLED) << (LED_MODE == GPIO_OUTPUT_PP ? 16 : 0); GPIOREG(vLED2)->BSRR = BITMASK(vLED2) << (LED2_MODE == GPIO_OUTPUT_PP ? 16 : 0);
#define vATN PA(8) // SCSI:ATN #define vATN PA(8) // SCSI:ATN
#define vBSY PA(9) // SCSI:BSY #define vBSY PA(9) // SCSI:BSY
#define vACK PA(10) // SCSI:ACK #define vACK PA(10) // SCSI:ACK
@ -113,7 +151,7 @@
// SCSI output pin control: opendrain active LOW (direct pin drive) // SCSI output pin control: opendrain active LOW (direct pin drive)
#define SCSI_OUT(VPIN,ACTIVE) { GPIOREG(VPIN)->BSRR = BITMASK(VPIN)<<((ACTIVE)?16:0); } #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 SCSI_IN(VPIN) ((~GPIOREG(VPIN)->IDR>>(VPIN&15))&1)
#define NOP(x) for(unsigned _nopcount = x; _nopcount; _nopcount--) { asm("NOP"); } #define NOP(x) for(unsigned _nopcount = x; _nopcount; _nopcount--) { asm("NOP"); }
@ -144,7 +182,7 @@
| 1 | 1 | 1 | MESSAGE IN | Initiator from target / | phase | | 1 | 1 | 1 | MESSAGE IN | Initiator from target / | phase |
|-----------------------------------------------------------------------------| |-----------------------------------------------------------------------------|
| Key: 0 = False, 1 = True, * = Reserved for future standardization | | Key: 0 = False, 1 = True, * = Reserved for future standardization |
+=============================================================================+ +=============================================================================+
*/ */
// SCSI phase change as single write to port B // SCSI phase change as single write to port B
#define SCSIPHASEMASK(MSGACTIVE, CDACTIVE, IOACTIVE) ((BITMASK(vMSG)<<((MSGACTIVE)?16:0)) | (BITMASK(vCD)<<((CDACTIVE)?16:0)) | (BITMASK(vIO)<<((IOACTIVE)?16:0))) #define SCSIPHASEMASK(MSGACTIVE, CDACTIVE, IOACTIVE) ((BITMASK(vMSG)<<((MSGACTIVE)?16:0)) | (BITMASK(vCD)<<((CDACTIVE)?16:0)) | (BITMASK(vIO)<<((IOACTIVE)?16:0)))
@ -178,7 +216,7 @@
#define SCSI_TARGET_ACTIVE() { gpio_mode(REQ, GPIO_OUTPUT_PP); gpio_mode(MSG, GPIO_OUTPUT_PP); gpio_mode(CD, GPIO_OUTPUT_PP); gpio_mode(IO, GPIO_OUTPUT_PP); gpio_mode(BSY, GPIO_OUTPUT_PP); TRANSCEIVER_IO_SET(vTR_TARGET,TR_OUTPUT);} #define SCSI_TARGET_ACTIVE() { gpio_mode(REQ, GPIO_OUTPUT_PP); gpio_mode(MSG, GPIO_OUTPUT_PP); gpio_mode(CD, GPIO_OUTPUT_PP); gpio_mode(IO, GPIO_OUTPUT_PP); gpio_mode(BSY, GPIO_OUTPUT_PP); TRANSCEIVER_IO_SET(vTR_TARGET,TR_OUTPUT);}
// BSY,REQ,MSG,CD,IO Turn off output, BSY is the last input // BSY,REQ,MSG,CD,IO Turn off output, BSY is the last input
#define SCSI_TARGET_INACTIVE() { pinMode(REQ, INPUT); pinMode(MSG, INPUT); pinMode(CD, INPUT); pinMode(IO, INPUT); pinMode(BSY, INPUT); TRANSCEIVER_IO_SET(vTR_TARGET,TR_INPUT); } #define SCSI_TARGET_INACTIVE() { gpio_mode(REQ, GPIO_INPUT_FLOATING); gpio_mode(MSG, GPIO_INPUT_FLOATING); gpio_mode(CD, GPIO_INPUT_FLOATING); gpio_mode(IO, GPIO_INPUT_FLOATING); gpio_mode(BSY, GPIO_INPUT_FLOATING); TRANSCEIVER_IO_SET(vTR_TARGET,TR_INPUT); }
#define DB_MODE_OUT 1 // push-pull mode #define DB_MODE_OUT 1 // push-pull mode
#define DB_MODE_IN 4 // floating inputs #define DB_MODE_IN 4 // floating inputs
@ -207,20 +245,22 @@
// Put DB and DP in output mode // Put DB and DP in output mode
#define SCSI_DB_OUTPUT() { PBREG->CRL=(PBREG->CRL &0xfffffff0)|DB_MODE_OUT; PBREG->CRH = 0x11111111*DB_MODE_OUT; } #define SCSI_DB_OUTPUT() { PBREG->CRL=(PBREG->CRL &0xfffffff0)|DB_MODE_OUT; PBREG->CRH = 0x11111111*DB_MODE_OUT; }
// Put DB and DP in input mode // Put DB and DP in input mode
#define SCSI_DB_INPUT() { PBREG->CRL=(PBREG->CRL &0xfffffff0)|DB_MODE_IN ; PBREG->CRH = 0x11111111*DB_MODE_IN; } #define SCSI_DB_INPUT() { PBREG->CRL=(PBREG->CRL &0xfffffff0)|DB_MODE_IN ; PBREG->CRH = (uint32_t)0x11111111*DB_MODE_IN; }
// HDDiamge file // HDDiamge file
#define HDIMG_ID_POS 2 // Position to embed ID number #define HDIMG_ID_POS 2 // Position to embed ID number
#define HDIMG_LUN_POS 3 // Position to embed LUN numbers #define HDIMG_LUN_POS 3 // Position to embed LUN numbers
#define HDIMG_BLK_POS 5 // Position to embed block size numbers #define HDIMG_BLK_POS 5 // Position to embed block size numbers
#define MAX_FILE_PATH 32 // Maximum file name length #define MAX_FILE_PATH 64 // Maximum file name length
#define MAX_MAC_PATH 32 // Maximum file name length on vintage macs
#define MAC_BLK_SIZE 4096
/* /*
* Data byte to BSRR register setting value and parity table * Data byte to BSRR register setting value and parity table
*/ */
// Parity bit generation // 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 // Data byte to BSRR register setting value conversion table
// BSRR[31:24] = DB[7:0] // BSRR[31:24] = DB[7:0]
@ -250,16 +290,9 @@ uint32_t db_bsrr[256];
// #define GET_CDB6_LBA(x) ((x[2] & 01f) << 16) | (x[3] << 8) | x[4] // #define GET_CDB6_LBA(x) ((x[2] & 01f) << 16) | (x[3] << 8) | x[4]
#define READ_DATA_BUS() (byte)((~(uint32_t)GPIOB->regs->IDR)>>8) #define READ_DATA_BUS() (byte)((~(uint32_t)GPIOB->regs->IDR)>>8)
enum SCSI_DEVICE_TYPE
{
SCSI_DEVICE_HDD,
SCSI_DEVICE_OPTICAL,
};
#define CDROM_RAW_SECTORSIZE 2352
#define CDROM_COMMON_SECTORSIZE 2048
struct SCSI_INQUIRY_DATA typedef struct _SCSI_INQUIRY_DATA
{ {
union union
{ {
@ -302,22 +335,37 @@ struct SCSI_INQUIRY_DATA
// raw bytes // raw bytes
byte raw[64]; byte raw[64];
}; };
}; } SCSI_INQUIRY_DATA;
// HDD image // HDD image
typedef __attribute__((aligned(4))) struct _SCSI_DEVICE typedef __attribute__((aligned(4))) struct _SCSI_DEVICE
{ {
FsFile *m_file; // File object FsFile m_file; // File object
uint64_t m_fileSize; // File size uint64_t m_fileSize; // File size
uint16_t m_blocksize; // SCSI BLOCK size uint16_t m_blocksize; // SCSI BLOCK size
uint8_t m_type; // SCSI device type uint16_t m_rawblocksize; // OPTICAL raw sector size
uint32_t m_blockcount; // blockcount uint8_t m_type; // SCSI device type
bool m_raw; // Raw disk uint32_t m_blockcount; // blockcount
SCSI_INQUIRY_DATA inquiry_block; // SCSI information SCSI_INQUIRY_DATA inquiry_block; // SCSI information
uint8_t m_senseKey; // Sense key uint8_t m_senseKey; // Sense key
uint16_t m_additional_sense_code; // ASC/ASCQ 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; } SCSI_DEVICE;
static byte cdb_len_lookup[] = {
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
10,10,10,10,10,10,10,10,10,10,10,10,10,16,16,16,16,16,16,16,16,
16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
16,16,16,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
12,12,12,12,12,12,12,12,12,12,12,12,12,12,10,10,10,10,10,10,10,
10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
10,10,10,10,10,10,10,10,10,10,10,10,10,10
};
#endif #endif

View File

@ -21,6 +21,7 @@
#define SCSI_RECV_DIAG_RESULTS 0x1C #define SCSI_RECV_DIAG_RESULTS 0x1C
#define SCSI_SEND_DIAG 0x1D #define SCSI_SEND_DIAG 0x1D
#define SCSI_PREVENT_ALLOW_REMOVAL 0x1E #define SCSI_PREVENT_ALLOW_REMOVAL 0x1E
#define SCSI_ICD_EXTENDED_CMD 0x1F
#define SCSI_READ_CAPACITY 0x25 #define SCSI_READ_CAPACITY 0x25
#define SCSI_READ10 0x28 #define SCSI_READ10 0x28
#define SCSI_WRITE10 0x2A #define SCSI_WRITE10 0x2A
@ -50,6 +51,14 @@
#define SCSI_READ12 0xA8 #define SCSI_READ12 0xA8
#define SCSI_VERIFY12 0xAF #define SCSI_VERIFY12 0xAF
#define BLUESCSI_LIST_FILES 0xD0
#define BLUESCSI_GET_FILE 0xD1
#define BLUESCSI_COUNT_FILES 0xD2
#define BLUESCSI_SEND_PREP 0xD3
#define BLUESCSI_SEND 0xD4
#define BLUESCSI_SEND_END 0xD5
#define SCSI_TOC_LENGTH 20 // length for default CDROM TOC #define SCSI_TOC_LENGTH 20 // length for default CDROM TOC

View File

@ -27,9 +27,13 @@
#define SCSI_ASC_WRITE_PROTECTED 0x2700 #define SCSI_ASC_WRITE_PROTECTED 0x2700
#define SCSI_ASC_CANNOT_READ_MEDIUM_UNKNOWN_FORMAT 0x3001 #define SCSI_ASC_CANNOT_READ_MEDIUM_UNKNOWN_FORMAT 0x3001
#define SCSI_ASC_CANNOT_READ_MEDIUM_INCOMPATIBLE_FORMAT 0x3002 #define SCSI_ASC_CANNOT_READ_MEDIUM_INCOMPATIBLE_FORMAT 0x3002
#define SCSI_ASC_SAVING_PARAMETERS_NOT_SUPPORTED 0x3900
#define SCSI_ASC_MEDIUM_NOT_PRESENT 0x3A00 #define SCSI_ASC_MEDIUM_NOT_PRESENT 0x3A00
#define SCSI_ASC_LUN_NOT_READY_MANUAL_INTERVENTION_REQUIRED 0x0403 #define SCSI_ASC_LUN_NOT_READY_MANUAL_INTERVENTION_REQUIRED 0x0403
// OpenRetroSCSI Vendor Sense
#define OPEN_RETRO_SCSI_TOO_MANY_FILES 0x0001
// SCSI mode page codes // SCSI mode page codes
#define SCSI_SENSE_MODE_VENDOR 0x00 #define SCSI_SENSE_MODE_VENDOR 0x00
@ -39,8 +43,12 @@
#define SCSI_SENSE_MODE_DISK_GEOMETRY 0x04 #define SCSI_SENSE_MODE_DISK_GEOMETRY 0x04
#define SCSI_SENSE_MODE_FLEXABLE_GEOMETRY 0x05 #define SCSI_SENSE_MODE_FLEXABLE_GEOMETRY 0x05
#define SCSI_SENSE_MODE_CACHING 0x08 #define SCSI_SENSE_MODE_CACHING 0x08
#define SCSI_SENSE_MODE_CDROM 0x0D
#define SCSI_SENSE_MODE_CDROM_AUDIO_CONTROL 0x0E
#define SCSI_SENSE_MODE_VENDOR_APPLE 0x30 #define SCSI_SENSE_MODE_VENDOR_APPLE 0x30
#define SCSI_SENSE_MODE_VENDOR_BLUESCSI 0x31 // Lookup range for vndr
#define SCSI_SENSE_MODE_ALL 0x3F #define SCSI_SENSE_MODE_ALL 0x3F