├── python
├── __init__.py
├── web
│ ├── __init__.py
│ ├── src
│ │ ├── __init__.py
│ │ ├── pwa
│ │ │ ├── favicon.ico
│ │ │ ├── apple-icon.png
│ │ │ ├── favicon-16x16.png
│ │ │ ├── favicon-32x32.png
│ │ │ ├── favicon-96x96.png
│ │ │ ├── ms-icon-70x70.png
│ │ │ ├── apple-icon-57x57.png
│ │ │ ├── apple-icon-60x60.png
│ │ │ ├── apple-icon-72x72.png
│ │ │ ├── apple-icon-76x76.png
│ │ │ ├── ms-icon-144x144.png
│ │ │ ├── ms-icon-150x150.png
│ │ │ ├── ms-icon-310x310.png
│ │ │ ├── android-icon-36x36.png
│ │ │ ├── android-icon-48x48.png
│ │ │ ├── android-icon-72x72.png
│ │ │ ├── android-icon-96x96.png
│ │ │ ├── apple-icon-114x114.png
│ │ │ ├── apple-icon-120x120.png
│ │ │ ├── apple-icon-144x144.png
│ │ │ ├── apple-icon-152x152.png
│ │ │ ├── apple-icon-180x180.png
│ │ │ ├── android-icon-144x144.png
│ │ │ ├── android-icon-192x192.png
│ │ │ ├── apple-icon-precomposed.png
│ │ │ ├── browserconfig.xml
│ │ │ └── manifest.json
│ │ ├── templates
│ │ │ ├── diskinfo.html
│ │ │ ├── manpage.html
│ │ │ ├── logs.html
│ │ │ └── deviceinfo.html
│ │ ├── static
│ │ │ └── themes
│ │ │ │ └── modern
│ │ │ │ └── icons
│ │ │ │ ├── cloud.svg
│ │ │ │ ├── success.svg
│ │ │ │ ├── device-optical.svg
│ │ │ │ ├── device-reserved.svg
│ │ │ │ ├── home.svg
│ │ │ │ ├── upload-success.svg
│ │ │ │ ├── cloud-off.svg
│ │ │ │ ├── info.svg
│ │ │ │ ├── upload-error.svg
│ │ │ │ ├── file-copy.svg
│ │ │ │ ├── file-delete.svg
│ │ │ │ ├── log-out.svg
│ │ │ │ ├── upload-queued.svg
│ │ │ │ ├── file-rename.svg
│ │ │ │ ├── upload-in-progress.svg
│ │ │ │ ├── command.svg
│ │ │ │ ├── external-link.svg
│ │ │ │ ├── device-removable.svg
│ │ │ │ ├── error.svg
│ │ │ │ ├── device-printer.svg
│ │ │ │ ├── device-network.svg
│ │ │ │ ├── warning.svg
│ │ │ │ ├── device-other.svg
│ │ │ │ ├── device-hard-drive.svg
│ │ │ │ ├── file-info.svg
│ │ │ │ ├── LICENSE
│ │ │ │ ├── file-device-attach.svg
│ │ │ │ └── file-extract.svg
│ │ └── settings.py
│ ├── tests
│ │ ├── output
│ │ │ └── .gitkeep
│ │ ├── assets
│ │ │ ├── test_image.7z
│ │ │ ├── test_image.sit
│ │ │ └── test_image.zip
│ │ └── api
│ │ │ └── test_auth.py
│ ├── mock
│ │ └── bin
│ │ │ ├── git
│ │ │ ├── journalctl
│ │ │ ├── systemctl
│ │ │ ├── brctl
│ │ │ ├── hostnamectl
│ │ │ └── vcgencmd
│ ├── .prettierrc.json
│ ├── babel.cfg
│ ├── package.json
│ ├── pyproject.toml
│ ├── .stylelintrc.json
│ ├── service-infra
│ │ ├── piscsi-web.service
│ │ ├── 502.html
│ │ └── nginx-default.conf
│ ├── requirements.txt
│ ├── requirements-dev.txt
│ └── translation_update.sh
├── common
│ ├── tests
│ │ └── .gitkeep
│ ├── src
│ │ ├── __init__.py
│ │ ├── piscsi
│ │ │ ├── __init__.py
│ │ │ ├── exceptions.py
│ │ │ ├── common_settings.py
│ │ │ └── return_codes.py
│ │ ├── util
│ │ │ ├── __init__.py
│ │ │ └── run.py
│ │ └── README.md
│ ├── resources
│ │ ├── type_writer.ttf
│ │ ├── splash_stop_32.bmp
│ │ ├── splash_stop_64.bmp
│ │ ├── splash_start_32.bmp
│ │ ├── splash_start_64.bmp
│ │ ├── DejaVuSansMono-Bold.ttf
│ │ └── README.md
│ └── requirements.txt
├── ctrlboard
│ ├── __init__.py
│ ├── src
│ │ ├── __init__.py
│ │ ├── menu
│ │ │ ├── __init__.py
│ │ │ ├── menu_builder.py
│ │ │ ├── timer.py
│ │ │ ├── blank_screensaver.py
│ │ │ ├── menu_renderer_adafruit_ssd1306.py
│ │ │ ├── menu.py
│ │ │ ├── screensaver.py
│ │ │ ├── menu_renderer_luma_oled.py
│ │ │ └── menu_renderer_config.py
│ │ ├── ctrlboard_hw
│ │ │ ├── __init__.py
│ │ │ ├── hardware_button.py
│ │ │ ├── ctrlboard_hw_constants.py
│ │ │ └── encoder.py
│ │ ├── ctrlboard_event_handler
│ │ │ ├── __init__.py
│ │ │ ├── ctrlboard_print_event_handler.py
│ │ │ ├── piscsi_profile_cycler.py
│ │ │ └── piscsi_shutdown_cycler.py
│ │ ├── observer.py
│ │ ├── observable.py
│ │ ├── config.py
│ │ └── piscsi_menu_controller.py
│ ├── requirements.txt
│ ├── service-infra
│ │ └── piscsi-ctrlboard.service
│ └── README.md
├── oled
│ ├── src
│ │ ├── __init__.py
│ │ └── interrupt_handler.py
│ ├── tests
│ │ └── .gitkeep
│ ├── service-infra
│ │ └── piscsi-oled.service
│ ├── requirements.txt
│ └── README.md
├── .flake8
├── pyproject.toml
└── README.md
├── docker
├── volumes
│ ├── config
│ │ └── .gitkeep
│ └── images
│ │ └── .gitkeep
├── docker-compose.override.yml.example
├── pytest
│ └── Dockerfile
├── backend
│ ├── piscsi_wrapper.sh
│ └── Dockerfile
├── web
│ ├── web_start_wrapper.sh
│ └── Dockerfile
├── docker-compose.ci.yml
└── docker-compose.yml
├── _config.yml
├── .github
├── CODEOWNERS
├── FUNDING.yml
├── ISSUE_TEMPLATE.md
├── dependabot.yml
└── workflows
│ └── build_code.yml
├── os_integration
├── piscsi.conf
├── dhcpcd.conf.patch
├── piscsi_bridge
└── piscsi.service
├── doc
├── logo
│ ├── redpanda-16x16.png
│ ├── redpanda-32x32.png
│ ├── redpanda-mono.ai
│ ├── redpanda-mono.png
│ └── redpanda-rgb.png
├── scsimon.1
├── scsiloop.1
├── scsimon_man_page.txt
└── scsiloop_man_page.txt
├── hw
└── README.md
├── cpp
├── .gitignore
├── hal
│ ├── gpiobus_factory.h
│ ├── data_sample.cpp
│ ├── log.h
│ ├── gpiobus_factory.cpp
│ ├── systimer.cpp
│ ├── data_sample.h
│ ├── systimer.h
│ ├── sbc_version.h
│ ├── pin_control.h
│ ├── connection_type
│ │ ├── connection_aibom.h
│ │ ├── connection_fullspec.h
│ │ ├── connection_gamernium.h
│ │ └── connection_standard.h
│ └── systimer_raspberry.h
├── piscsi
│ ├── piscsi.cpp
│ ├── piscsi_service.h
│ ├── command_context.h
│ ├── piscsi_image.h
│ ├── piscsi_core.h
│ └── localizer.h
├── scsimon
│ ├── scsimon.cpp
│ ├── sm_reports.h
│ └── sm_core.h
├── scsictl
│ ├── scsictl.cpp
│ ├── scsictl_core.h
│ ├── scsictl_parser.cpp
│ ├── scsictl_parser.h
│ ├── scsictl_display.h
│ └── scsictl_commands.h
├── scsiloop
│ ├── scsiloop_timer.h
│ ├── scsiloop.cpp
│ ├── scsiloop_core.h
│ ├── scsiloop_cout.cpp
│ ├── scsiloop_cout.h
│ └── scsiloop_gpio.h
├── scsidump
│ └── scsidump.cpp
├── shared
│ ├── piscsi_version.h
│ ├── network_util.h
│ ├── config.h
│ ├── piscsi_version.cpp
│ ├── piscsi_exceptions.h
│ ├── piscsi_util.h
│ ├── protobuf_util.h
│ └── network_util.cpp
├── devices
│ ├── interfaces
│ │ ├── scsi_mmc_commands.h
│ │ ├── scsi_printer_commands.h
│ │ ├── scsi_block_commands.h
│ │ └── scsi_primary_commands.h
│ ├── device_logger.h
│ ├── scsihd.h
│ ├── mode_page_device.h
│ ├── cd_track.h
│ ├── scsimo.h
│ ├── device_logger.cpp
│ ├── host_services.h
│ ├── device_factory.h
│ ├── scsihd_nec.h
│ ├── disk_track.h
│ ├── scsicd.h
│ ├── ctapdriver.h
│ ├── scsi_printer.h
│ ├── scsi_command_util.h
│ └── scsi_streamer.h
├── test
│ ├── linux_os_stubs.h
│ ├── network_util_test.cpp
│ ├── test_setup.cpp
│ ├── localizer_test.cpp
│ ├── ctapdriver_test.cpp
│ ├── piscsi_exceptions_test.cpp
│ ├── test_shared.h
│ ├── linux_os_stubs.cpp
│ ├── scsictl_parser_test.cpp
│ └── scsidump_test.cpp
└── controllers
│ ├── phase_handler.cpp
│ ├── controller_manager.h
│ └── phase_handler.h
├── ide_setup
└── README
├── .dockerignore
├── .gitignore
└── LICENSE
/python/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/python/web/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/python/common/tests/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/python/ctrlboard/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/python/oled/src/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/python/oled/tests/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/python/web/src/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docker/volumes/config/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docker/volumes/images/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/python/common/src/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/python/ctrlboard/src/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/python/web/tests/output/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/python/common/src/piscsi/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/python/common/src/util/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/python/ctrlboard/src/menu/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-midnight
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | * @akuker @rdmark
2 |
--------------------------------------------------------------------------------
/python/ctrlboard/src/ctrlboard_hw/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/python/ctrlboard/src/ctrlboard_event_handler/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/python/web/mock/bin/git:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | exit 0
3 |
--------------------------------------------------------------------------------
/python/web/.prettierrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "printWidth": 100
3 | }
4 |
--------------------------------------------------------------------------------
/python/web/babel.cfg:
--------------------------------------------------------------------------------
1 | [python: **.py]
2 | [jinja2: **/templates/**.html]
3 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: akuker
4 |
--------------------------------------------------------------------------------
/os_integration/piscsi.conf:
--------------------------------------------------------------------------------
1 | if $programname == 'PISCSI' then /var/log/piscsi.log
2 | & stop
3 |
--------------------------------------------------------------------------------
/doc/logo/redpanda-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PiSCSI/piscsi/HEAD/doc/logo/redpanda-16x16.png
--------------------------------------------------------------------------------
/doc/logo/redpanda-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PiSCSI/piscsi/HEAD/doc/logo/redpanda-32x32.png
--------------------------------------------------------------------------------
/doc/logo/redpanda-mono.ai:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PiSCSI/piscsi/HEAD/doc/logo/redpanda-mono.ai
--------------------------------------------------------------------------------
/doc/logo/redpanda-mono.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PiSCSI/piscsi/HEAD/doc/logo/redpanda-mono.png
--------------------------------------------------------------------------------
/doc/logo/redpanda-rgb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PiSCSI/piscsi/HEAD/doc/logo/redpanda-rgb.png
--------------------------------------------------------------------------------
/python/.flake8:
--------------------------------------------------------------------------------
1 | [flake8]
2 | max-line-length = 100
3 | exclude =
4 | venv
5 | piscsi_interface_pb2.py
--------------------------------------------------------------------------------
/python/web/src/pwa/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PiSCSI/piscsi/HEAD/python/web/src/pwa/favicon.ico
--------------------------------------------------------------------------------
/python/web/src/pwa/apple-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PiSCSI/piscsi/HEAD/python/web/src/pwa/apple-icon.png
--------------------------------------------------------------------------------
/python/web/src/pwa/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PiSCSI/piscsi/HEAD/python/web/src/pwa/favicon-16x16.png
--------------------------------------------------------------------------------
/python/web/src/pwa/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PiSCSI/piscsi/HEAD/python/web/src/pwa/favicon-32x32.png
--------------------------------------------------------------------------------
/python/web/src/pwa/favicon-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PiSCSI/piscsi/HEAD/python/web/src/pwa/favicon-96x96.png
--------------------------------------------------------------------------------
/python/web/src/pwa/ms-icon-70x70.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PiSCSI/piscsi/HEAD/python/web/src/pwa/ms-icon-70x70.png
--------------------------------------------------------------------------------
/python/web/tests/assets/test_image.7z:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PiSCSI/piscsi/HEAD/python/web/tests/assets/test_image.7z
--------------------------------------------------------------------------------
/python/common/resources/type_writer.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PiSCSI/piscsi/HEAD/python/common/resources/type_writer.ttf
--------------------------------------------------------------------------------
/python/web/src/pwa/apple-icon-57x57.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PiSCSI/piscsi/HEAD/python/web/src/pwa/apple-icon-57x57.png
--------------------------------------------------------------------------------
/python/web/src/pwa/apple-icon-60x60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PiSCSI/piscsi/HEAD/python/web/src/pwa/apple-icon-60x60.png
--------------------------------------------------------------------------------
/python/web/src/pwa/apple-icon-72x72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PiSCSI/piscsi/HEAD/python/web/src/pwa/apple-icon-72x72.png
--------------------------------------------------------------------------------
/python/web/src/pwa/apple-icon-76x76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PiSCSI/piscsi/HEAD/python/web/src/pwa/apple-icon-76x76.png
--------------------------------------------------------------------------------
/python/web/src/pwa/ms-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PiSCSI/piscsi/HEAD/python/web/src/pwa/ms-icon-144x144.png
--------------------------------------------------------------------------------
/python/web/src/pwa/ms-icon-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PiSCSI/piscsi/HEAD/python/web/src/pwa/ms-icon-150x150.png
--------------------------------------------------------------------------------
/python/web/src/pwa/ms-icon-310x310.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PiSCSI/piscsi/HEAD/python/web/src/pwa/ms-icon-310x310.png
--------------------------------------------------------------------------------
/python/web/tests/assets/test_image.sit:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PiSCSI/piscsi/HEAD/python/web/tests/assets/test_image.sit
--------------------------------------------------------------------------------
/python/web/tests/assets/test_image.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PiSCSI/piscsi/HEAD/python/web/tests/assets/test_image.zip
--------------------------------------------------------------------------------
/python/common/resources/splash_stop_32.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PiSCSI/piscsi/HEAD/python/common/resources/splash_stop_32.bmp
--------------------------------------------------------------------------------
/python/common/resources/splash_stop_64.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PiSCSI/piscsi/HEAD/python/common/resources/splash_stop_64.bmp
--------------------------------------------------------------------------------
/python/web/src/pwa/android-icon-36x36.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PiSCSI/piscsi/HEAD/python/web/src/pwa/android-icon-36x36.png
--------------------------------------------------------------------------------
/python/web/src/pwa/android-icon-48x48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PiSCSI/piscsi/HEAD/python/web/src/pwa/android-icon-48x48.png
--------------------------------------------------------------------------------
/python/web/src/pwa/android-icon-72x72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PiSCSI/piscsi/HEAD/python/web/src/pwa/android-icon-72x72.png
--------------------------------------------------------------------------------
/python/web/src/pwa/android-icon-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PiSCSI/piscsi/HEAD/python/web/src/pwa/android-icon-96x96.png
--------------------------------------------------------------------------------
/python/web/src/pwa/apple-icon-114x114.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PiSCSI/piscsi/HEAD/python/web/src/pwa/apple-icon-114x114.png
--------------------------------------------------------------------------------
/python/web/src/pwa/apple-icon-120x120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PiSCSI/piscsi/HEAD/python/web/src/pwa/apple-icon-120x120.png
--------------------------------------------------------------------------------
/python/web/src/pwa/apple-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PiSCSI/piscsi/HEAD/python/web/src/pwa/apple-icon-144x144.png
--------------------------------------------------------------------------------
/python/web/src/pwa/apple-icon-152x152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PiSCSI/piscsi/HEAD/python/web/src/pwa/apple-icon-152x152.png
--------------------------------------------------------------------------------
/python/web/src/pwa/apple-icon-180x180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PiSCSI/piscsi/HEAD/python/web/src/pwa/apple-icon-180x180.png
--------------------------------------------------------------------------------
/python/common/resources/splash_start_32.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PiSCSI/piscsi/HEAD/python/common/resources/splash_start_32.bmp
--------------------------------------------------------------------------------
/python/common/resources/splash_start_64.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PiSCSI/piscsi/HEAD/python/common/resources/splash_start_64.bmp
--------------------------------------------------------------------------------
/python/web/src/pwa/android-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PiSCSI/piscsi/HEAD/python/web/src/pwa/android-icon-144x144.png
--------------------------------------------------------------------------------
/python/web/src/pwa/android-icon-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PiSCSI/piscsi/HEAD/python/web/src/pwa/android-icon-192x192.png
--------------------------------------------------------------------------------
/python/common/resources/DejaVuSansMono-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PiSCSI/piscsi/HEAD/python/common/resources/DejaVuSansMono-Bold.ttf
--------------------------------------------------------------------------------
/python/pyproject.toml:
--------------------------------------------------------------------------------
1 | [tool.black]
2 | line-length = 100
3 | target-version = ['py39', 'py310', 'py311']
4 | extend-exclude = ".*_pb2.py"
5 |
--------------------------------------------------------------------------------
/python/web/src/pwa/apple-icon-precomposed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PiSCSI/piscsi/HEAD/python/web/src/pwa/apple-icon-precomposed.png
--------------------------------------------------------------------------------
/hw/README.md:
--------------------------------------------------------------------------------
1 | # Where's the hardware?
2 |
3 | The hardware design files have been moved to a separate repository at:
4 | https://github.com/PiSCSI/piscsi-hw
5 |
--------------------------------------------------------------------------------
/python/common/requirements.txt:
--------------------------------------------------------------------------------
1 | certifi==2024.7.4
2 | charset-normalizer==3.3.2
3 | idna==3.11
4 | protobuf==3.20.3
5 | requests==2.32.4
6 | urllib3==2.6.0
7 | vcgencmd==0.1.1
8 |
--------------------------------------------------------------------------------
/cpp/.gitignore:
--------------------------------------------------------------------------------
1 | *.bak
2 | *.HDA
3 | *.save
4 | *.cbp
5 | *.layout
6 | *.log
7 | *.vcd
8 | *.json
9 | *.html
10 | piscsi.dat
11 | obj
12 | bin
13 | coverage
14 | generated
15 |
--------------------------------------------------------------------------------
/python/web/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "devDependencies": {
3 | "prettier": "3.7.3",
4 | "stylelint": "^16.26.1",
5 | "stylelint-config-standard": "^39.0.1"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/python/web/pyproject.toml:
--------------------------------------------------------------------------------
1 | [tool.pytest.ini_options]
2 | addopts = "--junitxml=tests/output/report.xml --log-file=tests/output/pytest.log"
3 | log_cli = true
4 | log_cli_level = "warn"
--------------------------------------------------------------------------------
/python/web/.stylelintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["stylelint-config-standard"],
3 | "rules": {
4 | "no-descending-specificity": null,
5 | "media-feature-range-notation": "prefix"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/docker/docker-compose.override.yml.example:
--------------------------------------------------------------------------------
1 | services:
2 | web:
3 | volumes:
4 | - ../python:/home/pi/piscsi/python:delegated
5 | pytest:
6 | volumes:
7 | - ../python/web:/src:delegated
8 |
--------------------------------------------------------------------------------
/python/web/mock/bin/journalctl:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Mock responses to piscsi-web
4 | case $1 in
5 | -n)
6 | echo "logs $*"
7 | ;;
8 |
9 | **)
10 | echo "default"
11 | ;;
12 | esac
13 |
--------------------------------------------------------------------------------
/python/web/mock/bin/systemctl:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Mock responses to piscsi-web
4 | case $1 in
5 | is-active)
6 | echo "is-active"
7 | ;;
8 |
9 | **)
10 | echo "default"
11 | ;;
12 | esac
13 |
--------------------------------------------------------------------------------
/os_integration/dhcpcd.conf.patch:
--------------------------------------------------------------------------------
1 | --- dhcpcd_orig.conf 2021-02-26 17:32:14.065284400 -0600
2 | +++ dhcpcd.conf 2021-02-26 17:32:30.925039567 -0600
3 | @@ -58,3 +58,4 @@
4 | #interface eth0
5 | #fallback static_eth0
6 | #
7 | +denyinterfaces eth0
8 |
--------------------------------------------------------------------------------
/python/web/mock/bin/brctl:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Mock responses to piscsi-web
4 | case $1 in
5 | "show")
6 | echo "piscsi_bridge 8000.dca632b05dd1 no eth0"
7 | ;;
8 |
9 | **)
10 | echo "default"
11 | ;;
12 | esac
13 |
--------------------------------------------------------------------------------
/python/web/src/templates/diskinfo.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 |
{{ _("Disk Image Details: %(file_name)s", file_name=file_name) }}
5 | {{ diskinfo }}
6 |
7 |
8 | {% endblock content %}
9 |
--------------------------------------------------------------------------------
/python/ctrlboard/requirements.txt:
--------------------------------------------------------------------------------
1 | luma.core==2.4.1
2 | luma.oled==3.14.0
3 | pillow==11.3.0
4 | protobuf==3.20.3
5 | pyftdi==0.55.0
6 | pyserial==3.5
7 | pyusb==1.3.1
8 | RPi.GPIO==0.7.1
9 | smbus==1.1.post2
10 | smbus2==0.5.0
11 | Unidecode==1.3.2
12 |
--------------------------------------------------------------------------------
/ide_setup/README:
--------------------------------------------------------------------------------
1 | The Eclipse code formatter configuration shall be used together with
2 | Eclipse CDT in order to unify the formatting of the C++ code. Ensure to keep
3 | your formatting rules up to date.
4 |
5 | This formatter can also be imported into Intellij IDEA.
6 |
--------------------------------------------------------------------------------
/python/web/src/templates/manpage.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 | {{ _("Manual for %(app)s", app=app) }}
5 |
6 |
7 | {{ manpage | safe }}
8 |
9 |
10 |
11 | {% endblock content %}
12 |
--------------------------------------------------------------------------------
/python/web/src/static/themes/modern/icons/cloud.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | # Info
2 |
3 | - Which version of Pi are you using:
4 | - Which github revision of software:
5 | - Which board version:
6 | - Which computer is the PiSCSI connected to:
7 | - Which OS you are using (output of 'lsb_release -a'):
8 |
9 |
10 | # Describe the issue
11 |
--------------------------------------------------------------------------------
/python/web/src/static/themes/modern/icons/success.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/python/web/service-infra/piscsi-web.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=PiSCSI-Web service
3 | After=network-online.target piscsi.service
4 |
5 | [Service]
6 | Type=simple
7 | Restart=always
8 | ExecStart=/home/pi/piscsi/python/web/start.sh
9 | SyslogIdentifier=PISCSIWEB
10 |
11 | [Install]
12 | WantedBy=multi-user.target
13 |
--------------------------------------------------------------------------------
/python/web/src/pwa/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 | #ffffff
3 |
--------------------------------------------------------------------------------
/python/web/src/static/themes/modern/icons/device-optical.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docker/pytest/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:3.11-slim
2 | ENV DOCKER=1
3 |
4 | WORKDIR /src
5 |
6 | COPY python/web/requirements-dev.txt /src/requirements-dev.txt
7 | COPY python/web/pyproject.toml /src/pyproject.toml
8 | COPY python/web/tests /src/tests
9 |
10 | RUN pip install --no-cache-dir -r /src/requirements-dev.txt
11 |
12 | ENTRYPOINT ["pytest"]
13 |
--------------------------------------------------------------------------------
/python/web/src/static/themes/modern/icons/device-reserved.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/python/web/src/static/themes/modern/icons/home.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/python/web/src/static/themes/modern/icons/upload-success.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/python/web/src/static/themes/modern/icons/cloud-off.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/docker/backend/piscsi_wrapper.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | if [[ $BACKEND_PASSWORD ]]; then
4 | TOKEN_FILE="/home/pi/.config/piscsi/piscsi_secret"
5 | mkdir -p /home/pi/.config/piscsi || true
6 | echo $BACKEND_PASSWORD > $TOKEN_FILE
7 | chmod 700 $TOKEN_FILE
8 | /usr/local/bin/piscsi "$@" -P $TOKEN_FILE
9 | else
10 | /usr/local/bin/piscsi "$@"
11 | fi
12 |
--------------------------------------------------------------------------------
/python/web/src/static/themes/modern/icons/info.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/python/web/src/static/themes/modern/icons/upload-error.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/python/web/src/static/themes/modern/icons/file-copy.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/python/web/src/static/themes/modern/icons/file-delete.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/python/web/src/static/themes/modern/icons/log-out.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/python/web/src/static/themes/modern/icons/upload-queued.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/python/web/src/static/themes/modern/icons/file-rename.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/python/web/src/static/themes/modern/icons/upload-in-progress.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/python/web/src/static/themes/modern/icons/command.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/python/ctrlboard/service-infra/piscsi-ctrlboard.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=PiSCSI Control Board service
3 | After=network-online.target piscsi.service
4 |
5 | [Service]
6 | Type=simple
7 | Restart=always
8 | RestartSec=2s
9 | ExecStart=/home/pi/piscsi/python/ctrlboard/start.sh
10 | ExecStop=/bin/pkill --signal 2 -f "python3 src/main.py"
11 | SyslogIdentifier=PISCSICTRLB
12 |
13 | [Install]
14 | WantedBy=multi-user.target
15 |
--------------------------------------------------------------------------------
/python/web/src/static/themes/modern/icons/external-link.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/python/web/src/static/themes/modern/icons/device-removable.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/python/web/src/static/themes/modern/icons/error.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/python/ctrlboard/src/observer.py:
--------------------------------------------------------------------------------
1 | """Module implementing the Observer part of the Observer pattern"""
2 |
3 | from abc import ABC, abstractmethod
4 |
5 |
6 | # pylint: disable=too-few-public-methods
7 | class Observer(ABC):
8 | """Class implementing an abserver"""
9 |
10 | @abstractmethod
11 | def update(self, updated_object) -> None:
12 | """Abstract method for updating an observer. Needs to be implemented by subclasses."""
13 |
--------------------------------------------------------------------------------
/python/web/src/static/themes/modern/icons/device-printer.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/python/web/src/static/themes/modern/icons/device-network.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/python/web/src/static/themes/modern/icons/warning.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/os_integration/piscsi_bridge:
--------------------------------------------------------------------------------
1 | #
2 | # Defines the 'piscsi_bridge' bridge that connects the PiSCSI network
3 | # interface (ex DaynaPort SCSI/Link) to the outside world.
4 | #
5 | # Depending upon your system configuration, you may need to update this
6 | # file to change 'eth0' to your Ethernet interface
7 | #
8 | # This file should be place in /etc/network/interfaces.d
9 |
10 | auto piscsi_bridge
11 | iface piscsi_bridge inet dhcp
12 | bridge_ports eth0
13 |
14 |
--------------------------------------------------------------------------------
/python/web/src/static/themes/modern/icons/device-other.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/python/ctrlboard/src/menu/menu_builder.py:
--------------------------------------------------------------------------------
1 | """Module for creating menus"""
2 |
3 | from abc import ABC, abstractmethod
4 | from menu.menu import Menu
5 |
6 |
7 | # pylint: disable=too-few-public-methods
8 | class MenuBuilder(ABC):
9 | """Base class for menu builders"""
10 |
11 | def __init__(self):
12 | pass
13 |
14 | @abstractmethod
15 | def build(self, name: str, context_object=None) -> Menu:
16 | """builds a menu and gives it a name and a context object"""
17 |
--------------------------------------------------------------------------------
/cpp/hal/gpiobus_factory.h:
--------------------------------------------------------------------------------
1 | //---------------------------------------------------------------------------
2 | //
3 | // SCSI Target Emulator PiSCSI
4 | // for Raspberry Pi
5 | //
6 | // Copyright (C) 2022 akuker
7 | //
8 | //---------------------------------------------------------------------------
9 |
10 | #pragma once
11 |
12 | #include "hal/bus.h"
13 | #include
14 |
15 | class GPIOBUS_Factory
16 | {
17 | public:
18 |
19 | static unique_ptr Create(BUS::mode_e mode);
20 | };
21 |
--------------------------------------------------------------------------------
/python/web/mock/bin/hostnamectl:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | TMP_FILE="/tmp/hostnamectl_pretty.tmp"
4 |
5 | if [[ "$1" == "set-hostname" && "$2" == "--pretty" ]]; then
6 | if [[ -z "$3" ]]; then
7 | rm "$TMP_FILE" 2>/dev/null || true
8 | else
9 | echo "$3" > $TMP_FILE
10 | fi
11 |
12 | exit 0
13 | fi
14 |
15 | if [[ "$1" == "status" ]]; then
16 | cat "$TMP_FILE" 2>/dev/null
17 | exit 0
18 | fi
19 |
20 | echo "Mock does not recognize: $0 $@"
21 | exit 1
22 |
--------------------------------------------------------------------------------
/python/web/requirements.txt:
--------------------------------------------------------------------------------
1 | babel==2.17.0
2 | bjoern==3.2.2
3 | blinker==1.9.0
4 | certifi==2025.11.12
5 | charset-normalizer==2.1.1
6 | click==8.1.8
7 | flask==3.1.2
8 | flask-babel==4.0.0
9 | idna==3.11
10 | importlib-metadata==8.7.0
11 | itsdangerous==2.2.0
12 | jinja2==3.1.6
13 | MarkupSafe==3.0.3
14 | protobuf==3.20.3
15 | python-pam==2.0.2
16 | pytz==2023.3.post1
17 | requests==2.32.4
18 | six==1.17.0
19 | ua-parser==0.16.1
20 | urllib3==2.6.0
21 | vcgencmd==0.1.1
22 | werkzeug==3.1.4
23 | zipp==3.23.0
24 |
--------------------------------------------------------------------------------
/cpp/piscsi/piscsi.cpp:
--------------------------------------------------------------------------------
1 | //---------------------------------------------------------------------------
2 | //
3 | // SCSI Target Emulator PiSCSI
4 | // for Raspberry Pi
5 | //
6 | // Copyright (C) 2022-2023 Uwe Seimet
7 | //
8 | //---------------------------------------------------------------------------
9 |
10 | #include "piscsi/piscsi_core.h"
11 |
12 | using namespace std;
13 |
14 | int main(int argc, char *argv[])
15 | {
16 | vector args(argv, argv + argc);
17 |
18 | return Piscsi().run(args);
19 | }
20 |
--------------------------------------------------------------------------------
/cpp/scsimon/scsimon.cpp:
--------------------------------------------------------------------------------
1 | //---------------------------------------------------------------------------
2 | //
3 | // SCSI Target Emulator PiSCSI
4 | // for Raspberry Pi
5 | //
6 | // Copyright (C) 2022 Uwe Seimet
7 | //
8 | //---------------------------------------------------------------------------
9 |
10 | #include "scsimon/sm_core.h"
11 |
12 | using namespace std;
13 |
14 | int main(int argc, char *argv[])
15 | {
16 | const vector args(argv, argv + argc);
17 |
18 | return ScsiMon().run(args);
19 | }
20 |
--------------------------------------------------------------------------------
/cpp/scsictl/scsictl.cpp:
--------------------------------------------------------------------------------
1 | //---------------------------------------------------------------------------
2 | //
3 | // SCSI Target Emulator PiSCSI
4 | // for Raspberry Pi
5 | //
6 | // Copyright (C) 2022 Uwe Seimet
7 | //
8 | //---------------------------------------------------------------------------
9 |
10 | #include "scsictl/scsictl_core.h"
11 |
12 | using namespace std;
13 |
14 | int main(int argc, char *argv[])
15 | {
16 | const vector args(argv, argv + argc);
17 |
18 | return ScsiCtl().run(args);
19 | }
20 |
--------------------------------------------------------------------------------
/cpp/scsiloop/scsiloop_timer.h:
--------------------------------------------------------------------------------
1 | //---------------------------------------------------------------------------
2 | //
3 | // SCSI Target Emulator PiSCSI for Raspberry Pi
4 | // Loopback tester utility
5 | //
6 | // Copyright (C) 2022 akuker
7 | //
8 | //---------------------------------------------------------------------------
9 |
10 | #include
11 | #include
12 |
13 | using namespace std;
14 |
15 | class ScsiLoop_Timer
16 | {
17 | public:
18 | static int RunTimerTest(vector &error_list);
19 | };
--------------------------------------------------------------------------------
/cpp/scsidump/scsidump.cpp:
--------------------------------------------------------------------------------
1 | //---------------------------------------------------------------------------
2 | //
3 | // SCSI Target Emulator PiSCSI
4 | // for Raspberry Pi
5 | //
6 | // Copyright (C) 2022-2023 Uwe Seimet
7 | //
8 | //---------------------------------------------------------------------------
9 |
10 | #include "scsidump/scsidump_core.h"
11 |
12 | using namespace std;
13 |
14 | int main(int argc, char *argv[])
15 | {
16 | vector args(argv, argv + argc);
17 |
18 | return ScsiDump().run(args);
19 | }
20 |
--------------------------------------------------------------------------------
/python/web/src/static/themes/modern/icons/device-hard-drive.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/python/oled/service-infra/piscsi-oled.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=PiSCSI-OLED Monitor service
3 | After=network-online.target piscsi.service
4 |
5 | [Service]
6 | Type=simple
7 | Restart=always
8 | RestartSec=2s
9 | ExecStart=/home/pi/piscsi/python/oled/start.sh
10 | ExecStop=/bin/pkill --signal 2 -f "python3 src/piscsi_oled_monitor.py"
11 | # Sleep 2s as a crude way for the python interrupt handler to take effect and show the shutdown splash
12 | ExecStop=/bin/sleep 2
13 | SyslogIdentifier=PISCSIMON
14 |
15 | [Install]
16 | WantedBy=multi-user.target
17 |
--------------------------------------------------------------------------------
/cpp/scsiloop/scsiloop.cpp:
--------------------------------------------------------------------------------
1 | //---------------------------------------------------------------------------
2 | //
3 | // SCSI Target Emulator PiSCSI
4 | // for Raspberry Pi
5 | //
6 | // Copyright (C) 2022 Uwe Seimet
7 | // Copyright (C) 2022 akuker
8 | //
9 | //---------------------------------------------------------------------------
10 |
11 | #include "scsiloop/scsiloop_core.h"
12 |
13 | using namespace std;
14 |
15 | int main(int argc, char *argv[])
16 | {
17 | const vector args(argv, argv + argc);
18 |
19 | return ScsiLoop().run(args);
20 | }
21 |
--------------------------------------------------------------------------------
/python/common/src/piscsi/exceptions.py:
--------------------------------------------------------------------------------
1 | """
2 | Module for custom exceptions raised by the piscsi module
3 | """
4 |
5 |
6 | class FailedSocketConnectionException(Exception):
7 | """Raise when a piscsi protobuf socket connection cannot be established after multiple tries."""
8 |
9 |
10 | class EmptySocketChunkException(Exception):
11 | """Raise when a socket payload contains an empty chunk which implies a possible problem."""
12 |
13 |
14 | class InvalidProtobufResponse(Exception):
15 | """Raise when a piscsi socket payload contains unpexpected data."""
16 |
--------------------------------------------------------------------------------
/python/oled/requirements.txt:
--------------------------------------------------------------------------------
1 | Adafruit-Blinka==8.24.0
2 | adafruit-circuitpython-busdevice==5.2.14
3 | adafruit-circuitpython-connectionmanager==3.1.6
4 | adafruit-circuitpython-framebuf==1.6.4
5 | adafruit-circuitpython-requests==4.1.15
6 | adafruit-circuitpython-ssd1306==2.12.22
7 | adafruit-circuitpython-typing==1.12.3
8 | adafruit-platformdetect==3.84.1
9 | Adafruit-PureIO==1.1.11
10 | pillow==11.3.0
11 | protobuf==3.20.3
12 | pyftdi==0.55.0
13 | pyserial==3.5
14 | pyusb==1.3.1
15 | rpi-ws281x==5.0.0
16 | RPi.GPIO==0.7.1
17 | sysv-ipc==1.1.0
18 | typing-extensions==4.15.0
19 | Unidecode==1.3.6
20 |
--------------------------------------------------------------------------------
/python/web/service-infra/502.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | PiSCSI Web is Starting
5 |
6 |
7 |
8 |
9 |
10 | PiSCSI Web Interface is Starting....
11 | This page will automatically refresh.
12 | First boot and upgrades can take a second while resolving dependencies.
13 | If you're seeing this page for over a minute, please check the logs at sudo journalctl -f
14 |
15 |
16 |
--------------------------------------------------------------------------------
/cpp/shared/piscsi_version.h:
--------------------------------------------------------------------------------
1 | //---------------------------------------------------------------------------
2 | //
3 | // SCSI Target Emulator PiSCSI
4 | // for Raspberry Pi
5 | //
6 | // Copyright (C) 2020 akuker
7 | // [ Define the version string ]
8 | //
9 | //---------------------------------------------------------------------------
10 | #pragma once
11 |
12 | #include
13 |
14 | extern const int piscsi_major_version; // Last two digits of year
15 | extern const int piscsi_minor_version; // Month
16 | extern const int piscsi_patch_version; // Patch number
17 |
18 | std::string piscsi_get_version_string();
19 |
--------------------------------------------------------------------------------
/cpp/shared/network_util.h:
--------------------------------------------------------------------------------
1 | //---------------------------------------------------------------------------
2 | //
3 | // SCSI Target Emulator PiSCSI
4 | // for Raspberry Pi
5 | //
6 | // Copyright (C) 2023 Uwe Seimet
7 | //
8 | //---------------------------------------------------------------------------
9 |
10 | #pragma once
11 |
12 | #include
13 | #include
14 |
15 | using namespace std;
16 |
17 | struct sockaddr_in;
18 |
19 | namespace network_util
20 | {
21 | bool IsInterfaceUp(const string&);
22 | set> GetNetworkInterfaces();
23 | bool ResolveHostName(const string&, sockaddr_in *);
24 | }
25 |
--------------------------------------------------------------------------------
/cpp/devices/interfaces/scsi_mmc_commands.h:
--------------------------------------------------------------------------------
1 | //---------------------------------------------------------------------------
2 | //
3 | // SCSI Target Emulator PiSCSI
4 | // for Raspberry Pi
5 | //
6 | // Copyright (C) 2021-2022 Uwe Seimet
7 | //
8 | // Interface for SCSI Multi-Media commands (see https://www.t10.org/drafts.htm, MMC-6)
9 | //
10 | //---------------------------------------------------------------------------
11 |
12 | #pragma once
13 |
14 | class ScsiMmcCommands
15 | {
16 |
17 | public:
18 |
19 | ScsiMmcCommands() = default;
20 | virtual ~ScsiMmcCommands() = default;
21 |
22 | virtual void ReadToc() = 0;
23 | };
24 |
--------------------------------------------------------------------------------
/python/web/requirements-dev.txt:
--------------------------------------------------------------------------------
1 | babel==2.17.0
2 | black==25.11.0
3 | certifi==2024.7.4
4 | charset-normalizer==3.3.2
5 | click==8.1.8
6 | exceptiongroup==1.3.0
7 | flake8==7.3.0
8 | idna==3.11
9 | iniconfig==2.0.0
10 | MarkupSafe==3.0.3
11 | mccabe==0.7.0
12 | mypy-extensions==1.1.0
13 | packaging==25.0
14 | pathspec==0.12.1
15 | platformdirs==4.2.0
16 | pluggy==1.6.0
17 | pycodestyle==2.14.0
18 | pyflakes==3.4.0
19 | pygments==2.19.2
20 | pytest==8.4.2
21 | pytest-httpserver==1.1.3
22 | pytokens==0.3.0
23 | requests==2.32.4
24 | tomli==2.3.0
25 | typing-extensions==4.15.0
26 | urllib3==2.6.0
27 | vcgencmd==0.1.1
28 | watchdog==6.0.0
29 | werkzeug==3.1.4
30 |
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
1 | # Exclude all by default
2 | /*
3 |
4 | # Paths to include
5 | !/docker/backend/piscsi_wrapper.sh
6 | !/docker/web/web_start_wrapper.sh
7 | !/cpp
8 | !/doc
9 | !/os_integration
10 | !/proto
11 | !/python
12 | !/test
13 | !/easyinstall.sh
14 | !/LICENCE
15 | !/README.md
16 |
17 | # Dev artifacts to exclude
18 | **/.git
19 |
20 | /cpp/bin
21 | /cpp/obj
22 |
23 | **/venv*
24 | **/*.pyc
25 | **/__pycache__
26 | **/.pytest_cache
27 | **/piscsi_interface_pb2.py
28 | **/report.xml
29 |
30 | **/.idea
31 | **/.vscode
32 | **/.DS_Store
33 |
34 | **/core
35 | **/*.swp
36 | **/current
37 |
38 | **/node_modules
39 | **/messages.pot
40 | **/messages.mo
41 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | venv
2 | *.pyc
3 | *.swp
4 | *.log
5 | *~
6 | core
7 | .idea/
8 | .vscode
9 | .DS_Store
10 | __pycache__
11 | current
12 | rascsi_interface_pb2.py
13 | piscsi_interface_pb2.py
14 | messages.pot
15 | messages.mo
16 | report.xml
17 | node_modules
18 |
19 | # Intermediate files from astyle
20 | *.orig
21 |
22 | docker/docker-compose.override.yml
23 | /docker/volumes/images/*
24 | !/docker/volumes/images/.gitkeep
25 | /docker/volumes/config/*
26 | !/docker/volumes/config/.gitkeep
27 |
28 | # temporary user files
29 | s.sh
30 |
31 | # temporary kicad files
32 | *-backups
33 |
34 | # VSCode temp file
35 | settings.json
36 |
37 | # submodules
38 | hfdisk*
39 | mac-hard-disk-drivers
40 |
--------------------------------------------------------------------------------
/python/web/translation_update.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -e
3 |
4 | cd "$(dirname "$0")"
5 |
6 | # Create the venv if it doesn't exist
7 | if ! test -e venv; then
8 | echo "Creating python venv for PiSCSI-Web development"
9 | python3 -m venv venv
10 | echo "Activating venv"
11 | source venv/bin/activate
12 | echo "Installing requirements-dev.txt"
13 | pip3 install wheel
14 | pip3 install -r requirements.txt
15 | fi
16 |
17 | source venv/bin/activate
18 |
19 | pybabel extract -F babel.cfg -o messages.pot src
20 | pybabel update -i messages.pot -d src/translations
21 |
22 | echo
23 | echo "Translation stats:"
24 | find . -name \*.po -print -execdir msgfmt --statistics messages.po \;
25 |
--------------------------------------------------------------------------------
/cpp/scsictl/scsictl_core.h:
--------------------------------------------------------------------------------
1 | //---------------------------------------------------------------------------
2 | //
3 | // SCSI Target Emulator PiSCSI
4 | // for Raspberry Pi
5 | //
6 | // Copyright (C) 2022 Uwe Seimet
7 | //
8 | //---------------------------------------------------------------------------
9 |
10 | #pragma once
11 |
12 | #include "generated/piscsi_interface.pb.h"
13 | #include
14 | #include
15 |
16 | using namespace std;
17 | using namespace piscsi_interface;
18 |
19 | class ScsiCtl
20 | {
21 | public:
22 |
23 | ScsiCtl() = default;
24 | ~ScsiCtl() = default;
25 |
26 | int run(const vector&) const;
27 |
28 | private:
29 |
30 | void Banner(const vector&) const;
31 | };
32 |
--------------------------------------------------------------------------------
/python/ctrlboard/src/ctrlboard_hw/hardware_button.py:
--------------------------------------------------------------------------------
1 | """Module containing an abstraction for the hardware button through the i2c multiplexer"""
2 |
3 |
4 | # pylint: disable=too-few-public-methods
5 | class HardwareButton:
6 | """Class implementing a hardware button interface that uses the i2c multiplexer"""
7 |
8 | def __init__(self, pca_driver, pin):
9 | self.pca_driver = pca_driver
10 | self.pin = pin
11 | self.state = True
12 | self.state_interrupt = True
13 | self.name = "n/a"
14 | self.last_press = None
15 |
16 | def read(self):
17 | """Reads the configured port of the i2c multiplexer"""
18 | return self.pca_driver.read_input_register_port(self.pin)
19 |
--------------------------------------------------------------------------------
/docker/web/web_start_wrapper.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | if ! [[ -f "/home/pi/piscsi/python/common/src/piscsi_interface_pb2.py" ]]; then
4 | # Build piscsi_interface_pb2.py with the protobuf compiler
5 | protoc \
6 | --python_out=/home/pi/piscsi/python/common/src \
7 | --proto_path=/home/pi/piscsi/proto \
8 | /home/pi/piscsi/proto/piscsi_interface.proto
9 | fi
10 |
11 | # Start Nginx service
12 | nginx
13 |
14 | # Use mock commands
15 | export PATH="/home/pi/piscsi/python/web/mock/bin:$PATH"
16 |
17 | # Pass args to web UI start script
18 | if [[ $BACKEND_PASSWORD ]]; then
19 | /home/pi/piscsi/python/web/start.sh "$@" --password=$BACKEND_PASSWORD
20 | else
21 | /home/pi/piscsi/python/web/start.sh "$@"
22 | fi
23 |
--------------------------------------------------------------------------------
/cpp/test/linux_os_stubs.h:
--------------------------------------------------------------------------------
1 | //---------------------------------------------------------------------------
2 | //
3 | // SCSI Target Emulator PiSCSI
4 | // for Raspberry Pi
5 | //
6 | // Copyright (C) 2022 akuker
7 | //
8 | //---------------------------------------------------------------------------
9 |
10 | // This header file should ONLY be used in test procedures. It bypasses the
11 | // standard c library functionality. DO NOT USE THIS IN PRODUCTION CODE.
12 | #pragma once
13 | #include
14 |
15 | extern "C" {
16 | #ifdef __USE_LARGEFILE64
17 | FILE *__real_fopen64(const char *__restrict __filename, const char *__restrict __modes);
18 | #else
19 | FILE *__real_fopen(const char *__restrict __filename, const char *__restrict __modes);
20 | #endif
21 | }
22 |
--------------------------------------------------------------------------------
/cpp/devices/interfaces/scsi_printer_commands.h:
--------------------------------------------------------------------------------
1 | //---------------------------------------------------------------------------
2 | //
3 | // SCSI Target Emulator PiSCSI
4 | // for Raspberry Pi
5 | //
6 | // Copyright (C) 2021-2022 Uwe Seimet
7 | //
8 | // Interface for SCSI printer commands (see SCSI-2 specification)
9 | //
10 | //---------------------------------------------------------------------------
11 |
12 | #pragma once
13 |
14 | class ScsiPrinterCommands
15 | {
16 |
17 | public:
18 |
19 | ScsiPrinterCommands() = default;
20 | virtual ~ScsiPrinterCommands() = default;
21 |
22 | // Mandatory commands
23 | virtual void Print() = 0;
24 | virtual void ReleaseUnit() = 0;
25 | virtual void ReserveUnit() = 0;
26 | virtual void SendDiagnostic() = 0;
27 | };
28 |
--------------------------------------------------------------------------------
/os_integration/piscsi.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=PiSCSI service
3 | After=network.target
4 |
5 | [Service]
6 | Type=simple
7 | Restart=always
8 | ExecStart=/usr/local/bin/piscsi -r 7
9 | # Example 1: If you want to automatically attach a hard disk at startup,
10 | # say an image called harddisk.hds on SCSI ID 1, change the ExecStart line to:
11 | #
12 | # ExecStart=/usr/local/bin/piscsi -ID1 /home/pi/images/harddisk.hds
13 | #
14 | # Example 2: If you want to reserve SCSI IDs to prevent usage, add '-r' followed by
15 | # comma-separated SCSI ID numbers; for instance IDs 0 and 7:
16 | #
17 | # ExecStart=/usr/local/bin/piscsi -r 0,7
18 | #
19 | ExecStop=/usr/local/bin/scsictl -X
20 | SyslogIdentifier=PISCSI
21 |
22 | [Install]
23 | WantedBy=multi-user.target
24 |
25 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: "docker"
4 | directory: "/docker/backend"
5 | schedule:
6 | interval: "weekly"
7 |
8 | - package-ecosystem: "docker"
9 | directory: "/docker/pytest"
10 | schedule:
11 | interval: "weekly"
12 |
13 | - package-ecosystem: "docker"
14 | directory: "/docker/web"
15 | schedule:
16 | interval: "weekly"
17 |
18 | - package-ecosystem: "github-actions"
19 | directory: "/.github/workflows"
20 | schedule:
21 | interval: "weekly"
22 |
23 | - package-ecosystem: "npm"
24 | directory: "/python/web"
25 | schedule:
26 | interval: "weekly"
27 |
28 | - package-ecosystem: "pip"
29 | directory: "/python"
30 | schedule:
31 | interval: "weekly"
32 |
--------------------------------------------------------------------------------
/python/ctrlboard/src/ctrlboard_event_handler/ctrlboard_print_event_handler.py:
--------------------------------------------------------------------------------
1 | """Module for test printing events when buttons from the PiSCSI Control Board are pressed"""
2 |
3 | import observer
4 | from ctrlboard_hw.hardware_button import HardwareButton
5 | from ctrlboard_hw.encoder import Encoder
6 |
7 |
8 | # pylint: disable=too-few-public-methods
9 | class CtrlBoardPrintEventHandler(observer.Observer):
10 | """Class implements a basic event handler that prints button presses from the PiSCSI
11 | Control Board hardware."""
12 |
13 | def update(self, updated_object):
14 | if isinstance(updated_object, HardwareButton):
15 | print(updated_object.name + " has been pressed!")
16 | if isinstance(updated_object, Encoder):
17 | print(updated_object.pos)
18 |
--------------------------------------------------------------------------------
/python/ctrlboard/src/ctrlboard_hw/ctrlboard_hw_constants.py:
--------------------------------------------------------------------------------
1 | """Module containing the PiSCSI Control Board hardware constants"""
2 |
3 |
4 | # pylint: disable=too-few-public-methods
5 | class CtrlBoardHardwareConstants:
6 | """Class containing the PiSCSI Control Board hardware constants"""
7 |
8 | DISPLAY_I2C_ADDRESS = 0x3C
9 | PCA9554_I2C_ADDRESS = 0x3F
10 | PCA9554_PIN_ENC_A = 0
11 | PCA9554_PIN_ENC_B = 1
12 | PCA9554_PIN_BUTTON_1 = 2
13 | PCA9554_PIN_BUTTON_2 = 3
14 | PCA9554_PIN_BUTTON_ROTARY = 5
15 | PCA9554_PIN_LED_1 = 6
16 | PCA9554_PIN_LED_2 = 7
17 |
18 | PI_PIN_INTERRUPT = 9 # BCM
19 |
20 | BUTTON_1 = "Bt1"
21 | BUTTON_2 = "Bt2"
22 | ROTARY_A = "RotA"
23 | ROTARY_B = "RotB"
24 | ROTARY_BUTTON = "RotBtn"
25 | ROTARY = "Rot"
26 |
--------------------------------------------------------------------------------
/python/ctrlboard/src/observable.py:
--------------------------------------------------------------------------------
1 | """Module for Observable part of the Observer pattern functionality"""
2 |
3 | from typing import List
4 | from observer import Observer
5 |
6 |
7 | class Observable:
8 | """Class implementing the Observable pattern"""
9 |
10 | _observers: List[Observer] = []
11 |
12 | def attach(self, observer: Observer):
13 | """Attaches an observer to an obserable object"""
14 | self._observers.append(observer)
15 |
16 | def detach(self, observer: Observer):
17 | """detaches an observer from an observable object"""
18 | self._observers.remove(observer)
19 |
20 | def notify(self, updated_object):
21 | """Notifies all observers with a given object parameter"""
22 | for observer in self._observers:
23 | observer.update(updated_object)
24 |
--------------------------------------------------------------------------------
/python/web/mock/bin/vcgencmd:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Info: https://www.raspberrypi.com/documentation/computers/os.html#vcgencmd
4 | #
5 | # Bit Hex value Meaning
6 | # ----- ----------- ------------------------
7 | # 0 0x1 Under-voltage detected
8 | # 1 0x2 Arm frequency capped
9 | # 2 0x4 Currently throttled
10 | # 3 0x8 Soft temperature limit active
11 | # 16 0x10000 Under-voltage has occurred
12 | # 17 0x20000 Arm frequency capping has occurred
13 | # 18 0x40000 Throttling has occurred
14 | # 19 0x80000 Soft temperature limit has occurred
15 |
16 | if [[ "$1" == "get_throttled" ]]
17 | then
18 | # Return 'Under-voltage detected' & 'Under-voltage has occurred'
19 | echo "throttled=0x10001"
20 | fi
21 |
22 | echo "Mock does not recognize: $0 $@"
23 | exit 1
--------------------------------------------------------------------------------
/cpp/scsiloop/scsiloop_core.h:
--------------------------------------------------------------------------------
1 | //---------------------------------------------------------------------------
2 | //
3 | // SCSI Target Emulator PiSCSI
4 | // for Raspberry Pi
5 | //
6 | // Copyright (C) 2022 Uwe Seimet
7 | // Copyright (C) 2022 akuker
8 | //
9 | //---------------------------------------------------------------------------
10 |
11 | #pragma once
12 |
13 | #include