diff --git a/lib/SCSI2SD/src/firmware/bluescsi_toolbox.h b/lib/SCSI2SD/src/firmware/bluescsi_toolbox.h
new file mode 100644
index 00000000..95877bd1
--- /dev/null
+++ b/lib/SCSI2SD/src/firmware/bluescsi_toolbox.h
@@ -0,0 +1,25 @@
+/**
+ * Copyright (C) 2023 Eric Helgeson
+ *
+ * This file is part of BlueSCSI
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+**/
+
+#ifndef S2S_BLUESCSI_TOOLBOX_H
+#define S2S_BLUESCSI_TOOLBOX_H
+
+int scsiBlueSCSIToolboxCommand(void);
+
+#endif
diff --git a/lib/SCSI2SD/src/firmware/mode.c b/lib/SCSI2SD/src/firmware/mode.c
index 3ccca2af..78c05bf6 100755
--- a/lib/SCSI2SD/src/firmware/mode.c
+++ b/lib/SCSI2SD/src/firmware/mode.c
@@ -246,6 +246,14 @@ static const uint8_t AppleVendorPage[] =
'A','P','P','L','E',' ','C','O','M','P','U','T','E','R',',',' ','I','N','C',' ',' ',' '
};
+static const uint8_t BlueSCSIVendorPage[] =
+{
+0x31, // Page code
+42, // Page length
+'B','l','u','e','S','C','S','I',' ','i','s',' ','t','h','e',' ','B','E','S','T',' ',
+'S','T','O','L','E','N',' ','F','R','O','M',' ','B','L','U','E','S','C','S','I',0x00
+};
+
static void pageIn(int pc, int dataIdx, const uint8_t* pageData, int pageLen)
{
memcpy(&scsiDev.data[dataIdx], pageData, pageLen);
@@ -525,6 +533,13 @@ static void doModeSense(
idx += sizeof(AppleVendorPage);
}
+ if (pageCode == 0x31 || pageCode == 0x3F)
+ {
+ pageFound = 1;
+ pageIn(pc, idx, BlueSCSIVendorPage, sizeof(BlueSCSIVendorPage));
+ idx += sizeof(BlueSCSIVendorPage);
+ }
+
if (pageCode == 0x38) // Don't send unless requested
{
pageFound = 1;
diff --git a/lib/SCSI2SD/src/firmware/scsi.c b/lib/SCSI2SD/src/firmware/scsi.c
index 2e184fae..e378a81d 100755
--- a/lib/SCSI2SD/src/firmware/scsi.c
+++ b/lib/SCSI2SD/src/firmware/scsi.c
@@ -30,6 +30,7 @@
#include "tape.h"
#include "mo.h"
#include "vendor.h"
+#include "bluescsi_toolbox.h"
#include
@@ -587,6 +588,10 @@ static void process_Command()
{
// Already handled.
}
+ else if (scsiBlueSCSIToolboxCommand())
+ {
+ // handled
+ }
else if (scsiDiskCommand())
{
// Already handled.
diff --git a/lib/minIni/minGlue.h b/lib/minIni/minGlue.h
index d27d2fba..330e8743 100644
--- a/lib/minIni/minGlue.h
+++ b/lib/minIni/minGlue.h
@@ -2,7 +2,7 @@
#include
-#define INI_READONLY 1
+#define INI_OPENREWRITE 1
#define INI_FILETYPE FsFile
#define INI_FILEPOS fspos_t
@@ -11,3 +11,8 @@ bool ini_close(INI_FILETYPE *fp);
bool ini_read(char *buffer, int size, INI_FILETYPE *fp);
void ini_tell(INI_FILETYPE *fp, INI_FILEPOS *pos);
void ini_seek(INI_FILETYPE *fp, INI_FILEPOS *pos);
+
+bool ini_write(char *buffer, INI_FILETYPE *fp);
+bool ini_openwrite(const char *filename, INI_FILETYPE *fp);
+bool ini_openrewrite(const char *filename, INI_FILETYPE *fp);
+void ini_rename(const char *new_name, const char *old_name);
\ No newline at end of file
diff --git a/lib/minIni/minIni.cpp b/lib/minIni/minIni.cpp
index a80c5c76..ba1d0140 100644
--- a/lib/minIni/minIni.cpp
+++ b/lib/minIni/minIni.cpp
@@ -721,7 +721,7 @@ int ini_puts(const TCHAR *Section, const TCHAR *Key, const TCHAR *Value, const T
ini_tell(&rfp, &tail);
/* create new buffer (without writing it to file) */
writekey(LocalBuffer, Key, Value, NULL);
- if (_tcslen(LocalBuffer) == (size_t)(tail - head)) {
+ if (_tcslen(LocalBuffer) == (size_t)(tail.position - head.position)) {
/* length matches, close the file & re-open for read/write, then
* write at the correct position
*/
diff --git a/lib/minIni/minIni_cache.cpp b/lib/minIni/minIni_cache.cpp
index d549e4b3..6057c82d 100644
--- a/lib/minIni/minIni_cache.cpp
+++ b/lib/minIni/minIni_cache.cpp
@@ -71,6 +71,46 @@ bool ini_openread(const char *filename, INI_FILETYPE *fp)
return fp->open(SD.vol(), filename, O_RDONLY);
}
+// Open .ini file either from cache or from SD card
+bool ini_openwrite(const char *filename, INI_FILETYPE *fp)
+{
+#if INI_CACHE_SIZE > 0
+ if (g_ini_cache.valid &&
+ (filename == g_ini_cache.filename || strcmp(filename, g_ini_cache.filename) == 0))
+ {
+ fp->close();
+ g_ini_cache.fp = fp;
+ g_ini_cache.current_pos.position = 0;
+ return true;
+ }
+#endif
+
+ return fp->open(SD.vol(), filename, O_WRONLY);
+}
+
+// Open .ini file either from cache or from SD card
+bool ini_openrewrite(const char *filename, INI_FILETYPE *fp)
+{
+#if INI_CACHE_SIZE > 0
+ if (g_ini_cache.valid &&
+ (filename == g_ini_cache.filename || strcmp(filename, g_ini_cache.filename) == 0))
+ {
+ fp->close();
+ g_ini_cache.fp = fp;
+ g_ini_cache.current_pos.position = 0;
+ return true;
+ }
+#endif
+
+ return fp->open(SD.vol(), filename, O_RDWR);
+}
+
+void ini_rename(const char * old_name, const char *new_name)
+{
+ SD.rename(old_name, new_name);
+ invalidate_ini_cache();
+}
+
// Close previously opened file
bool ini_close(INI_FILETYPE *fp)
{
@@ -116,6 +156,18 @@ bool ini_read(char *buffer, int size, INI_FILETYPE *fp)
}
}
+// Write to the card and invalidate the cache.
+bool ini_write(char *buffer, INI_FILETYPE *fp)
+{
+ if(fp->write(buffer) > 0)
+ {
+ invalidate_ini_cache();
+ return true;
+ }
+ else
+ return false;
+}
+
// Get the position inside the file
void ini_tell(INI_FILETYPE *fp, INI_FILEPOS *pos)
{
diff --git a/src/BlueSCSI_Toolbox.cpp b/src/BlueSCSI_Toolbox.cpp
new file mode 100644
index 00000000..f5f64713
--- /dev/null
+++ b/src/BlueSCSI_Toolbox.cpp
@@ -0,0 +1,394 @@
+/**
+ * Copyright (C) 2023 Eric Helgeson
+ *
+ * This file is part of BlueSCSI
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+**/
+#include "BlueSCSI_Toolbox.h"
+#include "BlueSCSI_disk.h"
+#include "BlueSCSI_cdrom.h"
+#include "BlueSCSI_log.h"
+#include "BlueSCSI_config.h"
+#include
+#include
+extern "C" {
+#include
+#include
+#include
+}
+
+bool toolboxFilenameValid(const char* name)
+{
+ if(name[0] == '.')
+ {
+ debuglog("toolbox: Ignoring hidden file ", name);
+ return false;
+ }
+ if(strlen(name) == 0)
+ {
+ debuglog("toolbox: Ignoring filename empty file name");
+ return false;
+ }
+ const char *extension = strrchr(name, '.');
+ if (extension && strcasecmp(extension, ".cue") == 0)
+ {
+ debuglog("toolbox: Ignoring .cue ", name);
+ return false;
+ }
+
+ return true;
+}
+
+static void doCountFiles(const char * dir_name)
+{
+ FsFile dir;
+ FsFile file;
+ char name[MAX_FILE_PATH] = {0};
+ dir.open(dir_name);
+ dir.rewindDirectory();
+ uint8_t file_count = 0;
+ while (file.openNext(&dir, O_RDONLY))
+ {
+ if(file.getError() > 0)
+ {
+ file.close();
+ break;
+ }
+ file.getName(name, MAX_FILE_PATH);
+ file.close();
+ // only count valid files.
+ if(toolboxFilenameValid(name))
+ {
+ file_count = file_count + 1;
+ if(file_count > 100) {
+ scsiDev.status = CHECK_CONDITION;
+ scsiDev.target->sense.code = ILLEGAL_REQUEST;
+ scsiDev.target->sense.asc = OPEN_RETRO_SCSI_TOO_MANY_FILES;
+ scsiDev.phase = STATUS;
+ dir.close();
+ return;
+ }
+ }
+ }
+ scsiDev.data[0] = file_count;
+ scsiDev.dataLen = sizeof(file_count);
+ scsiDev.phase = DATA_IN;
+}
+
+void onListFiles(const char * dir_name) {
+ FsFile dir;
+ FsFile file;
+
+ memset(scsiDev.data, 0, 4096);
+ int ENTRY_SIZE = 40;
+ char name[MAX_FILE_PATH] = {0};
+ dir.open(dir_name);
+ dir.rewindDirectory();
+ uint8_t index = 0;
+ byte file_entry[40] = {0};
+ while (file.openNext(&dir, O_RDONLY))
+ {
+ uint8_t isDir = file.isDirectory() ? 0x00 : 0x01;
+ int len = file.getName(name, MAX_FILE_PATH);
+ if (len > MAX_MAC_PATH)
+ name[MAX_MAC_PATH] = 0x0;
+ uint64_t size = file.fileSize();
+ file.close();
+ if(!toolboxFilenameValid(name))
+ continue;
+ file_entry[0] = index;
+ file_entry[1] = isDir;
+ int c = 0; // Index of char in name[]
+
+ for(int i = 2; i < (MAX_MAC_PATH + 1 + 2); i++) { // bytes 2 - 34
+ file_entry[i] = name[c++];
+ }
+ file_entry[35] = 0; //(size >> 32) & 0xff;
+ file_entry[36] = (size >> 24) & 0xff;
+ file_entry[37] = (size >> 16) & 0xff;
+ file_entry[38] = (size >> 8) & 0xff;
+ file_entry[39] = (size) & 0xff;
+ memcpy(&(scsiDev.data[ENTRY_SIZE * index]), file_entry, ENTRY_SIZE);
+ index = index + 1;
+ }
+ dir.close();
+
+ scsiDev.dataLen = 4096;
+ scsiDev.phase = DATA_IN;
+}
+
+FsFile get_file_from_index(uint8_t index, const char * dir_name)
+{
+ FsFile dir;
+ FsFile file_test;
+ char name[MAX_FILE_PATH] = {0};
+
+ dir.open(dir_name);
+ dir.rewindDirectory(); // Back to the top
+ int count = 0;
+ while (file_test.openNext(&dir, O_RDONLY))
+ {
+ // If error there is no next file to open.
+ if(file_test.getError() > 0) {
+ file_test.close();
+ break;
+ }
+ file_test.getName(name, MAX_FILE_PATH);
+
+ if(!toolboxFilenameValid(name))
+ {
+ file_test.close();
+ continue;
+ }
+ if (count == index)
+ {
+ dir.close();
+ return file_test;
+ }
+ else
+ {
+ file_test.close();
+ }
+ count++;
+ }
+ file_test.close();
+ dir.close();
+ return file_test;
+}
+
+// Devices that are active on this SCSI device.
+void onListDevices()
+{
+ for (int i = 0; i < NUM_SCSIID; i++)
+ {
+ const S2S_TargetCfg* cfg = s2s_getConfigById(i);
+ if (cfg && (cfg->scsiId & S2S_CFG_TARGET_ENABLED))
+ {
+ scsiDev.data[i] = (int)cfg->deviceType; // 2 == cd
+ }
+ else
+ {
+ scsiDev.data[i] = 0xFF; // not enabled target.
+ }
+ }
+ scsiDev.dataLen = NUM_SCSIID;
+}
+
+void onSetNextCD(const char * img_dir)
+{
+ char name[MAX_FILE_PATH] = {0};
+ char full_path[MAX_FILE_PATH * 2] = {0};
+ uint8_t file_index = scsiDev.cdb[1];
+
+ image_config_t &img = *(image_config_t*)scsiDev.target->cfg;
+ FsFile next_cd = get_file_from_index(file_index, img_dir);
+ next_cd.getName(name, sizeof(name));
+ next_cd.close();
+ snprintf(full_path, (MAX_FILE_PATH * 2), "%s/%s", img_dir, name);
+ cdromSwitch(img, full_path);
+}
+
+FsFile gFile; // global so we can keep it open while transfering.
+void onGetFile10(char * dir_name) {
+ uint8_t index = scsiDev.cdb[1];
+
+ uint32_t offset = ((uint32_t)scsiDev.cdb[2] << 24) | ((uint32_t)scsiDev.cdb[3] << 16) | ((uint32_t)scsiDev.cdb[4] << 8) | scsiDev.cdb[5];
+
+ if (offset == 0) // first time, open the file.
+ {
+ gFile = get_file_from_index(index, dir_name);
+ if(!gFile.isDirectory() && !gFile.isReadable())
+ {
+ scsiDev.status = CHECK_CONDITION;
+ scsiDev.target->sense.code = ILLEGAL_REQUEST;
+ //SCSI_ASC_INVALID_FIELD_IN_CDB
+ scsiDev.phase = STATUS;
+ return;
+ }
+ }
+
+ uint32_t file_total = gFile.size();
+ memset(scsiDev.data, 0, 4096);
+ gFile.seekSet(offset * 4096);
+ int bytes_read = gFile.read(scsiDev.data, 4096);
+ if(offset * 4096 >= file_total) // transfer done, close.
+ {
+ gFile.close();
+ }
+ scsiDev.dataLen = bytes_read;
+ scsiDev.phase = DATA_IN;
+}
+
+/*
+ Prepares a file for receving. The file name is null terminated in the scsi data.
+*/
+void onSendFilePrep(char * dir_name)
+{
+ char file_name[32+1];
+ memset(file_name, '\0', 32+1);
+ scsiEnterPhase(DATA_OUT);
+ for (int i = 0; i < 32+1; ++i)
+ {
+ file_name[i] = scsiReadByte();
+ }
+ SD.chdir(dir_name);
+ gFile.open(file_name, FILE_WRITE);
+ SD.chdir("/");
+ if(gFile.isOpen() && gFile.isWritable())
+ {
+ gFile.rewind();
+ gFile.sync();
+ // do i need to manually set phase to status here?
+ return;
+ } else {
+ gFile.close();
+ scsiDev.status = CHECK_CONDITION;
+ scsiDev.target->sense.code = ILLEGAL_REQUEST;
+ //SCSI_ASC_INVALID_FIELD_IN_CDB
+ scsiDev.phase = STATUS;
+ }
+}
+
+void onSendFileEnd(void)
+{
+ gFile.sync();
+ gFile.close();
+ scsiDev.phase = STATUS;
+}
+
+void onSendFile10(void)
+{
+ if(!gFile.isOpen() || !gFile.isWritable())
+ {
+ scsiDev.status = CHECK_CONDITION;
+ scsiDev.target->sense.code = ILLEGAL_REQUEST;
+ //SCSI_ASC_INVALID_FIELD_IN_CDB
+ scsiDev.phase = STATUS;
+ }
+
+ // Number of bytes sent this request, 1..512.
+ uint16_t bytes_sent = ((uint16_t)scsiDev.cdb[1] << 8) | scsiDev.cdb[2];
+ // 512 byte offset of where to put these bytes.
+ uint32_t offset = ((uint32_t)scsiDev.cdb[3] << 16) | ((uint32_t)scsiDev.cdb[4] << 8) | scsiDev.cdb[5];
+ uint16_t buf_size = 512;
+ uint8_t buf[512];
+
+ // Check if last block of file, and not the only bock in file.
+ if(bytes_sent < buf_size)
+ {
+ buf_size = bytes_sent;
+ }
+
+ scsiEnterPhase(DATA_OUT);
+ scsiRead(buf, bytes_sent, NULL);
+ gFile.seekCur(offset * 512);
+ gFile.write(buf, buf_size);
+ if(gFile.getWriteError())
+ {
+ gFile.clearWriteError();
+ gFile.close();
+ scsiDev.status = CHECK_CONDITION;
+ scsiDev.target->sense.code = ILLEGAL_REQUEST;
+ }
+ //scsiDev.phase = STATUS;
+}
+void onToggleDebug()
+{
+ if(scsiDev.cdb[1] == 0) // 0 == Set Debug, 1 == Get Debug State
+ {
+ g_log_debug = scsiDev.cdb[2];
+ log("Set debug logs to: ", g_log_debug);
+ scsiDev.phase = STATUS;
+ }
+ else
+ {
+ log("Debug currently set to: ", g_log_debug);
+ scsiDev.data[0] = g_log_debug ? 0x1 : 0x0;
+ scsiDev.dataLen = 1;
+ scsiDev.phase = DATA_IN;
+ }
+}
+
+extern "C" int scsiBlueSCSIToolboxCommand()
+{
+ int commandHandled = 1;
+ image_config_t &img = *(image_config_t*)scsiDev.target->cfg;
+ uint8_t command = scsiDev.cdb[0];
+
+ if (unlikely(command == BLUESCSI_TOOLBOX_COUNT_FILES))
+ {
+ char img_dir[MAX_FILE_PATH];
+ getToolBoxSharedDir(img_dir);
+ doCountFiles(img_dir);
+ }
+ else if (unlikely(command == BLUESCSI_TOOLBOX_LIST_FILES))
+ {
+ char img_dir[MAX_FILE_PATH];
+ getToolBoxSharedDir(img_dir);
+ onListFiles(img_dir);
+ }
+ else if (unlikely(command == BLUESCSI_TOOLBOX_GET_FILE))
+ {
+ char img_dir[MAX_FILE_PATH];
+ getToolBoxSharedDir(img_dir);
+ onGetFile10(img_dir);
+ }
+ else if (unlikely(command == BLUESCSI_TOOLBOX_SEND_FILE_PREP))
+ {
+ char img_dir[MAX_FILE_PATH];
+ getToolBoxSharedDir(img_dir);
+ onSendFilePrep(img_dir);
+ }
+ else if (unlikely(command == BLUESCSI_TOOLBOX_SEND_FILE_10))
+ {
+ onSendFile10();
+ }
+ else if (unlikely(command == BLUESCSI_TOOLBOX_SEND_FILE_END))
+ {
+ onSendFileEnd();
+ }
+ else if(unlikely(command == BLUESCSI_TOOLBOX_TOGGLE_DEBUG))
+ {
+ onToggleDebug();
+ }
+ else if(unlikely(command == BLUESCSI_TOOLBOX_LIST_CDS))
+ {
+ char img_dir[4];
+ snprintf(img_dir, sizeof(img_dir), CD_IMG_DIR, (int)img.scsiId & S2S_CFG_TARGET_ID_BITS);
+ onListFiles(img_dir);
+ }
+ else if(unlikely(command == BLUESCSI_TOOLBOX_SET_NEXT_CD))
+ {
+ char img_dir[4];
+ snprintf(img_dir, sizeof(img_dir), CD_IMG_DIR, (int)img.scsiId & S2S_CFG_TARGET_ID_BITS);
+ onSetNextCD(img_dir);
+ }
+ else if(unlikely(command == BLUESCSI_TOOLBOX_LIST_DEVICES))
+ {
+ onListDevices();
+ }
+ else if (unlikely(command == BLUESCSI_TOOLBOX_COUNT_CDS))
+ {
+ char img_dir[4];
+ snprintf(img_dir, sizeof(img_dir), CD_IMG_DIR, (int)img.scsiId & S2S_CFG_TARGET_ID_BITS);
+ doCountFiles(img_dir);
+ }
+ else
+ {
+ commandHandled = 0;
+ }
+
+ return commandHandled;
+}
\ No newline at end of file
diff --git a/src/BlueSCSI_Toolbox.h b/src/BlueSCSI_Toolbox.h
new file mode 100644
index 00000000..a708f9da
--- /dev/null
+++ b/src/BlueSCSI_Toolbox.h
@@ -0,0 +1,36 @@
+/**
+ * Copyright (C) 2023 Eric Helgeson
+ *
+ * This file is part of BlueSCSI
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+**/
+
+#pragma once
+
+#define MAX_MAC_PATH 32
+#define CD_IMG_DIR "CD%d"
+
+#define BLUESCSI_TOOLBOX_COUNT_FILES 0xD2
+#define BLUESCSI_TOOLBOX_LIST_FILES 0xD0
+#define BLUESCSI_TOOLBOX_GET_FILE 0xD1
+#define BLUESCSI_TOOLBOX_SEND_FILE_PREP 0xD3
+#define BLUESCSI_TOOLBOX_SEND_FILE_10 0xD4
+#define BLUESCSI_TOOLBOX_SEND_FILE_END 0xD5
+#define BLUESCSI_TOOLBOX_TOGGLE_DEBUG 0xD6
+#define BLUESCSI_TOOLBOX_LIST_CDS 0xD7
+#define BLUESCSI_TOOLBOX_SET_NEXT_CD 0xD8
+#define BLUESCSI_TOOLBOX_LIST_DEVICES 0xD9
+#define BLUESCSI_TOOLBOX_COUNT_CDS 0xDA
+#define OPEN_RETRO_SCSI_TOO_MANY_FILES 0x0001
\ No newline at end of file
diff --git a/src/BlueSCSI_cdrom.cpp b/src/BlueSCSI_cdrom.cpp
index 69c332f2..b0cf40f2 100644
--- a/src/BlueSCSI_cdrom.cpp
+++ b/src/BlueSCSI_cdrom.cpp
@@ -1216,25 +1216,57 @@ bool cdromSwitchNextImage(image_config_t &img)
int target_idx = img.scsiId & S2S_CFG_TARGET_ID_BITS;
scsiDiskGetNextImageName(img, filename, sizeof(filename));
+ if (filename[0] != '\0')
+ {
#ifdef ENABLE_AUDIO_OUTPUT
// if in progress for this device, terminate audio playback immediately (Annex C)
audio_stop(target_idx);
// Reset position tracking for the new image
audio_get_status_code(target_idx); // trash audio status code
#endif
+ log("Switching to next CD-ROM image for ", target_idx, ": ", filename);
+ img.file.close();
+ bool status = scsiDiskOpenHDDImage(target_idx, filename, target_idx, 0,
+ getBlockSize(filename, target_idx, 2048));
+
+ if (status)
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// Check if we have multiple CD-ROM images to cycle when drive is ejected.
+bool cdromSwitch(image_config_t &img, const char* filename)
+{
+ // Check if we have a next image to load, so that drive is closed next time the host asks.
+ int target_idx = img.scsiId & S2S_CFG_TARGET_ID_BITS;
if (filename[0] != '\0')
{
- log("Switching to next CD-ROM image for SCSI ID: ", target_idx, ": ", filename);
+#ifdef ENABLE_AUDIO_OUTPUT
+ // if in progress for this device, terminate audio playback immediately (Annex C)
+ audio_stop(target_idx);
+ // Reset position tracking for the new image
+ audio_get_status_code(target_idx); // trash audio status code
+#endif
+ log("Switching to next CD-ROM image for ", target_idx, ": ", filename);
img.file.close();
- bool status = scsiDiskOpenHDDImage(target_idx, filename, target_idx, 0,
- getBlockSize(filename, target_idx, 2048));
+ bool status = scsiDiskOpenHDDImage(target_idx, filename, target_idx, 0, 2048);
if (status)
{
+ img.ejected = false;
+ img.cdrom_events = 2; // New media
return true;
}
}
+ else
+ {
+ log("Could not switch to CD-ROM image as provide filename was empty.");
+ }
return false;
}
diff --git a/src/BlueSCSI_cdrom.h b/src/BlueSCSI_cdrom.h
index 95499152..1d14711b 100644
--- a/src/BlueSCSI_cdrom.h
+++ b/src/BlueSCSI_cdrom.h
@@ -31,4 +31,7 @@ bool cdromValidateCueSheet(image_config_t &img);
// Audio playback status
// boolean flag is true if just basic mechanism status (playback true/false)
// is desired, or false if historical audio status codes should be returned
-void cdromGetAudioPlaybackStatus(uint8_t *status, uint32_t *current_lba, bool current_only);
\ No newline at end of file
+void cdromGetAudioPlaybackStatus(uint8_t *status, uint32_t *current_lba, bool current_only);
+
+// switch to a given filename for the cd.
+bool cdromSwitch(image_config_t &img, const char* filename);
\ No newline at end of file
diff --git a/src/BlueSCSI_config.cpp b/src/BlueSCSI_config.cpp
index bb7207a7..5853c577 100644
--- a/src/BlueSCSI_config.cpp
+++ b/src/BlueSCSI_config.cpp
@@ -61,4 +61,9 @@ int getImg(int scsiId, int img_index, char* filename)
int dirlen = ini_gets(section, key, "", filename, sizeof(filename), CONFIGFILE);
return dirlen;
+}
+
+int getToolBoxSharedDir(char * dir_name)
+{
+ return ini_gets("SCSI", "ToolBoxSharedDir", "/shared", dir_name, MAX_FILE_PATH, CONFIGFILE);
}
\ No newline at end of file
diff --git a/src/BlueSCSI_config.h b/src/BlueSCSI_config.h
index 01de02c2..d4b8f91c 100644
--- a/src/BlueSCSI_config.h
+++ b/src/BlueSCSI_config.h
@@ -84,4 +84,6 @@ int getBlockSize(char *filename, int scsiId, int default_size);
int getImgDir(int scsiId, char* dirname);
-int getImg(int scsiId, int img_index, char* filename);
\ No newline at end of file
+int getImg(int scsiId, int img_index, char* filename);
+
+int getToolBoxSharedDir(char * dir_name);
\ No newline at end of file
diff --git a/src/BlueSCSI_disk.cpp b/src/BlueSCSI_disk.cpp
index e59313f9..9708be35 100644
--- a/src/BlueSCSI_disk.cpp
+++ b/src/BlueSCSI_disk.cpp
@@ -506,7 +506,7 @@ bool scsiDiskFilenameValid(const char* name)
{
if (strcasecmp(extension, ignore_exts[i]) == 0)
{
- // ignore these without log message
+ debuglog("-- Ignoring file ", name);
return false;
}
}
diff --git a/src/BlueSCSI_log_trace.cpp b/src/BlueSCSI_log_trace.cpp
index 81a80e86..67df5da6 100644
--- a/src/BlueSCSI_log_trace.cpp
+++ b/src/BlueSCSI_log_trace.cpp
@@ -3,6 +3,7 @@
#include "BlueSCSI_log_trace.h"
#include "BlueSCSI_log.h"
#include
+#include "BlueSCSI_Toolbox.h"
extern "C" {
#include
@@ -78,6 +79,17 @@ static const char *getCommandName(uint8_t cmd)
case 0xA8: return "Read12";
case 0xC0: return "OMTI-5204 DefineFlexibleDiskFormat";
case 0xC2: return "OMTI-5204 AssignDiskParameters";
+ case BLUESCSI_TOOLBOX_COUNT_FILES: return "BLUESCSI_TOOLBOX_COUNT_FILES";
+ case BLUESCSI_TOOLBOX_LIST_FILES: return "BLUESCSI_TOOLBOX_LIST_FILES";
+ case BLUESCSI_TOOLBOX_GET_FILE: return "BLUESCSI_TOOLBOX_GET_FILE";
+ case BLUESCSI_TOOLBOX_SEND_FILE_PREP: return "BLUESCSI_TOOLBOX_SEND_FILE_PREP";
+ case BLUESCSI_TOOLBOX_SEND_FILE_10: return "BLUESCSI_TOOLBOX_SEND_FILE_10";
+ case BLUESCSI_TOOLBOX_SEND_FILE_END: return "BLUESCSI_TOOLBOX_SEND_FILE_END";
+ case BLUESCSI_TOOLBOX_TOGGLE_DEBUG: return "BLUESCSI_TOOLBOX_TOGGLE_DEBUG";
+ case BLUESCSI_TOOLBOX_LIST_CDS: return "BLUESCSI_TOOLBOX_LIST_CDS";
+ case BLUESCSI_TOOLBOX_SET_NEXT_CD: return "BLUESCSI_TOOLBOX_SET_NEXT_CD";
+ case BLUESCSI_TOOLBOX_LIST_DEVICES: return "BLUESCSI_TOOLBOX_LIST_DEVICES";
+ case BLUESCSI_TOOLBOX_COUNT_CDS: return "BLUESCSI_TOOLBOX_COUNT_CDS";
default: return "Unknown";
}
}
diff --git a/src/ImageBackingStore.cpp b/src/ImageBackingStore.cpp
index 02095b16..4ac2041c 100644
--- a/src/ImageBackingStore.cpp
+++ b/src/ImageBackingStore.cpp
@@ -304,6 +304,16 @@ void ImageBackingStore::flush()
}
}
+void ImageBackingStore::getName(char * name, size_t len)
+{
+ if(m_isrom)
+ name = (char*)"ROM:";
+ else if(m_israw)
+ name = (char*)"RAW:";
+ else
+ m_fsfile.getName(name, len);
+}
+
uint64_t ImageBackingStore::position()
{
if (!m_israw && !m_isrom)
diff --git a/src/ImageBackingStore.h b/src/ImageBackingStore.h
index 6724c7cb..41572992 100644
--- a/src/ImageBackingStore.h
+++ b/src/ImageBackingStore.h
@@ -74,6 +74,9 @@ class ImageBackingStore
// Flush any pending changes to filesystem
void flush();
+ // Get name of the fs_file
+ void getName(char *name, size_t len);
+
// Gets current position for following read/write operations
// Result is only valid for regular files, not raw or flash access
uint64_t position();