mirror of https://github.com/akuker/RASCSI.git
Compare commits
14 Commits
52ba6b4b01
...
b54e81886e
Author | SHA1 | Date |
---|---|---|
Tony Kuker | b54e81886e | |
Daniel Markstedt | ea4dce02fb | |
Daniel Markstedt | 1919eb34bb | |
Daniel Markstedt | a7538980d7 | |
Daniel Markstedt | 85dc2cf0be | |
Daniel Markstedt | a6a8cadf21 | |
dependabot[bot] | 12bb86db9b | |
dependabot[bot] | b348643ff3 | |
dependabot[bot] | 396af80e62 | |
dependabot[bot] | 99cb648c60 | |
Daniel Markstedt | b1a3ffbc7d | |
dependabot[bot] | 52e4a92aec | |
Daniel Markstedt | afdd3c0ae2 | |
Tony Kuker | 6dbef076b1 |
|
@ -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
|
||||||
|
|
11
README.md
11
README.md
|
@ -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!
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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:
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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:
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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()) {
|
||||||
|
|
|
@ -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:
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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";
|
|
||||||
}
|
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 });
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
FROM python:3.7-slim
|
FROM python:3.9-slim
|
||||||
ENV DOCKER=1
|
ENV DOCKER=1
|
||||||
|
|
||||||
WORKDIR /src
|
WORKDIR /src
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
"""Module implementing a blank screensaver"""
|
"""Module implementing a blank screensaver"""
|
||||||
|
|
||||||
from menu.screensaver import ScreenSaver
|
from menu.screensaver import ScreenSaver
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
"""Module for creating a menu"""
|
"""Module for creating a menu"""
|
||||||
|
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
"""Module providing a timer class"""
|
"""Module providing a timer class"""
|
||||||
|
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
"""
|
"""
|
||||||
Linux interrupt handling module
|
Linux interrupt handling module
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import signal
|
import signal
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue