Compare commits

...

14 Commits

Author SHA1 Message Date
Tony Kuker b54e81886e
Merge afdd3c0ae2 into ea4dce02fb 2024-04-26 19:44:31 +03:00
Daniel Markstedt ea4dce02fb Nicer badges on README.md
Plus: Remove the badge for the Tindie store that is taking a break.
2024-04-23 08:01:24 +09:00
Daniel Markstedt 1919eb34bb Bump software copyright year to 2024 2024-04-23 08:00:58 +09:00
Daniel Markstedt a7538980d7 Bump to netatalk 2.3.2 2024-04-23 08:00:42 +09:00
Daniel Markstedt 85dc2cf0be
Bump Netatalk Webmin module to 1.3 (#1454) 2024-04-20 15:24:15 -07:00
Daniel Markstedt a6a8cadf21
Revert fixes for DEC vendor specific pages and CD-ROM block size changing (#1451)
* Revert "Don't ResizeCache on sector change if no filename is defined (#1438)"

This reverts commit dd9a3296d4.

* Revert "Add ModeSense page 0x25 (DEC special function control page) (#1412)"

This reverts commit 1121b8d9d6.

* Revert "DiskCache needs a size"

This reverts commit 7cc8df271c.

* Revert "Honor sector size change via ModeSelect6 in scsicd (#1406)"

This reverts commit b7f65d33e2.

* Revert "Multiple fixes for ModeSelect (#1405)"

This reverts commit ad5eae93e7.
2024-04-13 03:40:53 -07:00
dependabot[bot] 12bb86db9b Bump idna from 3.6 to 3.7 in /python/web
Bumps [idna](https://github.com/kjd/idna) from 3.6 to 3.7.
- [Release notes](https://github.com/kjd/idna/releases)
- [Changelog](https://github.com/kjd/idna/blob/master/HISTORY.rst)
- [Commits](https://github.com/kjd/idna/compare/v3.6...v3.7)

---
updated-dependencies:
- dependency-name: idna
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-13 09:47:25 +09:00
dependabot[bot] b348643ff3 Bump idna from 3.4 to 3.7 in /python/common
Bumps [idna](https://github.com/kjd/idna) from 3.4 to 3.7.
- [Release notes](https://github.com/kjd/idna/releases)
- [Changelog](https://github.com/kjd/idna/blob/master/HISTORY.rst)
- [Commits](https://github.com/kjd/idna/compare/v3.4...v3.7)

---
updated-dependencies:
- dependency-name: idna
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-12 12:59:49 +09:00
dependabot[bot] 396af80e62 Bump pillow from 10.2.0 to 10.3.0 in /python/oled
Bumps [pillow](https://github.com/python-pillow/Pillow) from 10.2.0 to 10.3.0.
- [Release notes](https://github.com/python-pillow/Pillow/releases)
- [Changelog](https://github.com/python-pillow/Pillow/blob/main/CHANGES.rst)
- [Commits](https://github.com/python-pillow/Pillow/compare/10.2.0...10.3.0)

---
updated-dependencies:
- dependency-name: pillow
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-05 13:01:10 +09:00
dependabot[bot] 99cb648c60 Bump pillow from 10.2.0 to 10.3.0 in /python/ctrlboard
Bumps [pillow](https://github.com/python-pillow/Pillow) from 10.2.0 to 10.3.0.
- [Release notes](https://github.com/python-pillow/Pillow/releases)
- [Changelog](https://github.com/python-pillow/Pillow/blob/main/CHANGES.rst)
- [Commits](https://github.com/python-pillow/Pillow/compare/10.2.0...10.3.0)

---
updated-dependencies:
- dependency-name: pillow
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-05 13:00:45 +09:00
Daniel Markstedt b1a3ffbc7d Python: bump flake8 to 7.0.0, while removing attrs, py and tomli 2024-03-22 22:42:23 +09:00
dependabot[bot] 52e4a92aec
Bump black from 22.8.0 to 24.3.0 in /python/web (#1444)
* Bump black from 22.8.0 to 24.3.0 in /python/web

Bumps [black](https://github.com/psf/black) from 22.8.0 to 24.3.0.
- [Release notes](https://github.com/psf/black/releases)
- [Changelog](https://github.com/psf/black/blob/main/CHANGES.md)
- [Commits](https://github.com/psf/black/compare/22.8.0...24.3.0)

---
updated-dependencies:
- dependency-name: black
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>

* Github CI: Backend web test runner use python 3.9.19

* Reformat python sources with black

* Docker: Bump to python 3.9-slim image for pytest

* Bump pytest version to 8.1.1

* Bump more library versions, and freeze them

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Daniel Markstedt <daniel@mindani.net>
2024-03-22 00:19:13 -07:00
Daniel Markstedt afdd3c0ae2 Another cache dir 2023-10-24 13:46:21 +00:00
Tony Kuker 6dbef076b1 #1149 cache pip packages to explicit directory 2023-10-23 21:16:22 +09:00
54 changed files with 101 additions and 197 deletions

View File

@ -32,7 +32,7 @@ jobs:
- uses: actions/setup-python@v4 - uses: actions/setup-python@v4
with: with:
python-version: 3.7.15 python-version: 3.9.19
cache: 'pip' cache: 'pip'
- run: pip install -r web/requirements-dev.txt - run: pip install -r web/requirements-dev.txt

View File

@ -1,9 +1,17 @@
# What is PiSCSI? # What is PiSCSI?
[![Build Status](https://github.com/PiSCSI/piscsi/actions/workflows/cpp.yml/badge.svg)](https://github.com/PiSCSI/piscsi/actions/workflows/cpp.yml)
[![Project releases](https://img.shields.io/github/release/PiSCSI/piscsi)](https://github.com/PiSCSI/piscsi/releases)
[![Project contributors](https://img.shields.io/github/contributors/PiSCSI/piscsi)](https://github.com/PiSCSI/piscsi/graphs/contributors)
[![License: BSD 3-Clause](https://img.shields.io/github/license/PiSCSI/piscsi)](https://github.com/PiSCSI/piscsi/blob/develop/LICENSE)
[<img src="https://sonarcloud.io/images/project_badges/sonarcloud-orange.svg" height="20" />](https://sonarcloud.io/summary/new_code?id=akuker-PISCSI)
PiSCSI is a virtual SCSI device emulator that runs on a Raspberry Pi. It runs in userspace, and can emulate several SCSI devices at one time. There is a control interface to attach / detach drives during runtime, as well as insert and eject removable media. This project is aimed at users of vintage Macintosh and Atari computers and more (see [compatibility list](https://github.com/PiSCSI/piscsi/wiki/Compatibility)) from the 1980's and 1990's. PiSCSI is a virtual SCSI device emulator that runs on a Raspberry Pi. It runs in userspace, and can emulate several SCSI devices at one time. There is a control interface to attach / detach drives during runtime, as well as insert and eject removable media. This project is aimed at users of vintage Macintosh and Atari computers and more (see [compatibility list](https://github.com/PiSCSI/piscsi/wiki/Compatibility)) from the 1980's and 1990's.
Please check out the full story with much more detail on the [wiki](https://github.com/PiSCSI/piscsi/wiki)! Please check out the full story with much more detail on the [wiki](https://github.com/PiSCSI/piscsi/wiki)!
# How do I contribute? # How do I contribute?
PiSCSI is using the <a href="https://datasift.github.io/gitflow/IntroducingGitFlow.html">Gitflow Workflow</a>. A quick overview: PiSCSI is using the <a href="https://datasift.github.io/gitflow/IntroducingGitFlow.html">Gitflow Workflow</a>. A quick overview:
- The *main* branch should always reflect the contents of the last stable release - The *main* branch should always reflect the contents of the last stable release
@ -17,9 +25,8 @@ When you are ready to contribute code to PiSCSI, follow the <a href="https://doc
If you want to add a new translation, or improve upon an existing one, please follow the <a href="https://github.com/PiSCSI/piscsi/tree/master/python/web#localizing-the-web-interface">instructions in the Web Interface README</a>. Once the translation is complete, please use the same workflow as above to contribute it to the project. If you want to add a new translation, or improve upon an existing one, please follow the <a href="https://github.com/PiSCSI/piscsi/tree/master/python/web#localizing-the-web-interface">instructions in the Web Interface README</a>. Once the translation is complete, please use the same workflow as above to contribute it to the project.
<a href="https://www.tindie.com/stores/landogriffin/?ref=offsite_badges&utm_source=sellers_akuker&utm_medium=badges&utm_campaign=badge_large"><img src="https://d2ss6ovg47m0r5.cloudfront.net/badges/tindie-larges.png" alt="I sell on Tindie" width="200" height="104"></a>[![SonarCloud](https://sonarcloud.io/images/project_badges/sonarcloud-orange.svg)](https://sonarcloud.io/summary/new_code?id=akuker_PISCSI)
# GitHub Sponsors # GitHub Sponsors
Thank you to all of the GitHub sponsors who support the development community! Thank you to all of the GitHub sponsors who support the development community!
Special thank you to the Gold level sponsors! Special thank you to the Gold level sponsors!

View File

@ -696,17 +696,11 @@ uint32_t Disk::GetSectorSizeInBytes() const
void Disk::SetSectorSizeInBytes(uint32_t size_in_bytes) void Disk::SetSectorSizeInBytes(uint32_t size_in_bytes)
{ {
if (!GetSupportedSectorSizes().contains(size_in_bytes)) { if (!GetSupportedSectorSizes().contains(size_in_bytes)) {
throw io_exception("Invalid sector size of " + to_string(size_in_bytes) + " byte(s)"); throw io_exception("Invalid sector size of " + to_string(size_in_bytes) + " byte(s)");
} }
uint64_t current_blocks = GetBlockCount();
uint32_t current_size_shift_count = size_shift_count;
uint64_t current_size = current_blocks << current_size_shift_count;
size_shift_count = CalculateShiftCount(size_in_bytes); size_shift_count = CalculateShiftCount(size_in_bytes);
assert(size_shift_count); assert(size_shift_count);
if ((current_blocks > 0) && (current_size_shift_count > 0)) {
SetBlockCount(current_size >> size_shift_count);
}
} }
uint32_t Disk::GetConfiguredSectorSize() const uint32_t Disk::GetConfiguredSectorSize() const
@ -720,7 +714,7 @@ bool Disk::SetConfiguredSectorSize(uint32_t configured_size)
return false; return false;
} }
configured_sector_size = configured_size; configured_sector_size = configured_size;
return true; return true;
} }

View File

@ -112,7 +112,7 @@ protected:
void SetUpCache(off_t, bool = false); void SetUpCache(off_t, bool = false);
void ResizeCache(const string&, bool); void ResizeCache(const string&, bool);
bool GetRawMode() const { return (cache?cache->GetRawMode():false); }
void SetUpModePages(map<int, vector<byte>>&, int, bool) const override; void SetUpModePages(map<int, vector<byte>>&, int, bool) const override;
void AddErrorPage(map<int, vector<byte>>&, bool) const; void AddErrorPage(map<int, vector<byte>>&, bool) const;
virtual void AddFormatPage(map<int, vector<byte>>&, bool) const; virtual void AddFormatPage(map<int, vector<byte>>&, bool) const;

View File

@ -51,7 +51,6 @@ public:
~DiskCache() = default; ~DiskCache() = default;
void SetRawMode(bool b) { cd_raw = b; } // CD-ROM raw mode setting void SetRawMode(bool b) { cd_raw = b; } // CD-ROM raw mode setting
bool GetRawMode() const { return cd_raw; }
bool Save(); // Save and release all bool Save(); // Save and release all
bool ReadSector(span<uint8_t>, uint32_t); // Sector Read bool ReadSector(span<uint8_t>, uint32_t); // Sector Read

View File

@ -114,7 +114,7 @@ void ModePageDevice::ModeSense10() const
EnterDataInPhase(); EnterDataInPhase();
} }
void ModePageDevice::ModeSelect(scsi_command, cdb_t, span<const uint8_t>, int) void ModePageDevice::ModeSelect(scsi_command, cdb_t, span<const uint8_t>, int) const
{ {
// There is no default implementation of MODE SELECT // There is no default implementation of MODE SELECT
throw scsi_exception(sense_key::illegal_request, asc::invalid_command_operation_code); throw scsi_exception(sense_key::illegal_request, asc::invalid_command_operation_code);

View File

@ -23,7 +23,7 @@ public:
bool Init(const param_map&) override; bool Init(const param_map&) override;
virtual void ModeSelect(scsi_defs::scsi_command, cdb_t, span<const uint8_t>, int); virtual void ModeSelect(scsi_defs::scsi_command, cdb_t, span<const uint8_t>, int) const;
protected: protected:

View File

@ -40,8 +40,7 @@ string scsi_command_util::ModeSelect(scsi_command cmd, cdb_t cdb, span<const uin
} }
length -= offset; length -= offset;
// treat zero length as valid bool has_valid_page_code = false;
bool has_valid_page_code = (length == 0);
// Parse the pages // Parse the pages
while (length > 0) { while (length > 0) {
@ -63,10 +62,6 @@ string scsi_command_util::ModeSelect(scsi_command cmd, cdb_t cdb, span<const uin
has_valid_page_code = true; has_valid_page_code = true;
} }
else if (page == 0x01) {
// OpenVMS Alpha 7.3 uses this
has_valid_page_code = true;
}
else { else {
stringstream s; stringstream s;
s << "Unknown MODE SELECT page code: $" << setfill('0') << setw(2) << hex << page; s << "Unknown MODE SELECT page code: $" << setfill('0') << setw(2) << hex << page;
@ -76,7 +71,7 @@ string scsi_command_util::ModeSelect(scsi_command cmd, cdb_t cdb, span<const uin
// Advance to the next page // Advance to the next page
const int size = buf[offset + 1] + 2; const int size = buf[offset + 1] + 2;
length -= size + 1; length -= size;
offset += size; offset += size;
} }

View File

@ -165,33 +165,6 @@ vector<uint8_t> SCSICD::InquiryInternal() const
return HandleInquiry(device_type::cd_rom, scsi_level, true); return HandleInquiry(device_type::cd_rom, scsi_level, true);
} }
void SCSICD::ModeSelect(scsi_command cmd, cdb_t cdb, span<const uint8_t> buf, int length)
{
int sector_size = 1 << GetSectorSizeShiftCount();
int wanted_sector_size;
// skip Block Descriptor
int offset = 4;
// evaluate Mode Parameter Block Descriptor, sector size
wanted_sector_size = scsi_command_util::GetInt16(buf, offset + 6);
if (wanted_sector_size != sector_size) {
LogDebug("Changing sector size from " + to_string(sector_size) + " to " + to_string(wanted_sector_size));
SetSectorSizeInBytes(wanted_sector_size);
ClearTrack();
CreateDataTrack();
FlushCache();
string filename;
if ((filename = GetFilename()) != "") {
// DiskCache fails without a file to compute the cache size
ResizeCache(filename, GetRawMode());
}
}
if (const string result = scsi_command_util::ModeSelect(cmd, cdb, buf, length, sector_size);
!result.empty()) {
LogWarn(result);
}
}
void SCSICD::SetUpModePages(map<int, vector<byte>>& pages, int page, bool changeable) const void SCSICD::SetUpModePages(map<int, vector<byte>>& pages, int page, bool changeable) const
{ {
Disk::SetUpModePages(pages, page, changeable); Disk::SetUpModePages(pages, page, changeable);

View File

@ -34,7 +34,6 @@ public:
vector<uint8_t> InquiryInternal() const override; vector<uint8_t> InquiryInternal() const override;
int Read(span<uint8_t>, uint64_t) override; int Read(span<uint8_t>, uint64_t) override;
void ModeSelect(scsi_defs::scsi_command, cdb_t, span<const uint8_t>, int) override;
protected: protected:

View File

@ -82,7 +82,7 @@ vector<uint8_t> SCSIHD::InquiryInternal() const
return HandleInquiry(device_type::direct_access, scsi_level, IsRemovable()); return HandleInquiry(device_type::direct_access, scsi_level, IsRemovable());
} }
void SCSIHD::ModeSelect(scsi_command cmd, cdb_t cdb, span<const uint8_t> buf, int length) void SCSIHD::ModeSelect(scsi_command cmd, cdb_t cdb, span<const uint8_t> buf, int length) const
{ {
if (const string result = scsi_command_util::ModeSelect(cmd, cdb, buf, length, 1 << GetSectorSizeShiftCount()); if (const string result = scsi_command_util::ModeSelect(cmd, cdb, buf, length, 1 << GetSectorSizeShiftCount());
!result.empty()) { !result.empty()) {
@ -97,32 +97,8 @@ void SCSIHD::AddFormatPage(map<int, vector<byte>>& pages, bool changeable) const
EnrichFormatPage(pages, changeable, 1 << GetSectorSizeShiftCount()); EnrichFormatPage(pages, changeable, 1 << GetSectorSizeShiftCount());
} }
// Page code 37 (25h) - DEC Special Function Control page
void SCSIHD::AddDECSpecialFunctionControlPage(map<int, vector<byte>>& pages, bool changeable) const
{
vector<byte> buf(25);
// No changeable area
if (changeable) {
pages[0x25] = buf;
return;
}
buf[0] = static_cast<byte> (0x25 | 0x80); // page code, high bit set
buf[1] = static_cast<byte> (sizeof(buf) - 1);
buf[2] = static_cast<byte> (0x01); // drive does not auto-start
pages[0x25] = buf;
}
void SCSIHD::AddVendorPage(map<int, vector<byte>>& pages, int page, bool changeable) const void SCSIHD::AddVendorPage(map<int, vector<byte>>& pages, int page, bool changeable) const
{ {
// Page code 0x25: DEC Special Function Control page
if (page == 0x25 || page == 0x3f) {
AddDECSpecialFunctionControlPage(pages, changeable);
}
// Page code 48 // Page code 48
if (page == 0x30 || page == 0x3f) { if (page == 0x30 || page == 0x3f) {
AddAppleVendorModePage(pages, changeable); AddAppleVendorModePage(pages, changeable);

View File

@ -37,10 +37,9 @@ public:
// Commands // Commands
vector<uint8_t> InquiryInternal() const override; vector<uint8_t> InquiryInternal() const override;
void ModeSelect(scsi_defs::scsi_command, cdb_t, span<const uint8_t>, int) override; void ModeSelect(scsi_defs::scsi_command, cdb_t, span<const uint8_t>, int) const override;
void AddFormatPage(map<int, vector<byte>>&, bool) const override; void AddFormatPage(map<int, vector<byte>>&, bool) const override;
void AddDECSpecialFunctionControlPage(map<int, vector<byte>>&, bool) const;
void AddVendorPage(map<int, vector<byte>>&, int, bool) const override; void AddVendorPage(map<int, vector<byte>>&, int, bool) const override;
private: private:

View File

@ -88,7 +88,7 @@ void SCSIMO::AddOptionPage(map<int, vector<byte>>& pages, bool) const
// Do not report update blocks // Do not report update blocks
} }
void SCSIMO::ModeSelect(scsi_command cmd, cdb_t cdb, span<const uint8_t> buf, int length) void SCSIMO::ModeSelect(scsi_command cmd, cdb_t cdb, span<const uint8_t> buf, int length) const
{ {
if (const string result = scsi_command_util::ModeSelect(cmd, cdb, buf, length, 1 << GetSectorSizeShiftCount()); if (const string result = scsi_command_util::ModeSelect(cmd, cdb, buf, length, 1 << GetSectorSizeShiftCount());
!result.empty()) { !result.empty()) {

View File

@ -32,7 +32,7 @@ public:
void Open() override; void Open() override;
vector<uint8_t> InquiryInternal() const override; vector<uint8_t> InquiryInternal() const override;
void ModeSelect(scsi_defs::scsi_command, cdb_t, span<const uint8_t>, int) override; void ModeSelect(scsi_defs::scsi_command, cdb_t, span<const uint8_t>, int) const override;
protected: protected:

View File

@ -112,7 +112,7 @@ string piscsi_util::Banner(string_view app)
s << "Version " << piscsi_get_version_string() << " (" << __DATE__ << ' ' << __TIME__ << ")\n"; s << "Version " << piscsi_get_version_string() << " (" << __DATE__ << ' ' << __TIME__ << ")\n";
s << "Powered by XM6 TypeG Technology / "; s << "Powered by XM6 TypeG Technology / ";
s << "Copyright (C) 2016-2020 GIMONS\n"; s << "Copyright (C) 2016-2020 GIMONS\n";
s << "Copyright (C) 2020-2023 Contributors to the PiSCSI project\n"; s << "Copyright (C) 2020-2024 Contributors to the PiSCSI project\n";
return s.str(); return s.str();
} }

View File

@ -360,7 +360,6 @@ class MockSCSIHD : public SCSIHD //NOSONAR Ignore inheritance hierarchy depth in
FRIEND_TEST(ScsiHdTest, FinalizeSetup); FRIEND_TEST(ScsiHdTest, FinalizeSetup);
FRIEND_TEST(ScsiHdTest, GetProductData); FRIEND_TEST(ScsiHdTest, GetProductData);
FRIEND_TEST(ScsiHdTest, SetUpModePages); FRIEND_TEST(ScsiHdTest, SetUpModePages);
FRIEND_TEST(ScsiHdTest, DECSpecialFunctionControlPage);
FRIEND_TEST(ScsiHdTest, GetSectorSizes); FRIEND_TEST(ScsiHdTest, GetSectorSizes);
FRIEND_TEST(ScsiHdTest, ModeSelect); FRIEND_TEST(ScsiHdTest, ModeSelect);
FRIEND_TEST(PiscsiExecutorTest, SetSectorSize); FRIEND_TEST(PiscsiExecutorTest, SetSectorSize);
@ -388,7 +387,6 @@ class MockSCSICD : public SCSICD //NOSONAR Ignore inheritance hierarchy depth in
FRIEND_TEST(ScsiCdTest, GetSectorSizes); FRIEND_TEST(ScsiCdTest, GetSectorSizes);
FRIEND_TEST(ScsiCdTest, SetUpModePages); FRIEND_TEST(ScsiCdTest, SetUpModePages);
FRIEND_TEST(ScsiCdTest, ReadToc); FRIEND_TEST(ScsiCdTest, ReadToc);
FRIEND_TEST(ScsiCdTest, ModeSelect);
using SCSICD::SCSICD; using SCSICD::SCSICD;
}; };

View File

@ -46,11 +46,6 @@ TEST(ScsiCommandUtilTest, ModeSelect6)
Property(&scsi_exception::get_asc, asc::invalid_field_in_parameter_list)))) Property(&scsi_exception::get_asc, asc::invalid_field_in_parameter_list))))
<< "Unsupported page 0 was not rejected"; << "Unsupported page 0 was not rejected";
// Page 1
buf[12] = 0x01;
EXPECT_NO_THROW(ModeSelect(scsi_command::eCmdModeSelect6, cdb, buf, LENGTH, 512))
<< "Page 1 is supported";
// Page 3 (Format Device Page) // Page 3 (Format Device Page)
buf[12] = 0x03; buf[12] = 0x03;
EXPECT_THAT([&] { ModeSelect(scsi_command::eCmdModeSelect6, cdb, buf, LENGTH, 512); }, EXPECT_THAT([&] { ModeSelect(scsi_command::eCmdModeSelect6, cdb, buf, LENGTH, 512); },
@ -67,25 +62,7 @@ TEST(ScsiCommandUtilTest, ModeSelect6)
Property(&scsi_exception::get_asc, asc::invalid_field_in_parameter_list)))) Property(&scsi_exception::get_asc, asc::invalid_field_in_parameter_list))))
<< "Not enough command parameters"; << "Not enough command parameters";
// check length computation EXPECT_FALSE(ModeSelect(scsi_command::eCmdModeSelect6, cdb, buf, LENGTH, 512).empty());
buf[3] = 8;
buf[10] = 2;
buf[12] = 1;
buf[13] = 10;
buf[14] = 0x24;
buf[24] = 0;
EXPECT_NO_THROW(ModeSelect(scsi_command::eCmdModeSelect6, cdb, buf, LENGTH, 512))
<< "Multi-page length computation";
// check length computation
buf[3] = 8;
buf[10] = 12;
buf[12] = 0;
buf[13] = 0;
buf[14] = 0;
buf[24] = 0;
EXPECT_NO_THROW(ModeSelect(scsi_command::eCmdModeSelect6, cdb, buf, 12, 512))
<< "Empty ModeSelect6";
} }
TEST(ScsiCommandUtilTest, ModeSelect10) TEST(ScsiCommandUtilTest, ModeSelect10)
@ -134,6 +111,8 @@ TEST(ScsiCommandUtilTest, ModeSelect10)
Property(&scsi_exception::get_sense_key, sense_key::illegal_request), Property(&scsi_exception::get_sense_key, sense_key::illegal_request),
Property(&scsi_exception::get_asc, asc::invalid_field_in_parameter_list)))) Property(&scsi_exception::get_asc, asc::invalid_field_in_parameter_list))))
<< "Not enough command parameters"; << "Not enough command parameters";
EXPECT_FALSE(ModeSelect(scsi_command::eCmdModeSelect10, cdb, buf, LENGTH, 512).empty());
} }
TEST(ScsiCommandUtilTest, EnrichFormatPage) TEST(ScsiCommandUtilTest, EnrichFormatPage)

View File

@ -133,56 +133,3 @@ TEST(ScsiCdTest, ReadToc)
// Further testing requires filesystem access // Further testing requires filesystem access
} }
TEST(ScsiCdTest, ModeSelect)
{
MockSCSICD cd(0);
MockSCSICD cd1(0);
vector<int> cmd(6);
vector<uint8_t> buf(255);
// dummy file for DiskCache resize after sector size change
path filename = CreateTempFile(2* 2048);
cd.SetFilename(string(filename));
cd.Open();
EXPECT_EQ(2, cd.GetBlockCount());
cd.SetSectorSizeInBytes(2048);
// PF
cmd[1] = 0x10;
// Length
buf[3] = 0x08;
// 2048 bytes per sector
buf[10] = 0x08;
// Page 3 (Device Format Page)
buf[12] = 0x01;
EXPECT_NO_THROW(cd.ModeSelect(scsi_command::eCmdModeSelect6, cmd, buf, 255)) << "MODE SELECT(6) with sector size 2048 is supported";
// 512 bytes per sector - ModeSelect6
buf[10] = 0x02;
EXPECT_NO_THROW(cd.ModeSelect(scsi_command::eCmdModeSelect6, cmd, buf, 255)) << "MODE SELECT(6) with sector size 512 is supported";
// 2048 bytes per sector - ModeSelect6
buf[10] = 0x08;
EXPECT_NO_THROW(cd.ModeSelect(scsi_command::eCmdModeSelect6, cmd, buf, 255)) << "MODE SELECT(6) with sector size 2048 is supported";
// 512 bytes per sector - ModeSelect10
buf[10] = 0x02;
EXPECT_NO_THROW(cd.ModeSelect(scsi_command::eCmdModeSelect10, cmd, buf, 255)) << "MODE SELECT(10) with sector size 512 is supported";
// unsupported sector size - ModeSelect6
buf[10] = 0x04;
EXPECT_THROW(cd.ModeSelect(scsi_command::eCmdModeSelect6, cmd, buf, 255), io_exception) << "MODE SELECT(6) with sector size 1024 is unsupported";
// sector size not multiple of 512 - ModeSelect6
buf[10] = 0x03;
EXPECT_THROW(cd.ModeSelect(scsi_command::eCmdModeSelect6, cmd, buf, 255), io_exception) << "MODE SELECT(6) with sector size 768 is unsupported";
// cd1 has no dummy file attached, simulating an empty CD drive
cd1.SetSectorSizeInBytes(2048);
// 512 bytes per sector - ModeSelect6
buf[10] = 0x02;
EXPECT_NO_THROW(cd1.ModeSelect(scsi_command::eCmdModeSelect6, cmd, buf, 255)) << "MODE SELECT(6), emtpy drive, with sector size 512 is supported";
}

View File

@ -18,12 +18,11 @@ using namespace filesystem;
void ScsiHdNecTest_SetUpModePages(map<int, vector<byte>>& pages) void ScsiHdNecTest_SetUpModePages(map<int, vector<byte>>& pages)
{ {
EXPECT_EQ(6, pages.size()) << "Unexpected number of mode pages"; EXPECT_EQ(5, pages.size()) << "Unexpected number of mode pages";
EXPECT_EQ(12, pages[1].size()); EXPECT_EQ(12, pages[1].size());
EXPECT_EQ(24, pages[3].size()); EXPECT_EQ(24, pages[3].size());
EXPECT_EQ(20, pages[4].size()); EXPECT_EQ(20, pages[4].size());
EXPECT_EQ(12, pages[8].size()); EXPECT_EQ(12, pages[8].size());
EXPECT_EQ(25, pages[37].size());
EXPECT_EQ(30, pages[48].size()); EXPECT_EQ(30, pages[48].size());
} }

View File

@ -13,12 +13,11 @@
void ScsiHdTest_SetUpModePages(map<int, vector<byte>>& pages) void ScsiHdTest_SetUpModePages(map<int, vector<byte>>& pages)
{ {
EXPECT_EQ(6, pages.size()) << "Unexpected number of mode pages"; EXPECT_EQ(5, pages.size()) << "Unexpected number of mode pages";
EXPECT_EQ(12, pages[1].size()); EXPECT_EQ(12, pages[1].size());
EXPECT_EQ(24, pages[3].size()); EXPECT_EQ(24, pages[3].size());
EXPECT_EQ(24, pages[4].size()); EXPECT_EQ(24, pages[4].size());
EXPECT_EQ(12, pages[8].size()); EXPECT_EQ(12, pages[8].size());
EXPECT_EQ(25, pages[37].size());
EXPECT_EQ(30, pages[48].size()); EXPECT_EQ(30, pages[48].size());
} }
@ -102,20 +101,6 @@ TEST(ScsiHdTest, SetUpModePages)
ScsiHdTest_SetUpModePages(pages); ScsiHdTest_SetUpModePages(pages);
} }
TEST(ScsiHdTest, DECSpecialFunctionControlPage)
{
map<int, vector<byte>> pages;
vector<byte> buf;
MockSCSIHD hd(0, false);
EXPECT_NO_THROW(hd.SetUpModePages(pages, 0x25, false)) << "MODE SENSE(6) DEC unique page is supported";
EXPECT_NE(pages.end(), pages.find(0x25));
buf = pages[0x25];
EXPECT_EQ(static_cast<byte> (0x25 | 0x80), buf[0]);
EXPECT_EQ(static_cast<byte> (0x17), buf[1]);
EXPECT_EQ(static_cast<byte> (0x01), buf[2]);
}
TEST(ScsiHdTest, ModeSelect) TEST(ScsiHdTest, ModeSelect)
{ {
MockSCSIHD hd({ 512 }); MockSCSIHD hd({ 512 });

View File

@ -1,4 +1,4 @@
FROM python:3.7-slim FROM python:3.9-slim
ENV DOCKER=1 ENV DOCKER=1
WORKDIR /src WORKDIR /src

View File

@ -161,9 +161,18 @@ function installPackagesWeb() {
# cache the pip packages # cache the pip packages
function cachePipPackages(){ function cachePipPackages(){
pushd $WEB_INSTALL_PATH CACHEDIR="$HOME/.cache/piscsi"
sudo pip3 install -r ./requirements.txt mkdir -p "$CACHEDIR" || exit 1
popd # Note: these need to be installed in source form ONLY. If the binary packages are installed, the architecture
# is selected based upon the building host architecture, not the target architecture. (so, if you're building
# a PiSCSI image on x86, pip will download x86 binaries, which aren't usefull on a Raspberry Pi
python3 -m pip download --no-binary :all: --destination-directory "$CACHEDIR" setuptools
python3 -m pip download --no-binary :all: --destination-directory "$CACHEDIR" wheel
python3 -m pip download --no-binary :all: --destination-directory "$CACHEDIR" flit_core
python3 -m pip download --no-binary :all: --destination-directory "$CACHEDIR" -r $WEB_INSTALL_PATH/requirements.txt
python3 -m pip download --no-binary :all: --destination-directory "$CACHEDIR" -r $CTRLBOARD_INSTALL_PATH/requirements.txt
# TODO: The OLED requirements.txt includes a circuit python package that doesn't work with non-binary
# pip3 download
} }
# compile the PiSCSI binaries # compile the PiSCSI binaries
@ -772,7 +781,7 @@ function createFileSharingDir() {
# Downloads, compiles, and installs Netatalk (AppleShare server) # Downloads, compiles, and installs Netatalk (AppleShare server)
function installNetatalk() { function installNetatalk() {
NETATALK_VERSION="2.3.1" NETATALK_VERSION="2.3.2"
NETATALK_CONFIG_PATH="/etc/netatalk" NETATALK_CONFIG_PATH="/etc/netatalk"
NETATALK_OPTIONS="--base-dir=$BASE/tmp/netatalk-$NETATALK_VERSION --cores=$CORES --share-name='$FILE_SHARE_NAME' --share-path='$FILE_SHARE_PATH'" NETATALK_OPTIONS="--base-dir=$BASE/tmp/netatalk-$NETATALK_VERSION --cores=$CORES --share-name='$FILE_SHARE_NAME' --share-path='$FILE_SHARE_PATH'"
@ -951,7 +960,7 @@ function installSamba() {
function installWebmin() { function installWebmin() {
WEBMIN_PATH="/usr/share/webmin" WEBMIN_PATH="/usr/share/webmin"
WEBMIN_NETATALK_MODULE_CONFIG="/etc/webmin/netatalk2/config" WEBMIN_NETATALK_MODULE_CONFIG="/etc/webmin/netatalk2/config"
WEBMIN_NETATALK_MODULE_VERSION="1.2" WEBMIN_NETATALK_MODULE_VERSION="1.3"
WEBMIN_VSFTPD_MODULE_VERSION="2024-01-26" WEBMIN_VSFTPD_MODULE_VERSION="2024-01-26"
if [ -d "$WEBMIN_PATH" ]; then if [ -d "$WEBMIN_PATH" ]; then

View File

@ -1,6 +1,6 @@
certifi==2023.7.22 certifi==2023.7.22
charset-normalizer==3.3.2 charset-normalizer==3.3.2
idna==3.4 idna==3.7
protobuf==3.19.5 protobuf==3.19.5
requests==2.31.0 requests==2.31.0
urllib3==2.0.7 urllib3==2.0.7

View File

@ -85,9 +85,9 @@ class PiscsiCmds:
if PurePath(member["path"]).suffix.lower()[1:] == PROPERTIES_SUFFIX: if PurePath(member["path"]).suffix.lower()[1:] == PROPERTIES_SUFFIX:
member["is_properties_file"] = True member["is_properties_file"] = True
elif f"{member['path']}.{PROPERTIES_SUFFIX}" in properties_files: elif f"{member['path']}.{PROPERTIES_SUFFIX}" in properties_files:
member[ member["related_properties_file"] = (
"related_properties_file" f"{member['path']}.{PROPERTIES_SUFFIX}"
] = f"{member['path']}.{PROPERTIES_SUFFIX}" )
archive_contents.append(member) archive_contents.append(member)
except (unarchiver.LsarCommandError, unarchiver.LsarOutputError): except (unarchiver.LsarCommandError, unarchiver.LsarOutputError):

View File

@ -1,6 +1,7 @@
""" """
Module with methods that interact with the Pi system Module with methods that interact with the Pi system
""" """
import subprocess import subprocess
import logging import logging
import sys import sys

View File

@ -1,6 +1,6 @@
luma.core==2.4.1 luma.core==2.4.1
luma.oled==3.8.1 luma.oled==3.8.1
Pillow==10.2.0 Pillow==10.3.0
protobuf==3.19.5 protobuf==3.19.5
pyftdi==0.55.0 pyftdi==0.55.0
pyserial==3.5 pyserial==3.5

View File

@ -1,6 +1,7 @@
""" """
Module for central PiSCSI control board configuration parameters Module for central PiSCSI control board configuration parameters
""" """
from ctrlboard_hw.ctrlboard_hw_constants import CtrlBoardHardwareConstants from ctrlboard_hw.ctrlboard_hw_constants import CtrlBoardHardwareConstants

View File

@ -1,4 +1,5 @@
"""Module for interfacing between the menu controller and the PiSCSI Control Board hardware""" """Module for interfacing between the menu controller and the PiSCSI Control Board hardware"""
import logging import logging
from typing import Optional from typing import Optional

View File

@ -1,4 +1,5 @@
"""Module for test printing events when buttons from the PiSCSI Control Board are pressed""" """Module for test printing events when buttons from the PiSCSI Control Board are pressed"""
import observer import observer
from ctrlboard_hw.hardware_button import HardwareButton from ctrlboard_hw.hardware_button import HardwareButton
from ctrlboard_hw.encoder import Encoder from ctrlboard_hw.encoder import Encoder

View File

@ -1,4 +1,5 @@
"""Module providing the profile cycler class for the PiSCSI Control Board UI""" """Module providing the profile cycler class for the PiSCSI Control Board UI"""
from ctrlboard_menu_builder import CtrlBoardMenuBuilder from ctrlboard_menu_builder import CtrlBoardMenuBuilder
from menu.cycler import Cycler from menu.cycler import Cycler

View File

@ -1,4 +1,5 @@
"""Module providing the shutdown cycler for the PiSCSI Control Board UI """ """Module providing the shutdown cycler for the PiSCSI Control Board UI """
from menu.cycler import Cycler from menu.cycler import Cycler

View File

@ -1,4 +1,5 @@
"""Module providing the interface to the PiSCSI Control Board hardware""" """Module providing the interface to the PiSCSI Control Board hardware"""
# noinspection PyUnresolvedReferences # noinspection PyUnresolvedReferences
import logging import logging
import time import time

View File

@ -1,5 +1,6 @@
"""Module containing an implementation for reading the rotary encoder directions through """Module containing an implementation for reading the rotary encoder directions through
the i2c multiplexer + interrupt""" the i2c multiplexer + interrupt"""
from ctrlboard_hw.hardware_button import HardwareButton from ctrlboard_hw.hardware_button import HardwareButton

View File

@ -1,6 +1,7 @@
""" """
Module for interfacting with the pca9554 multiplexer Module for interfacting with the pca9554 multiplexer
""" """
# pylint: disable=c-extension-no-member # pylint: disable=c-extension-no-member
import logging import logging
import smbus import smbus

View File

@ -1,4 +1,5 @@
"""Module for building the control board UI specific menus""" """Module for building the control board UI specific menus"""
import logging import logging
from menu.menu import Menu from menu.menu import Menu

View File

@ -1,4 +1,5 @@
"""Module is the entry point for the PiSCSI Control Board UI""" """Module is the entry point for the PiSCSI Control Board UI"""
import argparse import argparse
import sys import sys
import logging import logging

View File

@ -1,4 +1,5 @@
"""Module implementing a blank screensaver""" """Module implementing a blank screensaver"""
from menu.screensaver import ScreenSaver from menu.screensaver import ScreenSaver

View File

@ -1,4 +1,5 @@
"""Module that implements a button cycling functionality""" """Module that implements a button cycling functionality"""
from abc import abstractmethod from abc import abstractmethod
from menu.timer import Timer from menu.timer import Timer
from piscsi.file_cmds import FileCmds from piscsi.file_cmds import FileCmds

View File

@ -1,4 +1,5 @@
"""Module for creating a menu""" """Module for creating a menu"""
from typing import List from typing import List

View File

@ -1,4 +1,5 @@
"""Module for creating menus""" """Module for creating menus"""
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from menu.menu import Menu from menu.menu import Menu

View File

@ -1,4 +1,5 @@
"""Module providing the menu controller.""" """Module providing the menu controller."""
import time import time
import importlib import importlib
from typing import Dict, Optional from typing import Dict, Optional

View File

@ -1,4 +1,5 @@
"""Module provides the abstract menu renderer class""" """Module provides the abstract menu renderer class"""
import time import time
import math import math
import itertools import itertools

View File

@ -1,4 +1,5 @@
"""Module providing the Adafruit SSD1306 menu renderer class""" """Module providing the Adafruit SSD1306 menu renderer class"""
# pylint: disable=import-error # pylint: disable=import-error
from board import SCL, SDA from board import SCL, SDA
import busio import busio

View File

@ -1,4 +1,5 @@
"""Module providing the luma oled menu renderer class""" """Module providing the luma oled menu renderer class"""
from luma.core.interface.serial import i2c from luma.core.interface.serial import i2c
from menu.menu_renderer import MenuRenderer from menu.menu_renderer import MenuRenderer

View File

@ -1,4 +1,5 @@
"""Module providing the menu screensaver class""" """Module providing the menu screensaver class"""
from abc import abstractmethod from abc import abstractmethod
from menu.timer import Timer from menu.timer import Timer

View File

@ -1,4 +1,5 @@
"""Module providing a timer class""" """Module providing a timer class"""
import time import time

View File

@ -1,4 +1,5 @@
"""Module providing implementations for menu transitions.""" """Module providing implementations for menu transitions."""
from abc import abstractmethod from abc import abstractmethod
from PIL import Image from PIL import Image

View File

@ -1,4 +1,5 @@
"""Module for Observable part of the Observer pattern functionality""" """Module for Observable part of the Observer pattern functionality"""
from typing import List from typing import List
from observer import Observer from observer import Observer

View File

@ -1,4 +1,5 @@
"""Module implementing the Observer part of the Observer pattern""" """Module implementing the Observer part of the Observer pattern"""
from abc import ABC, abstractmethod from abc import ABC, abstractmethod

View File

@ -1,4 +1,5 @@
"""Module implementing the PiSCSI Control Board UI specific menu controller""" """Module implementing the PiSCSI Control Board UI specific menu controller"""
from ctrlboard_menu_builder import CtrlBoardMenuBuilder from ctrlboard_menu_builder import CtrlBoardMenuBuilder
from menu.menu_builder import MenuBuilder from menu.menu_builder import MenuBuilder
from menu.menu_controller import MenuController from menu.menu_controller import MenuController

View File

@ -6,7 +6,7 @@ adafruit-circuitpython-ssd1306==2.12.11
adafruit-circuitpython-typing==1.9.5 adafruit-circuitpython-typing==1.9.5
Adafruit-PlatformDetect==3.53.0 Adafruit-PlatformDetect==3.53.0
Adafruit-PureIO==1.1.11 Adafruit-PureIO==1.1.11
Pillow==10.2.0 Pillow==10.3.0
protobuf==3.20.2 protobuf==3.20.2
pyftdi==0.55.0 pyftdi==0.55.0
pyserial==3.5 pyserial==3.5

View File

@ -1,6 +1,7 @@
""" """
Linux interrupt handling module Linux interrupt handling module
""" """
import signal import signal

View File

@ -1,7 +1,23 @@
pytest==7.1.3 black==24.3.0
pytest-httpserver==1.0.6 certifi==2024.2.2
black==22.8.0 charset-normalizer==3.3.2
flake8==5.0.4 click==8.1.7
watchdog==2.1.9 flake8==7.0.0
idna==3.7
iniconfig==2.0.0
MarkupSafe==2.1.5
mccabe==0.7.0
mypy-extensions==1.0.0
packaging==24.0
pathspec==0.12.1
platformdirs==4.2.0
pluggy==1.4.0
pycodestyle==2.11.1
pyflakes==3.2.0
pytest==8.1.1
pytest_httpserver==1.0.10
requests==2.31.0 requests==2.31.0
urllib3==2.2.1
vcgencmd==0.1.1 vcgencmd==0.1.1
watchdog==4.0.0
Werkzeug==3.0.1

View File

@ -2,6 +2,8 @@
set -e set -e
# set -x # Uncomment to Debug # set -x # Uncomment to Debug
CACHEDIR="$HOME/.cache/piscsi"
cd "$(dirname "$0")" cd "$(dirname "$0")"
# verify packages installed # verify packages installed
ERROR=0 ERROR=0
@ -65,8 +67,9 @@ if ! test -e venv; then
echo "Activating venv" echo "Activating venv"
source venv/bin/activate source venv/bin/activate
echo "Installing requirements.txt" echo "Installing requirements.txt"
pip3 install wheel pip3 install wheel --no-index --find-links="$CACHEDIR"
pip3 install -r requirements.txt # Reference: https://pip.pypa.io/en/latest/user_guide/#installing-from-local-packages
pip3 install -r requirements.txt --no-index --find-links="$CACHEDIR"
if git rev-parse --is-inside-work-tree &> /dev/null; then if git rev-parse --is-inside-work-tree &> /dev/null; then
git rev-parse HEAD > current git rev-parse HEAD > current
@ -85,7 +88,7 @@ if [[ $? -eq 0 ]]; then
git rev-parse > current git rev-parse > current
elif [ "$(cat current)" != "$(git rev-parse HEAD)" ]; then elif [ "$(cat current)" != "$(git rev-parse HEAD)" ]; then
echo "New version detected, updating libraries from requirements.txt" echo "New version detected, updating libraries from requirements.txt"
pip3 install -r requirements.txt pip3 install -r requirements.txt --no-index --find-links="$CACHEDIR"
git rev-parse HEAD > current git rev-parse HEAD > current
fi fi
else else