mirror of https://github.com/akuker/RASCSI.git
Merge branch 'develop' into feature_powerview
This commit is contained in:
commit
d8594a5b03
|
@ -142,12 +142,14 @@ function installRaScsiScreen() {
|
|||
SCREEN_HEIGHT="32"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Is RaSCSI using token-based authentication? [y/N]"
|
||||
read -r REPLY
|
||||
if [ "$REPLY" == "y" ] || [ "$REPLY" == "Y" ]; then
|
||||
echo -n "Enter the passphrase that you configured: "
|
||||
read -r TOKEN
|
||||
if [ -z "$TOKEN" ]; then
|
||||
echo ""
|
||||
echo "Did you protect your RaSCSI installation with a token password? [y/N]"
|
||||
read -r REPLY
|
||||
if [ "$REPLY" == "y" ] || [ "$REPLY" == "Y" ]; then
|
||||
echo -n "Enter the password that you configured with RaSCSI at the time of installation: "
|
||||
read -r TOKEN
|
||||
fi
|
||||
fi
|
||||
|
||||
stopRaScsiScreen
|
||||
|
@ -178,7 +180,7 @@ function installRaScsiScreen() {
|
|||
if [ ! -z "$TOKEN" ]; then
|
||||
sudo sed -i "8 i ExecStart=$BASE/src/oled_monitor/start.sh --rotation=$ROTATION --height=$SCREEN_HEIGHT --password=$TOKEN" "$SYSTEMD_PATH/monitor_rascsi.service"
|
||||
sudo chmod 600 "$SYSTEMD_PATH/monitor_rascsi.service"
|
||||
echo "Granted access to the OLED Monitor with the token passphrase that you configured for RaSCSI."
|
||||
echo "Granted access to the OLED Monitor with the password that you configured for RaSCSI."
|
||||
else
|
||||
sudo sed -i "8 i ExecStart=$BASE/src/oled_monitor/start.sh --rotation=$ROTATION --height=$SCREEN_HEIGHT" "$SYSTEMD_PATH/monitor_rascsi.service"
|
||||
fi
|
||||
|
@ -277,14 +279,14 @@ function backupRaScsiService() {
|
|||
fi
|
||||
}
|
||||
|
||||
# Modifies and installs the rascsi service
|
||||
function enableRaScsiService() {
|
||||
# Offers the choice of enabling token-based authentication for RaSCSI
|
||||
function configureTokenAuth() {
|
||||
echo ""
|
||||
echo "Do you want to enable token-based access control for RaSCSI? [y/N]"
|
||||
echo "Do you want to protect your RaSCSI installation with a password? [y/N]"
|
||||
read REPLY
|
||||
|
||||
if [ "$REPLY" == "y" ] || [ "$REPLY" == "Y" ]; then
|
||||
echo -n "Enter the passphrase that you want to use: "
|
||||
echo -n "Enter the password that you want to use: "
|
||||
read -r TOKEN
|
||||
if [ -f "$HOME/.rascsi_secret" ]; then
|
||||
sudo rm "$HOME/.rascsi_secret"
|
||||
|
@ -293,10 +295,17 @@ function enableRaScsiService() {
|
|||
echo "$TOKEN" > "$HOME/.rascsi_secret"
|
||||
sudo chown root:root "$HOME/.rascsi_secret"
|
||||
sudo chmod 600 "$HOME/.rascsi_secret"
|
||||
echo ""
|
||||
echo "Configured RaSCSI to use $HOME/.rascsi_secret for authentication. This file is readable by root only."
|
||||
echo "Make note of your password: you will need it to use rasctl and other RaSCSI clients."
|
||||
fi
|
||||
}
|
||||
|
||||
# Modifies and installs the rascsi service
|
||||
function enableRaScsiService() {
|
||||
if [ ! -z "$TOKEN" ]; then
|
||||
sudo sed -i "s@^ExecStart.*@& -F $VIRTUAL_DRIVER_PATH -P $HOME/.rascsi_secret@" "$SYSTEMD_PATH/rascsi.service"
|
||||
sudo chmod 600 "$SYSTEMD_PATH/rascsi.service"
|
||||
echo "Configured to use $HOME/.rascsi_secret to secure RaSCSI. This file is readable by root only."
|
||||
echo "Make note of your passphrase; you will need it to use rasctl, and other RaSCSI clients."
|
||||
else
|
||||
sudo sed -i "s@^ExecStart.*@& -F $VIRTUAL_DRIVER_PATH@" "$SYSTEMD_PATH/rascsi.service"
|
||||
fi
|
||||
|
@ -318,7 +327,7 @@ function installWebInterfaceService() {
|
|||
if [ ! -z "$TOKEN" ]; then
|
||||
sudo sed -i "8 i ExecStart=$WEB_INSTALL_PATH/start.sh --password=$TOKEN" "$SYSTEMD_PATH/rascsi-web.service"
|
||||
sudo chmod 600 "$SYSTEMD_PATH/rascsi-web.service"
|
||||
echo "Granted access to the Web Interface with the token passphrase that you configured for RaSCSI."
|
||||
echo "Granted access to the Web Interface with the token password that you configured for RaSCSI."
|
||||
else
|
||||
sudo sed -i "8 i ExecStart=$WEB_INSTALL_PATH/start.sh" "$SYSTEMD_PATH/rascsi-web.service"
|
||||
fi
|
||||
|
@ -724,7 +733,7 @@ function installMacproxy {
|
|||
|
||||
( sudo apt-get update && sudo apt-get install python3 python3-venv --assume-yes ) </dev/null
|
||||
|
||||
MACPROXY_VER="21.12.2"
|
||||
MACPROXY_VER="21.12.3"
|
||||
MACPROXY_PATH="$HOME/macproxy-$MACPROXY_VER"
|
||||
if [ -d "$MACPROXY_PATH" ]; then
|
||||
echo "The $MACPROXY_PATH directory already exists. Delete it to proceed with the installation."
|
||||
|
@ -784,11 +793,13 @@ function runChoice() {
|
|||
echo "- Install additional packages with apt-get"
|
||||
echo "- Add and modify systemd services"
|
||||
echo "- Modify and enable Apache2 and Nginx web services"
|
||||
echo "- Create directories and change permissions"
|
||||
echo "- Create files and directories"
|
||||
echo "- Change permissions of files and directories"
|
||||
echo "- Modify user groups and permissions"
|
||||
echo "- Install binaries to /usr/local/bin"
|
||||
echo "- Install manpages to /usr/local/man"
|
||||
sudoCheck
|
||||
configureTokenAuth
|
||||
stopOldWebInterface
|
||||
updateRaScsiGit
|
||||
createImagesDir
|
||||
|
@ -800,9 +811,13 @@ function runChoice() {
|
|||
backupRaScsiService
|
||||
installRaScsi
|
||||
enableRaScsiService
|
||||
startRaScsiScreen
|
||||
if [ -f "$SYSTEMD_PATH/monitor_rascsi.service" ]; then
|
||||
echo "Detected monitor_rascsi.service; will run the installation steps for the OLED monitor."
|
||||
installRaScsiScreen
|
||||
fi
|
||||
installRaScsiWebInterface
|
||||
installWebInterfaceService
|
||||
showRaScsiScreenStatus
|
||||
showRaScsiStatus
|
||||
showRaScsiWebStatus
|
||||
notifyBackup
|
||||
|
@ -813,11 +828,13 @@ function runChoice() {
|
|||
echo "This script will make the following changes to your system:"
|
||||
echo "- Install additional packages with apt-get"
|
||||
echo "- Add and modify systemd services"
|
||||
echo "- Create directories and change permissions"
|
||||
echo "- Create files ans directories"
|
||||
echo "- Change permissions of files and directories"
|
||||
echo "- Modify user groups and permissions"
|
||||
echo "- Install binaries to /usr/local/bin"
|
||||
echo "- Install manpages to /usr/local/man"
|
||||
sudoCheck
|
||||
configureTokenAuth
|
||||
updateRaScsiGit
|
||||
createImagesDir
|
||||
installPackages
|
||||
|
@ -827,7 +844,11 @@ function runChoice() {
|
|||
backupRaScsiService
|
||||
installRaScsi
|
||||
enableRaScsiService
|
||||
startRaScsiScreen
|
||||
if [ -f "$SYSTEMD_PATH/monitor_rascsi.service" ]; then
|
||||
echo "Detected monitor_rascsi.service; will run the installation steps for the OLED monitor."
|
||||
installRaScsiScreen
|
||||
fi
|
||||
showRaScsiScreenStatus
|
||||
showRaScsiStatus
|
||||
notifyBackup
|
||||
echo "Installing / Updating RaSCSI Service (${CONNECT_TYPE:-FULLSPEC}) - Complete!"
|
||||
|
|
|
@ -15,7 +15,14 @@ ignore-patterns=
|
|||
|
||||
# Python code to execute, usually for sys.path manipulation such as
|
||||
# pygtk.require().
|
||||
#init-hook=
|
||||
init-hook=
|
||||
# venv hook for pylint
|
||||
# Requires pylint-venv package:
|
||||
# $ pip install pylint-venv
|
||||
try: import pylint_venv
|
||||
except ImportError: pass
|
||||
else: pylint_venv.inithook()
|
||||
|
||||
|
||||
# Use multiple processes to speed up Pylint.
|
||||
jobs=1
|
||||
|
|
|
@ -31,8 +31,8 @@
|
|||
THE SOFTWARE.
|
||||
"""
|
||||
import argparse
|
||||
import sys
|
||||
from time import sleep
|
||||
from sys import argv
|
||||
from collections import deque
|
||||
from board import I2C
|
||||
from adafruit_ssd1306 import SSD1306_I2C
|
||||
|
@ -95,20 +95,22 @@ I2C = I2C()
|
|||
|
||||
# 128x32 display with hardware I2C:
|
||||
OLED = SSD1306_I2C(WIDTH, HEIGHT, I2C, addr=0x3C, reset=OLED_RESET)
|
||||
OLED.rotation = ROTATION
|
||||
|
||||
print("Running with the following display:")
|
||||
print(OLED)
|
||||
print()
|
||||
print("Will update the OLED display every " + str(DELAY_TIME_MS) + "ms (approximately)")
|
||||
|
||||
# Clear display.
|
||||
OLED.rotation = ROTATION
|
||||
OLED.fill(0)
|
||||
# Show a startup splash bitmap image before starting the main loop
|
||||
# Convert the image to mode '1' for 1-bit color (monochrome)
|
||||
# Make sure the splash bitmap image is in the same dir as this script
|
||||
IMAGE = Image.open(f"splash_start_{HEIGHT}.bmp").convert("1")
|
||||
OLED.image(IMAGE)
|
||||
OLED.show()
|
||||
|
||||
# Create blank image for drawing.
|
||||
# Make sure to create image with mode '1' for 1-bit color.
|
||||
IMAGE = Image.new("1", (OLED.width, OLED.height))
|
||||
# Keep the pretty splash on screen for a number of seconds
|
||||
sleep(4)
|
||||
|
||||
# Get drawing object to draw on image.
|
||||
DRAW = ImageDraw.Draw(IMAGE)
|
||||
|
@ -138,11 +140,6 @@ LINE_SPACING = 8
|
|||
# Some other nice fonts to try: http://www.dafont.com/bitmap.php
|
||||
FONT = ImageFont.truetype('type_writer.ttf', FONT_SIZE)
|
||||
|
||||
# Load a bitmap image for start and stop splash screens and convert to monocrome
|
||||
# Make sure the splash bitmap image is in the same dir as this script
|
||||
SPLASH_START = Image.open(f"splash_start_{HEIGHT}.bmp").convert("1")
|
||||
SPLASH_STOP = Image.open(f"splash_stop_{HEIGHT}.bmp").convert("1")
|
||||
|
||||
IP_ADDR, HOSTNAME = get_ip_and_host()
|
||||
|
||||
|
||||
|
@ -190,28 +187,7 @@ def formatted_output():
|
|||
return output
|
||||
|
||||
|
||||
def start_splash():
|
||||
"""
|
||||
Displays a splash screen for the startup sequence
|
||||
"""
|
||||
OLED.image(SPLASH_START)
|
||||
OLED.show()
|
||||
sleep(4)
|
||||
|
||||
def stop_splash():
|
||||
"""
|
||||
Displays a splash screen for the shutdown sequence
|
||||
"""
|
||||
OLED.image(SPLASH_STOP)
|
||||
OLED.show()
|
||||
|
||||
# Show a startup splash bitmap image before starting the main loop
|
||||
start_splash()
|
||||
|
||||
with GracefulInterruptHandler() as handler:
|
||||
"""
|
||||
The main loop of displaying attached device info, and other info
|
||||
"""
|
||||
while True:
|
||||
|
||||
# The reference snapshot of attached devices that will be compared against each cycle
|
||||
|
@ -225,10 +201,10 @@ with GracefulInterruptHandler() as handler:
|
|||
while snapshot == ref_snapshot:
|
||||
# Draw a black filled box to clear the image.
|
||||
DRAW.rectangle((0, 0, WIDTH, HEIGHT), outline=0, fill=0)
|
||||
y_pos = TOP
|
||||
Y_POS = TOP
|
||||
for output_line in active_output:
|
||||
DRAW.text((X_POS, y_pos), output_line, font=FONT, fill=255)
|
||||
y_pos += LINE_SPACING
|
||||
DRAW.text((X_POS, Y_POS), output_line, font=FONT, fill=255)
|
||||
Y_POS += LINE_SPACING
|
||||
|
||||
# Shift the index of the array by one to get a scrolling effect
|
||||
if len(active_output) > LINES:
|
||||
|
@ -242,6 +218,8 @@ with GracefulInterruptHandler() as handler:
|
|||
snapshot = formatted_output()
|
||||
|
||||
if handler.interrupted:
|
||||
# Catch interrupt signals and show a shutdown splash bitmap image
|
||||
stop_splash()
|
||||
exit("Shutting down the OLED display...")
|
||||
# Catch interrupt signals and blank out the screen
|
||||
DRAW.rectangle((0, 0, WIDTH, HEIGHT), outline=0, fill=0)
|
||||
OLED.image(IMAGE)
|
||||
OLED.show()
|
||||
sys.exit("Shutting down the OLED display...")
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 574 B |
Binary file not shown.
Before Width: | Height: | Size: 1.1 KiB |
|
@ -66,9 +66,13 @@ fi
|
|||
# Test for two known broken venv states
|
||||
if test -e venv; then
|
||||
GOOD_VENV=true
|
||||
! test -e venv/bin/activate && GOOD_VENV=false
|
||||
pip3 list 1> /dev/null
|
||||
test $? -eq 1 && GOOD_VENV=false
|
||||
if ! test -e venv/bin/activate; then
|
||||
GOOD_VENV=false
|
||||
else
|
||||
source venv/bin/activate
|
||||
pip3 list 1> /dev/null
|
||||
test $? -eq 1 && GOOD_VENV=false
|
||||
fi
|
||||
if ! "$GOOD_VENV"; then
|
||||
echo "Deleting bad python venv"
|
||||
sudo rm -rf venv
|
||||
|
|
|
@ -5,11 +5,14 @@
|
|||
*.layout
|
||||
*.log
|
||||
*.vcd
|
||||
*.json
|
||||
*.html
|
||||
rascsi
|
||||
scsimon
|
||||
rasctl
|
||||
sasidump
|
||||
rasdump
|
||||
scisparse
|
||||
obj
|
||||
bin
|
||||
/rascsi_interface.pb.cpp
|
||||
|
|
|
@ -24,8 +24,13 @@ else
|
|||
CXXFLAGS += -O3 -Wall -Werror -DNDEBUG
|
||||
BUILD_TYPE = Release
|
||||
endif
|
||||
ifeq ("$(shell uname -s)","Linux")
|
||||
# -Wno-psabi might not work on non-Linux platforms
|
||||
CXXFLAGS += -Wno-psabi
|
||||
endif
|
||||
|
||||
CFLAGS += -iquote . -D_FILE_OFFSET_BITS=64 -MD -MP
|
||||
CXXFLAGS += -std=c++17 -Wno-psabi -iquote . -D_FILE_OFFSET_BITS=64 -MD -MP
|
||||
CXXFLAGS += -std=c++17 -iquote . -D_FILE_OFFSET_BITS=64 -MD -MP
|
||||
|
||||
## EXTRA_FLAGS : Can be used to pass special purpose flags
|
||||
CFLAGS += $(EXTRA_FLAGS)
|
||||
|
@ -105,9 +110,8 @@ SRC_SCSIMON = \
|
|||
scsimon.cpp \
|
||||
scsi.cpp \
|
||||
gpiobus.cpp \
|
||||
filepath.cpp \
|
||||
fileio.cpp \
|
||||
rascsi_version.cpp
|
||||
SRC_SCSIMON += $(shell find ./monitor -name '*.cpp')
|
||||
|
||||
SRC_RASCTL = \
|
||||
rasctl.cpp\
|
||||
|
@ -135,8 +139,8 @@ SRC_SASIDUMP = \
|
|||
fileio.cpp\
|
||||
rascsi_version.cpp
|
||||
|
||||
vpath %.h ./ ./controllers ./devices
|
||||
vpath %.cpp ./ ./controllers ./devices
|
||||
vpath %.h ./ ./controllers ./devices ./monitor
|
||||
vpath %.cpp ./ ./controllers ./devices ./monitor
|
||||
vpath %.o ./$(OBJDIR)
|
||||
vpath ./$(BINDIR)
|
||||
|
||||
|
@ -193,6 +197,16 @@ $(BINDIR)/$(SASIDUMP): $(OBJ_SASIDUMP) | $(BINDIR)
|
|||
$(BINDIR)/$(SCSIMON): $(OBJ_SCSIMON) | $(BINDIR)
|
||||
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_SCSIMON) -lpthread
|
||||
|
||||
|
||||
# Phony rules for building individual utilities
|
||||
.PHONY: $(RASCSI) $(RASCTL) $(RASDUMP) $(SASIDUMP) $(SCSIMON)
|
||||
$(RASCSI) : $(BINDIR)/$(RASCSI)
|
||||
$(RASCTL) : $(BINDIR)/$(RASCTL)
|
||||
$(RASDUMP) : $(BINDIR)/$(RASDUMP)
|
||||
$(SASIDUMP): $(BINDIR)/$(SASIDUMP)
|
||||
$(SCSIMON) : $(BINDIR)/$(SCSIMON)
|
||||
|
||||
|
||||
## clean : Remove all of the object files, intermediate
|
||||
## compiler files and executable files
|
||||
.PHONY: clean
|
||||
|
|
|
@ -1385,6 +1385,7 @@ BOOL GPIOBUS::WaitSignal(int pin, BOOL ast)
|
|||
//---------------------------------------------------------------------------
|
||||
void GPIOBUS::DisableIRQ()
|
||||
{
|
||||
#ifdef __linux__
|
||||
if (rpitype == 4) {
|
||||
// RPI4 is disabled by GICC
|
||||
giccpmr = gicc[GICC_PMR];
|
||||
|
@ -1399,6 +1400,9 @@ void GPIOBUS::DisableIRQ()
|
|||
irptenb = irpctl[IRPT_ENB_IRQ_1];
|
||||
irpctl[IRPT_DIS_IRQ_1] = irptenb & 0xf;
|
||||
}
|
||||
#else
|
||||
(void)0;
|
||||
#endif
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
|
|
@ -19,72 +19,114 @@ using namespace std;
|
|||
Localizer::Localizer()
|
||||
{
|
||||
// Supported locales, always lower case
|
||||
supported_languages = { "en", "de", "sv" };
|
||||
supported_languages = { "en", "de", "sv", "fr", "es" };
|
||||
|
||||
// Positional string arguments are %1, %2, %3
|
||||
Add(ERROR_AUTHENTICATION, "en", "Authentication failed");
|
||||
Add(ERROR_AUTHENTICATION, "de", "Authentifizierung fehlgeschlagen");
|
||||
Add(ERROR_AUTHENTICATION, "sv", "Autentisering misslyckades");
|
||||
Add(ERROR_AUTHENTICATION, "fr", "Authentification éronnée");
|
||||
Add(ERROR_AUTHENTICATION, "es", "Fallo de autentificación");
|
||||
Add(ERROR_OPERATION, "en", "Unknown operation");
|
||||
Add(ERROR_OPERATION, "de", "Unbekannte Operation");
|
||||
Add(ERROR_OPERATION, "sv", "Okänd operation");
|
||||
Add(ERROR_OPERATION, "fr", "Opération inconnue");
|
||||
Add(ERROR_OPERATION, "es", "Operación desconocida");
|
||||
Add(ERROR_LOG_LEVEL, "en", "Invalid log level %1");
|
||||
Add(ERROR_LOG_LEVEL, "de", "Ungültiger Log-Level %1");
|
||||
Add(ERROR_LOG_LEVEL, "sv", "Ogiltig loggnivå %1");
|
||||
Add(ERROR_LOG_LEVEL, "fr", "Niveau de journalisation invalide %1");
|
||||
Add(ERROR_LOG_LEVEL, "es", "Nivel de registro %1 no válido");
|
||||
Add(ERROR_MISSING_DEVICE_ID, "en", "Missing device ID");
|
||||
Add(ERROR_MISSING_DEVICE_ID, "de", "Fehlende Geräte-ID");
|
||||
Add(ERROR_MISSING_DEVICE_ID, "sv", "Enhetens ID saknas");
|
||||
Add(ERROR_MISSING_DEVICE_ID, "fr", "ID de périphérique manquante");
|
||||
Add(ERROR_MISSING_DEVICE_ID, "es", "Falta el ID del dispositivo");
|
||||
Add(ERROR_MISSING_FILENAME, "en", "Missing filename");
|
||||
Add(ERROR_MISSING_FILENAME, "de", "Fehlender Dateiname");
|
||||
Add(ERROR_MISSING_FILENAME, "sv", "Filnamn saknas");
|
||||
Add(ERROR_MISSING_FILENAME, "fr", "Nom de fichier manquant");
|
||||
Add(ERROR_MISSING_FILENAME, "es", "Falta el nombre del archivo");
|
||||
Add(ERROR_IMAGE_IN_USE, "en", "Image file '%1' is already being used by ID %2, unit %3");
|
||||
Add(ERROR_IMAGE_IN_USE, "de", "Image-Datei '%1' wird bereits von ID %2, Einheit %3 benutzt");
|
||||
Add(ERROR_IMAGE_IN_USE, "sv", "Skivbildfilen '%1' används redan av ID %2, LUN %3");
|
||||
Add(ERROR_IMAGE_IN_USE, "fr", "Le fichier d'image '%1' est déjà utilisé par l'ID %2, unité %3");
|
||||
Add(ERROR_IMAGE_IN_USE, "es", "El archivo de imagen '%1' ya está siendo utilizado por el ID %2, unidad %3");
|
||||
Add(ERROR_RESERVED_ID, "en", "Device ID %1 is reserved");
|
||||
Add(ERROR_RESERVED_ID, "de", "Geräte-ID %1 ist reserviert");
|
||||
Add(ERROR_RESERVED_ID, "sv", "Enhets-ID %1 är reserverat");
|
||||
Add(ERROR_RESERVED_ID, "fr", "ID de périphérique %1 réservée");
|
||||
Add(ERROR_RESERVED_ID, "es", "El ID de dispositivo %1 está reservado");
|
||||
Add(ERROR_NON_EXISTING_DEVICE, "en", "Command for non-existing ID %1");
|
||||
Add(ERROR_NON_EXISTING_DEVICE, "de", "Kommando für nicht existente ID %1");
|
||||
Add(ERROR_NON_EXISTING_DEVICE, "sv", "Kommando för avsaknat ID %1");
|
||||
Add(ERROR_NON_EXISTING_DEVICE, "fr", "Commande pour ID %1 non-existant");
|
||||
Add(ERROR_NON_EXISTING_DEVICE, "es", "Comando para ID %1 no existente");
|
||||
Add(ERROR_NON_EXISTING_UNIT, "en", "Command for non-existing ID %1, unit %2");
|
||||
Add(ERROR_NON_EXISTING_UNIT, "de", "Kommando für nicht existente ID %1, Einheit %2");
|
||||
Add(ERROR_NON_EXISTING_UNIT, "sv", "Kommando för avsaknat ID %1, LUN %2");
|
||||
Add(ERROR_NON_EXISTING_UNIT, "fr", "Command pour ID %1, unité %2 non-existant");
|
||||
Add(ERROR_NON_EXISTING_UNIT, "es", "Comando para ID %1 inexistente, unidad %2");
|
||||
Add(ERROR_UNKNOWN_DEVICE_TYPE, "en", "Unknown device type %1");
|
||||
Add(ERROR_UNKNOWN_DEVICE_TYPE, "de", "Unbekannter Gerätetyp %1");
|
||||
Add(ERROR_UNKNOWN_DEVICE_TYPE, "sv", "Obekant enhetstyp: %1");
|
||||
Add(ERROR_UNKNOWN_DEVICE_TYPE, "fr", "Type de périphérique inconnu %1");
|
||||
Add(ERROR_UNKNOWN_DEVICE_TYPE, "es", "Tipo de dispositivo desconocido %1");
|
||||
Add(ERROR_MISSING_DEVICE_TYPE, "en", "Device type required for unknown extension of file '%1'");
|
||||
Add(ERROR_MISSING_DEVICE_TYPE, "de", "Gerätetyp erforderlich für unbekannte Extension der Datei '%1'");
|
||||
Add(ERROR_MISSING_DEVICE_TYPE, "sv", "Man måste ange enhetstyp för obekant filändelse '%1'");
|
||||
Add(ERROR_MISSING_DEVICE_TYPE, "fr", "Type de périphérique requis pour extension inconnue du fichier '%1'");
|
||||
Add(ERROR_MISSING_DEVICE_TYPE, "es", "Tipo de dispositivo requerido para la extensión desconocida del archivo '%1'");
|
||||
Add(ERROR_DUPLICATE_ID, "en", "Duplicate ID %1, unit %2");
|
||||
Add(ERROR_DUPLICATE_ID, "de", "Doppelte ID %1, Einheit %2");
|
||||
Add(ERROR_DUPLICATE_ID, "sv", "Duplikat ID %1, LUN %2");
|
||||
Add(ERROR_DUPLICATE_ID, "fr", "ID %1, unité %2 dupliquée");
|
||||
Add(ERROR_DUPLICATE_ID, "es", "ID duplicado %1, unidad %2");
|
||||
Add(ERROR_SASI_SCSI, "en", "SASI and SCSI can't be used at the same time");
|
||||
Add(ERROR_SASI_SCSI, "de", "SASI und SCSI können nicht gleichzeitig verwendet werden");
|
||||
Add(ERROR_SASI_SCSI, "sv", "SASI och SCSI kan ej användas samtidigt");
|
||||
Add(ERROR_SASI_SCSI, "fr", "SASI et SCSI ne peuvent être utilisés en même temps");
|
||||
Add(ERROR_SASI_SCSI, "es", "SASI y SCSI no pueden utilizarse al mismo tiempo");
|
||||
Add(ERROR_EJECT_REQUIRED, "en", "Existing medium must first be ejected");
|
||||
Add(ERROR_EJECT_REQUIRED, "de", "Das vorhandene Medium muss erst ausgeworfen werden");
|
||||
Add(ERROR_EJECT_REQUIRED, "sv", "Nuvarande skiva måste utmatas först");
|
||||
Add(ERROR_EJECT_REQUIRED, "fr", "Media déjà existant doit d'abord être éjecté");
|
||||
Add(ERROR_EJECT_REQUIRED, "es", "El medio existente debe ser expulsado primero");
|
||||
Add(ERROR_DEVICE_NAME_UPDATE, "en", "Once set the device name cannot be changed anymore");
|
||||
Add(ERROR_DEVICE_NAME_UPDATE, "de", "Ein bereits gesetzter Gerätename kann nicht mehr geändert werden");
|
||||
Add(ERROR_DEVICE_NAME_UPDATE, "sv", "Enhetsnamn kan ej ändras efter att ha fastställts en gång");
|
||||
Add(ERROR_DEVICE_NAME_UPDATE, "fr", "Une fois défini, le nom de périphérique ne peut plus être changé");
|
||||
Add(ERROR_DEVICE_NAME_UPDATE, "es", "Una vez establecido el nombre del dispositivo ya no se puede cambiar");
|
||||
Add(ERROR_SHUTDOWN_MODE_MISSING, "en", "Missing shutdown mode");
|
||||
Add(ERROR_SHUTDOWN_MODE_MISSING, "de", "Fehlender Shutdown-Modus");
|
||||
Add(ERROR_SHUTDOWN_MODE_MISSING, "sv", "Avstängningsläge saknas");
|
||||
Add(ERROR_SHUTDOWN_MODE_MISSING, "fr", "Mode d'extinction manquant");
|
||||
Add(ERROR_SHUTDOWN_MODE_MISSING, "es", "Falta el modo de apagado");
|
||||
Add(ERROR_SHUTDOWN_MODE_INVALID, "en", "Invalid shutdown mode '%1'");
|
||||
Add(ERROR_SHUTDOWN_MODE_INVALID, "de", "Ungültiger Shutdown-Modus '%1'");
|
||||
Add(ERROR_SHUTDOWN_MODE_INVALID, "sv", "Ogiltigt avstängsningsläge: '%1'");
|
||||
Add(ERROR_SHUTDOWN_MODE_INVALID, "fr", "Mode d'extinction invalide '%1'");
|
||||
Add(ERROR_SHUTDOWN_MODE_INVALID, "es", "Modo de apagado inválido '%1'");
|
||||
Add(ERROR_SHUTDOWN_PERMISSION, "en", "Missing root permission for shutdown or reboot");
|
||||
Add(ERROR_SHUTDOWN_PERMISSION, "de", "Fehlende Root-Berechtigung für Shutdown oder Neustart");
|
||||
Add(ERROR_SHUTDOWN_PERMISSION, "sv", "Root-rättigheter saknas för att kunna stänga av eller starta om systemet");
|
||||
Add(ERROR_SHUTDOWN_PERMISSION, "fr", "Permissions root manquantes pour extinction ou redémarrage");
|
||||
Add(ERROR_SHUTDOWN_PERMISSION, "es", "Falta el permiso de root para el apagado o el reinicio");
|
||||
Add(ERROR_FILE_OPEN, "en", "Invalid or non-existing file '%1': %2");
|
||||
Add(ERROR_FILE_OPEN, "de", "Ungültige oder fehlende Datei '%1': %2");
|
||||
Add(ERROR_FILE_OPEN, "sv", "Ogiltig eller saknad fil '%1': %2");
|
||||
Add(ERROR_FILE_OPEN, "fr", "Fichier invalide ou non-existant '%1': %2");
|
||||
Add(ERROR_FILE_OPEN, "es", "Archivo inválido o inexistente '%1': %2");
|
||||
Add(ERROR_BLOCK_SIZE, "en", "Invalid block size %1 bytes");
|
||||
Add(ERROR_BLOCK_SIZE, "de", "Ungültige Blockgröße %1 Bytes");
|
||||
Add(ERROR_BLOCK_SIZE, "sv", "Ogiltig blockstorlek: %1 byte");
|
||||
Add(ERROR_BLOCK_SIZE, "fr", "Taille de bloc invalide %1 octets");
|
||||
Add(ERROR_BLOCK_SIZE, "es", "Tamaño de bloque inválido %1 bytes");
|
||||
Add(ERROR_BLOCK_SIZE_NOT_CONFIGURABLE, "en", "Block size for device type %1 is not configurable");
|
||||
Add(ERROR_BLOCK_SIZE_NOT_CONFIGURABLE, "de", "Blockgröße für Gerätetyp %1 ist nicht konfigurierbar");
|
||||
Add(ERROR_BLOCK_SIZE_NOT_CONFIGURABLE, "sv", "Enhetstypen %1 kan inte använda andra blockstorlekar");
|
||||
Add(ERROR_BLOCK_SIZE_NOT_CONFIGURABLE, "fr", "Taille de block pour le type de périphérique %1 non configurable");
|
||||
Add(ERROR_BLOCK_SIZE_NOT_CONFIGURABLE, "es", "El tamaño del bloque para el tipo de dispositivo %1 no es configurable");
|
||||
}
|
||||
|
||||
void Localizer::Add(LocalizationKey key, const string& locale, const string& value)
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI (*^..^*) for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2020-2021 akuker
|
||||
//
|
||||
// [ SCSI Bus Monitor ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
#include "os.h"
|
||||
#include "scsi.h"
|
||||
#include "data_sample.h"
|
||||
|
||||
const char *GetPhaseStr(const data_capture *sample)
|
||||
{
|
||||
return BUS::GetPhaseStrRaw(GetPhase(sample));
|
||||
}
|
||||
|
||||
BUS::phase_t GetPhase(const data_capture *sample)
|
||||
{
|
||||
// Selection Phase
|
||||
if (GetSel(sample))
|
||||
{
|
||||
return BUS::selection;
|
||||
}
|
||||
|
||||
// Bus busy phase
|
||||
if (!GetBsy(sample))
|
||||
{
|
||||
return BUS::busfree;
|
||||
}
|
||||
|
||||
// Get target phase from bus signal line
|
||||
DWORD mci = GetMsg(sample) ? 0x04 : 0x00;
|
||||
mci |= GetCd(sample) ? 0x02 : 0x00;
|
||||
mci |= GetIo(sample) ? 0x01 : 0x00;
|
||||
return BUS::GetPhase(mci);
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI (*^..^*)
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2020-2021 akuker
|
||||
//
|
||||
// [ SCSI Bus Monitor ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "scsi.h"
|
||||
#include "gpiobus.h"
|
||||
|
||||
typedef struct data_capture
|
||||
{
|
||||
DWORD data;
|
||||
uint64_t timestamp;
|
||||
} data_capture_t;
|
||||
|
||||
#define GET_PIN(SAMPLE, PIN) ((bool)((SAMPLE->data >> PIN) & 1))
|
||||
|
||||
inline bool GetBsy(const data_capture *sample) { return BUS::GetPinRaw(sample->data, PIN_BSY); }
|
||||
inline bool GetSel(const data_capture *sample) { return BUS::GetPinRaw(sample->data, PIN_SEL); }
|
||||
inline bool GetAtn(const data_capture *sample) { return BUS::GetPinRaw(sample->data, PIN_ATN); }
|
||||
inline bool GetAck(const data_capture *sample) { return BUS::GetPinRaw(sample->data, PIN_ACK); }
|
||||
inline bool GetRst(const data_capture *sample) { return BUS::GetPinRaw(sample->data, PIN_RST); }
|
||||
inline bool GetMsg(const data_capture *sample) { return BUS::GetPinRaw(sample->data, PIN_MSG); }
|
||||
inline bool GetCd(const data_capture *sample) { return BUS::GetPinRaw(sample->data, PIN_CD); }
|
||||
inline bool GetIo(const data_capture *sample) { return BUS::GetPinRaw(sample->data, PIN_IO); }
|
||||
inline bool GetReq(const data_capture *sample) { return BUS::GetPinRaw(sample->data, PIN_REQ); }
|
||||
inline bool GetDp(const data_capture *sample) { return BUS::GetPinRaw(sample->data, PIN_DP); }
|
||||
inline BYTE GetData(const data_capture *sample)
|
||||
{
|
||||
DWORD data = sample->data;
|
||||
return (BYTE)((data >> (PIN_DT0 - 0)) & (1 << 0)) |
|
||||
((data >> (PIN_DT1 - 1)) & (1 << 1)) |
|
||||
((data >> (PIN_DT2 - 2)) & (1 << 2)) |
|
||||
((data >> (PIN_DT3 - 3)) & (1 << 3)) |
|
||||
((data >> (PIN_DT4 - 4)) & (1 << 4)) |
|
||||
((data >> (PIN_DT5 - 5)) & (1 << 5)) |
|
||||
((data >> (PIN_DT6 - 6)) & (1 << 6)) |
|
||||
((data >> (PIN_DT7 - 7)) & (1 << 7));
|
||||
}
|
||||
|
||||
const char *GetPhaseStr(const data_capture *sample);
|
||||
BUS::phase_t GetPhase(const data_capture *sample);
|
|
@ -0,0 +1,205 @@
|
|||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI (*^..^*)
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Powered by XM6 TypeG Technology.
|
||||
// Copyright (C) 2016-2020 GIMONS
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include "os.h"
|
||||
#include "log.h"
|
||||
#include "sm_reports.h"
|
||||
#include "rascsi_version.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
const static string html_header = R"(
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
table, th, td {
|
||||
border: 1px solid black;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
h1 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
h2 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
h3 {
|
||||
text-align: center;
|
||||
}
|
||||
pre {
|
||||
text-align: center;
|
||||
}
|
||||
.collapsible {
|
||||
background-color: #777;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
border: none;
|
||||
text-align: left;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.active, .collapsible:hover {
|
||||
background-color: #555;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 0;
|
||||
display: none;
|
||||
overflow: hidden;
|
||||
background-color: #f1f1f1;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
)";
|
||||
|
||||
static void print_copyright_info(ofstream& html_fp)
|
||||
{
|
||||
html_fp << "<table>" << endl \
|
||||
<< "<h1>RaSCSI scsimon Capture Tool</h1>" << endl \
|
||||
<< "<pre>Version " << rascsi_get_version_string() \
|
||||
<< __DATE__ << " " << __TIME__ << endl \
|
||||
<< "Copyright (C) 2016-2020 GIMONS" << endl \
|
||||
<< "Copyright (C) 2020-2021 Contributors to the RaSCSI project" << endl \
|
||||
<< "</pre></table>" << endl \
|
||||
<< "<br>" << endl;
|
||||
}
|
||||
|
||||
static const string html_footer = R"(
|
||||
</table>
|
||||
<script>
|
||||
var coll = document.getElementsByClassName("collapsible");
|
||||
var i;
|
||||
|
||||
for (i = 0; i < coll.length; i++) {
|
||||
coll[i].addEventListener("click", function() {
|
||||
this.classList.toggle("active");
|
||||
var content = this.nextElementSibling;
|
||||
if (content.style.display === "block") {
|
||||
content.style.display = "none";
|
||||
} else {
|
||||
content.style.display = "block";
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</html>
|
||||
)";
|
||||
|
||||
|
||||
static void print_html_data(ofstream& html_fp, const data_capture *data_capture_array, DWORD capture_count)
|
||||
{
|
||||
const data_capture *data;
|
||||
bool prev_data_valid = false;
|
||||
bool curr_data_valid;
|
||||
DWORD selected_id = 0;
|
||||
BUS::phase_t prev_phase = BUS::busfree;
|
||||
bool close_row = false;
|
||||
int data_space_count = 0;
|
||||
bool collapsible_div_active = false;
|
||||
bool button_active = false;
|
||||
|
||||
html_fp << "<table>" << endl;
|
||||
|
||||
for (DWORD idx = 0; idx < capture_count; idx++)
|
||||
{
|
||||
data = &data_capture_array[idx];
|
||||
curr_data_valid = GetAck(data) && GetReq(data);
|
||||
BUS::phase_t phase = GetPhase(data);
|
||||
if (phase == BUS::selection && !GetBsy(data))
|
||||
{
|
||||
selected_id = GetData(data);
|
||||
}
|
||||
if (prev_phase != phase)
|
||||
{
|
||||
if (close_row)
|
||||
{
|
||||
if (collapsible_div_active)
|
||||
{
|
||||
html_fp << "</code></div>";
|
||||
}
|
||||
else if (button_active)
|
||||
{
|
||||
html_fp << "</code></button>";
|
||||
}
|
||||
html_fp << "</td>";
|
||||
if (data_space_count < 1)
|
||||
{
|
||||
html_fp << "<td>--</td>";
|
||||
}
|
||||
else
|
||||
{
|
||||
html_fp << "<td>wc: " << std::dec << "(0x" << std::hex << data_space_count << ")</td>";
|
||||
}
|
||||
html_fp << "</tr>" << endl;
|
||||
data_space_count = 0;
|
||||
}
|
||||
html_fp << "<tr>";
|
||||
close_row = true; // Close the row the next time around
|
||||
html_fp << "<td>" << (double)data->timestamp / 100000 << "</td>";
|
||||
html_fp << "<td>" << GetPhaseStr(data) << "</td>";
|
||||
html_fp << "<td>" << std::hex << selected_id << "</td>";
|
||||
html_fp << "<td>";
|
||||
}
|
||||
if (curr_data_valid && !prev_data_valid)
|
||||
{
|
||||
if (data_space_count == 0)
|
||||
{
|
||||
button_active = true;
|
||||
html_fp << "<button type=\"button\" class=\"collapsible\"><code>";
|
||||
}
|
||||
if ((data_space_count % 16) == 0)
|
||||
{
|
||||
html_fp << std::hex << data_space_count << ": ";
|
||||
}
|
||||
|
||||
html_fp << fmt::format("{0:02X}", GetData(data));
|
||||
|
||||
data_space_count++;
|
||||
if ((data_space_count % 4) == 0)
|
||||
{
|
||||
html_fp << " ";
|
||||
}
|
||||
if (data_space_count == 16)
|
||||
{
|
||||
html_fp << "</code></button><div class=\"content\"><code>" << endl;
|
||||
collapsible_div_active = true;
|
||||
button_active = false;
|
||||
}
|
||||
if (((data_space_count % 16) == 0) && (data_space_count > 17))
|
||||
{
|
||||
html_fp << "<br>" << endl;
|
||||
}
|
||||
}
|
||||
prev_data_valid = curr_data_valid;
|
||||
prev_phase = phase;
|
||||
}
|
||||
}
|
||||
|
||||
void scsimon_generate_html(const char *filename, const data_capture *data_capture_array, DWORD capture_count)
|
||||
{
|
||||
LOGINFO("Creating HTML report file (%s)", filename);
|
||||
|
||||
ofstream html_ofstream;
|
||||
|
||||
html_ofstream.open(filename, ios::out);
|
||||
|
||||
html_ofstream << html_header;
|
||||
print_copyright_info(html_ofstream);
|
||||
print_html_data(html_ofstream, data_capture_array, capture_count);
|
||||
|
||||
html_ofstream << html_footer;
|
||||
|
||||
html_ofstream.close();
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI (*^..^*)
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Powered by XM6 TypeG Technology.
|
||||
// Copyright (C) 2016-2020 GIMONS
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "sm_reports.h"
|
||||
#include "log.h"
|
||||
#include "spdlog/spdlog.h"
|
||||
#include "string.h"
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
using namespace std;
|
||||
|
||||
const char timestamp_label[] = "\"timestamp\":\"0x";
|
||||
const char data_label[] = "\"data\":\"0x";
|
||||
|
||||
DWORD scsimon_read_json(const char *json_filename, data_capture *data_capture_array, DWORD max_sz)
|
||||
{
|
||||
char str_buf[1024];
|
||||
FILE *fp = fopen(json_filename, "r");
|
||||
DWORD sample_count = 0;
|
||||
|
||||
while (fgets(str_buf, sizeof(str_buf), fp))
|
||||
{
|
||||
|
||||
char timestamp[1024];
|
||||
char data[1024];
|
||||
uint64_t timestamp_uint;
|
||||
uint32_t data_uint;
|
||||
char *ptr;
|
||||
|
||||
char *timestamp_str;
|
||||
char *data_str;
|
||||
timestamp_str = strstr(str_buf, timestamp_label);
|
||||
if (!timestamp_str)
|
||||
continue;
|
||||
strncpy(timestamp, ×tamp_str[strlen(timestamp_label)], 16);
|
||||
timestamp[16] = '\0';
|
||||
timestamp_uint = strtoull(timestamp, &ptr, 16);
|
||||
|
||||
data_str = strstr(str_buf, data_label);
|
||||
if (!data_str)
|
||||
continue;
|
||||
strncpy(data, &data_str[strlen(data_label)], 8);
|
||||
data[8] = '\0';
|
||||
data_uint = strtoul(data, &ptr, 16);
|
||||
|
||||
// printf("Time: %016llX Data: %08X\n", timestamp_uint, data_uint);
|
||||
|
||||
data_capture_array[sample_count].timestamp = timestamp_uint;
|
||||
data_capture_array[sample_count].data = data_uint;
|
||||
sample_count++;
|
||||
if (sample_count >= max_sz)
|
||||
{
|
||||
LOGWARN("File exceeds maximum buffer size. Some data may be missing.");
|
||||
LOGWARN("Try re-running the tool with a larger buffer size");
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
return sample_count;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Generate JSON Output File
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void scsimon_generate_json(const char *filename, const data_capture *data_capture_array, DWORD capture_count)
|
||||
{
|
||||
LOGTRACE("Creating JSON file (%s)", filename);
|
||||
ofstream json_ofstream;
|
||||
json_ofstream.open(filename, ios::out);
|
||||
|
||||
json_ofstream << "[" << endl;
|
||||
|
||||
DWORD i = 0;
|
||||
while (i < capture_count)
|
||||
{
|
||||
json_ofstream << fmt::format("{{\"id\": \"{0:d}\", \"timestamp\":\"{1:#016x}\", \"data\":\"{2:#08x}\"}}", i, data_capture_array[i].timestamp, data_capture_array[i].data);
|
||||
|
||||
if (i != (capture_count - 1))
|
||||
{
|
||||
json_ofstream << ",";
|
||||
}
|
||||
json_ofstream << endl;
|
||||
i++;
|
||||
}
|
||||
json_ofstream << "]" << endl;
|
||||
json_ofstream.close();
|
||||
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI (*^..^*) for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2020-2021 akuker
|
||||
//
|
||||
// [ SCSI Bus Monitor ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "data_sample.h"
|
||||
|
||||
DWORD scsimon_read_json(const char *json_filename, data_capture *data_capture_array, DWORD max_sz);
|
||||
|
||||
void scsimon_generate_html(const char *filename, const data_capture *data_capture_array, DWORD capture_count);
|
||||
void scsimon_generate_json(const char *filename, const data_capture *data_capture_array, DWORD capture_count);
|
||||
void scsimon_generate_value_change_dump(const char *filename, const data_capture *data_capture_array, DWORD capture_count);
|
|
@ -0,0 +1,187 @@
|
|||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI (*^..^*) for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2020-2021 akuker
|
||||
//
|
||||
// [ SCSI Bus Monitor ]
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "os.h"
|
||||
#include "log.h"
|
||||
#include "spdlog/spdlog.h"
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include "data_sample.h"
|
||||
#include "sm_reports.h"
|
||||
#include "gpiobus.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Constant declarations
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
// Symbol definition for the VCD file
|
||||
// These are just arbitrary symbols. They can be anything allowed by the VCD file format,
|
||||
// as long as they're consistently used.
|
||||
const char SYMBOL_PIN_DAT = '#';
|
||||
const char SYMBOL_PIN_ATN = '+';
|
||||
const char SYMBOL_PIN_RST = '$';
|
||||
const char SYMBOL_PIN_ACK = '%';
|
||||
const char SYMBOL_PIN_REQ = '^';
|
||||
const char SYMBOL_PIN_MSG = '&';
|
||||
const char SYMBOL_PIN_CD = '*';
|
||||
const char SYMBOL_PIN_IO = '(';
|
||||
const char SYMBOL_PIN_BSY = ')';
|
||||
const char SYMBOL_PIN_SEL = '-';
|
||||
const char SYMBOL_PIN_PHASE = '=';
|
||||
|
||||
// We'll use position 0 in the prev_value array to store the previous phase
|
||||
#define PIN_PHASE 0
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Variable declarations
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
static BYTE prev_value[32] = {0xFF};
|
||||
|
||||
extern double ns_per_loop;
|
||||
|
||||
static BOOL get_pin_value(DWORD data, int pin)
|
||||
{
|
||||
return (data >> pin) & 1;
|
||||
}
|
||||
|
||||
static BYTE get_data_field(DWORD data)
|
||||
{
|
||||
DWORD data_out =
|
||||
((data >> (PIN_DT0 - 0)) & (1 << 7)) |
|
||||
((data >> (PIN_DT1 - 1)) & (1 << 6)) |
|
||||
((data >> (PIN_DT2 - 2)) & (1 << 5)) |
|
||||
((data >> (PIN_DT3 - 3)) & (1 << 4)) |
|
||||
((data >> (PIN_DT4 - 4)) & (1 << 3)) |
|
||||
((data >> (PIN_DT5 - 5)) & (1 << 2)) |
|
||||
((data >> (PIN_DT6 - 6)) & (1 << 1)) |
|
||||
((data >> (PIN_DT7 - 7)) & (1 << 0));
|
||||
|
||||
return (BYTE)data_out;
|
||||
}
|
||||
|
||||
static void vcd_output_if_changed_phase(ofstream& fp, DWORD data, int pin, char symbol)
|
||||
{
|
||||
BUS::phase_t new_value = GPIOBUS::GetPhaseRaw(data);
|
||||
if (prev_value[pin] != new_value)
|
||||
{
|
||||
prev_value[pin] = new_value;
|
||||
fp << "s" << GPIOBUS::GetPhaseStrRaw(new_value) << " " << symbol << endl;
|
||||
}
|
||||
}
|
||||
|
||||
static void vcd_output_if_changed_bool(ofstream& fp, DWORD data, int pin, char symbol)
|
||||
{
|
||||
BOOL new_value = get_pin_value(data, pin);
|
||||
if (prev_value[pin] != new_value)
|
||||
{
|
||||
prev_value[pin] = new_value;
|
||||
fp << new_value << symbol << endl;
|
||||
}
|
||||
}
|
||||
|
||||
static void vcd_output_if_changed_byte(ofstream& fp, DWORD data, int pin, char symbol)
|
||||
{
|
||||
BYTE new_value = get_data_field(data);
|
||||
if (prev_value[pin] != new_value)
|
||||
{
|
||||
prev_value[pin] = new_value;
|
||||
fp << "b"
|
||||
<< fmt::format("{0:b}", get_pin_value(data, PIN_DT7))
|
||||
<< fmt::format("{0:b}", get_pin_value(data, PIN_DT6))
|
||||
<< fmt::format("{0:b}", get_pin_value(data, PIN_DT5))
|
||||
<< fmt::format("{0:b}", get_pin_value(data, PIN_DT4))
|
||||
<< fmt::format("{0:b}", get_pin_value(data, PIN_DT3))
|
||||
<< fmt::format("{0:b}", get_pin_value(data, PIN_DT2))
|
||||
<< fmt::format("{0:b}", get_pin_value(data, PIN_DT1))
|
||||
<< fmt::format("{0:b}", get_pin_value(data, PIN_DT0))
|
||||
<< " " << symbol << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void scsimon_generate_value_change_dump(const char *filename, const data_capture *data_capture_array, DWORD capture_count)
|
||||
{
|
||||
LOGTRACE("Creating Value Change Dump file (%s)", filename);
|
||||
ofstream vcd_ofstream;
|
||||
vcd_ofstream.open(filename, ios::out);
|
||||
|
||||
// Get the current time
|
||||
time_t rawtime;
|
||||
time(&rawtime);
|
||||
struct tm *timeinfo = localtime(&rawtime);
|
||||
char timestamp[256];
|
||||
strftime(timestamp, sizeof(timestamp), "%d-%m-%Y %H-%M-%S", timeinfo);
|
||||
|
||||
vcd_ofstream
|
||||
<< "$date" << endl
|
||||
<< timestamp << endl
|
||||
<< "$end" << endl
|
||||
<< "$version" << endl
|
||||
<< " VCD generator tool version info text." << endl
|
||||
<< "$end" << endl
|
||||
<< "$comment" << endl
|
||||
<< " Tool build date:" << __TIMESTAMP__ << endl
|
||||
<< "$end" << endl
|
||||
<< "$timescale 1 ns $end" << endl
|
||||
<< "$scope module logic $end" << endl
|
||||
<< "$var wire 1 " << SYMBOL_PIN_BSY << " BSY $end" << endl
|
||||
<< "$var wire 1 " << SYMBOL_PIN_SEL << " SEL $end" << endl
|
||||
<< "$var wire 1 " << SYMBOL_PIN_CD << " CD $end" << endl
|
||||
<< "$var wire 1 " << SYMBOL_PIN_IO << " IO $end"<< endl
|
||||
<< "$var wire 1 " << SYMBOL_PIN_MSG << " MSG $end"<< endl
|
||||
<< "$var wire 1 " << SYMBOL_PIN_REQ << " REQ $end" << endl
|
||||
<< "$var wire 1 " << SYMBOL_PIN_ACK << " ACK $end" << endl
|
||||
<< "$var wire 1 " << SYMBOL_PIN_ATN << " ATN $end" << endl
|
||||
<< "$var wire 1 " << SYMBOL_PIN_RST << " RST $end" << endl
|
||||
<< "$var wire 8 " << SYMBOL_PIN_DAT << " data $end" << endl
|
||||
<< "$var string 1 " << SYMBOL_PIN_PHASE << " phase $end" << endl
|
||||
<< "$upscope $end" << endl
|
||||
<< "$enddefinitions $end" << endl;
|
||||
|
||||
// Initial values - default to zeros
|
||||
vcd_ofstream
|
||||
<< "$dumpvars" << endl
|
||||
<< "0" << SYMBOL_PIN_BSY << endl
|
||||
<< "0" << SYMBOL_PIN_SEL << endl
|
||||
<< "0" << SYMBOL_PIN_CD << endl
|
||||
<< "0" << SYMBOL_PIN_IO << endl
|
||||
<< "0" << SYMBOL_PIN_MSG << endl
|
||||
<< "0" << SYMBOL_PIN_REQ << endl
|
||||
<< "0" << SYMBOL_PIN_ACK << endl
|
||||
<< "0" << SYMBOL_PIN_ATN << endl
|
||||
<< "0" << SYMBOL_PIN_RST << endl
|
||||
<< "b00000000 " << SYMBOL_PIN_DAT << endl
|
||||
<< "$end" << endl;
|
||||
|
||||
DWORD i = 0;
|
||||
while (i < capture_count)
|
||||
{
|
||||
vcd_ofstream << "#" << (uint64_t)(data_capture_array[i].timestamp * ns_per_loop) << endl;
|
||||
vcd_output_if_changed_bool(vcd_ofstream, data_capture_array[i].data, PIN_BSY, SYMBOL_PIN_BSY);
|
||||
vcd_output_if_changed_bool(vcd_ofstream, data_capture_array[i].data, PIN_SEL, SYMBOL_PIN_SEL);
|
||||
vcd_output_if_changed_bool(vcd_ofstream, data_capture_array[i].data, PIN_CD, SYMBOL_PIN_CD);
|
||||
vcd_output_if_changed_bool(vcd_ofstream, data_capture_array[i].data, PIN_IO, SYMBOL_PIN_IO);
|
||||
vcd_output_if_changed_bool(vcd_ofstream, data_capture_array[i].data, PIN_MSG, SYMBOL_PIN_MSG);
|
||||
vcd_output_if_changed_bool(vcd_ofstream, data_capture_array[i].data, PIN_REQ, SYMBOL_PIN_REQ);
|
||||
vcd_output_if_changed_bool(vcd_ofstream, data_capture_array[i].data, PIN_ACK, SYMBOL_PIN_ACK);
|
||||
vcd_output_if_changed_bool(vcd_ofstream, data_capture_array[i].data, PIN_ATN, SYMBOL_PIN_ATN);
|
||||
vcd_output_if_changed_bool(vcd_ofstream, data_capture_array[i].data, PIN_RST, SYMBOL_PIN_RST);
|
||||
vcd_output_if_changed_byte(vcd_ofstream, data_capture_array[i].data, PIN_DT0, SYMBOL_PIN_DAT);
|
||||
vcd_output_if_changed_phase(vcd_ofstream, data_capture_array[i].data, PIN_PHASE, SYMBOL_PIN_PHASE);
|
||||
i++;
|
||||
}
|
||||
vcd_ofstream.close();
|
||||
}
|
|
@ -58,7 +58,9 @@
|
|||
#include <pwd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#if defined(__linux__)
|
||||
#include <sys/epoll.h>
|
||||
#endif
|
||||
#include <netinet/in.h>
|
||||
|
||||
#if defined(__linux__)
|
||||
|
|
|
@ -12,9 +12,9 @@
|
|||
#include <cstdio>
|
||||
|
||||
// The following should be updated for each release
|
||||
const int rascsi_major_version = 21; // Last two digits of year
|
||||
const int rascsi_minor_version = 12; // Month
|
||||
const int rascsi_patch_version = -1; // Patch number - increment for each update
|
||||
const int rascsi_major_version = 22; // Last two digits of year
|
||||
const int rascsi_minor_version = 01; // Month
|
||||
const int rascsi_patch_version = 01; // Patch number - increment for each update
|
||||
|
||||
static char rascsi_version_string[30]; // Allow for string up to "XX.XX.XXX" + null character + "development build"
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
//---------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
#include "os.h"
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
|
|
|
@ -9,8 +9,6 @@
|
|||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "os.h"
|
||||
#include "filepath.h"
|
||||
#include "fileio.h"
|
||||
#include "log.h"
|
||||
#include "gpiobus.h"
|
||||
#include "rascsi_version.h"
|
||||
|
@ -19,7 +17,11 @@
|
|||
#include <climits>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <getopt.h>
|
||||
#include "rascsi.h"
|
||||
#include <sched.h>
|
||||
#include "monitor/sm_reports.h"
|
||||
#include "monitor/data_sample.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
@ -28,48 +30,47 @@ using namespace std;
|
|||
// Constant declarations
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
#define MAX_BUFF_SIZE 1000000
|
||||
|
||||
// Symbol definition for the VCD file
|
||||
// These are just arbitrary symbols. They can be anything allowed by the VCD file format,
|
||||
// as long as they're consistently used.
|
||||
#define SYMBOL_PIN_DAT '#'
|
||||
#define SYMBOL_PIN_ATN '+'
|
||||
#define SYMBOL_PIN_RST '$'
|
||||
#define SYMBOL_PIN_ACK '%'
|
||||
#define SYMBOL_PIN_REQ '^'
|
||||
#define SYMBOL_PIN_MSG '&'
|
||||
#define SYMBOL_PIN_CD '*'
|
||||
#define SYMBOL_PIN_IO '('
|
||||
#define SYMBOL_PIN_BSY ')'
|
||||
#define SYMBOL_PIN_SEL '-'
|
||||
#define SYMBOL_PIN_DAT '#'
|
||||
#define SYMBOL_PIN_ATN '+'
|
||||
#define SYMBOL_PIN_RST '$'
|
||||
#define SYMBOL_PIN_ACK '%'
|
||||
#define SYMBOL_PIN_REQ '^'
|
||||
#define SYMBOL_PIN_MSG '&'
|
||||
#define SYMBOL_PIN_CD '*'
|
||||
#define SYMBOL_PIN_IO '('
|
||||
#define SYMBOL_PIN_BSY ')'
|
||||
#define SYMBOL_PIN_SEL '-'
|
||||
#define SYMBOL_PIN_PHASE '='
|
||||
|
||||
// We'll use position 0 in the prev_value array to store the previous phase
|
||||
#define PIN_PHASE 0
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Variable declarations
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
static BYTE prev_value[32] = {0xFF};
|
||||
static volatile bool running; // Running flag
|
||||
GPIOBUS *bus; // GPIO Bus
|
||||
typedef struct data_capture{
|
||||
DWORD data;
|
||||
uint64_t timestamp;
|
||||
} data_capture_t;
|
||||
static volatile bool running; // Running flag
|
||||
GPIOBUS *bus; // GPIO Bus
|
||||
|
||||
data_capture data_buffer[MAX_BUFF_SIZE];
|
||||
DWORD buff_size = 1000000;
|
||||
data_capture *data_buffer;
|
||||
DWORD data_idx = 0;
|
||||
|
||||
double ns_per_loop;
|
||||
|
||||
bool print_help = false;
|
||||
bool import_data = false;
|
||||
|
||||
// We don't really need to support 256 character file names - this causes
|
||||
// all kinds of compiler warnings when the log filename can be up to 256
|
||||
// characters. _MAX_FNAME/2 is just an arbitrary value.
|
||||
char log_file_name[_MAX_FNAME/2] = "log.vcd";
|
||||
char file_base_name[_MAX_FNAME / 2] = "log";
|
||||
char vcd_file_name[_MAX_FNAME];
|
||||
char json_file_name[_MAX_FNAME];
|
||||
char html_file_name[_MAX_FNAME];
|
||||
char input_file_name[_MAX_FNAME];
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
|
@ -78,8 +79,84 @@ char log_file_name[_MAX_FNAME/2] = "log.vcd";
|
|||
//---------------------------------------------------------------------------
|
||||
void KillHandler(int sig)
|
||||
{
|
||||
// Stop instruction
|
||||
running = false;
|
||||
// Stop instruction
|
||||
running = false;
|
||||
}
|
||||
|
||||
void parse_arguments(int argc, char *argv[])
|
||||
{
|
||||
int opt;
|
||||
|
||||
while ((opt = getopt(argc, argv, "-Hhb:i:")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
// The three options below are kind of a compound option with two letters
|
||||
case 'h':
|
||||
case 'H':
|
||||
print_help = true;
|
||||
break;
|
||||
case 'b':
|
||||
buff_size = atoi(optarg);
|
||||
break;
|
||||
case 'i':
|
||||
strncpy(input_file_name, optarg, sizeof(input_file_name)-1);
|
||||
import_data = true;
|
||||
break;
|
||||
case 1:
|
||||
strncpy(file_base_name, optarg, sizeof(file_base_name) - 5);
|
||||
break;
|
||||
default:
|
||||
cout << "default: " << optarg << endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Process any remaining command line arguments (not options). */
|
||||
if (optind < argc)
|
||||
{
|
||||
while (optind < argc)
|
||||
strncpy(file_base_name, argv[optind++], sizeof(file_base_name)-1);
|
||||
}
|
||||
|
||||
strcpy(vcd_file_name, file_base_name);
|
||||
strcat(vcd_file_name, ".vcd");
|
||||
strcpy(json_file_name, file_base_name);
|
||||
strcat(json_file_name, ".json");
|
||||
strcpy(html_file_name, file_base_name);
|
||||
strcat(html_file_name, ".html");
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright text
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void print_copyright_text(int argc, char *argv[])
|
||||
{
|
||||
LOGINFO("SCSI Monitor Capture Tool - part of RaSCSI(*^..^*) ");
|
||||
LOGINFO("version %s (%s, %s)",
|
||||
rascsi_get_version_string(),
|
||||
__DATE__,
|
||||
__TIME__);
|
||||
LOGINFO("Powered by XM6 TypeG Technology ");
|
||||
LOGINFO("Copyright (C) 2016-2020 GIMONS");
|
||||
LOGINFO("Copyright (C) 2020-2021 Contributors to the RaSCSI project");
|
||||
LOGINFO(" ");
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Help text
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void print_help_text(int argc, char *argv[])
|
||||
{
|
||||
LOGINFO("%s -i [input file json] -b [buffer size] [output file]", argv[0]);
|
||||
LOGINFO(" -i [input file json] - scsimon will parse the json file instead of capturing new data");
|
||||
LOGINFO(" If -i option is not specified, scsimon will read the gpio pins");
|
||||
LOGINFO(" -b [buffer size] - Override the default buffer size of %d.", buff_size);
|
||||
LOGINFO(" [output file] - Base name of the output files. The file extension (ex: .json)");
|
||||
LOGINFO(" will be appended to this file name");
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -87,30 +164,23 @@ void KillHandler(int sig)
|
|||
// Banner Output
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
void Banner(int argc, char* argv[])
|
||||
void Banner(int argc, char *argv[])
|
||||
{
|
||||
LOGINFO("SCSI Monitor Capture Tool - part of RaSCSI(*^..^*) ");
|
||||
LOGINFO("version %s (%s, %s)\n",
|
||||
rascsi_get_version_string(),
|
||||
__DATE__,
|
||||
__TIME__);
|
||||
LOGINFO("Powered by XM6 TypeG Technology ");
|
||||
LOGINFO("Copyright (C) 2016-2020 GIMONS");
|
||||
LOGINFO("Copyright (C) 2020-2021 Contributors to the RaSCSI project");
|
||||
LOGINFO("Connect type : %s", CONNECT_DESC);
|
||||
LOGINFO(" %s - Value Change Dump file that can be opened with GTKWave", log_file_name);
|
||||
|
||||
if ((argc > 1 && strcmp(argv[1], "-h") == 0) ||
|
||||
(argc > 1 && strcmp(argv[1], "--help") == 0)){
|
||||
LOGINFO("Usage: %s [log filename]...", argv[0]);
|
||||
exit(0);
|
||||
}
|
||||
if (import_data)
|
||||
{
|
||||
LOGINFO("Reading input file: %s", input_file_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGINFO(" ");
|
||||
LOGINFO("Now collecting data.... Press CTRL-C to stop.")
|
||||
LOGINFO(" ");
|
||||
LOGINFO("Reading live data from the GPIO pins");
|
||||
LOGINFO(" Connection type : %s", CONNECT_DESC);
|
||||
}
|
||||
LOGINFO(" Data buffer size: %u", buff_size);
|
||||
LOGINFO(" ");
|
||||
LOGINFO("Generating output files:");
|
||||
LOGINFO(" %s - Value Change Dump file that can be opened with GTKWave", vcd_file_name);
|
||||
LOGINFO(" %s - JSON file with raw data", json_file_name);
|
||||
LOGINFO(" %s - HTML file with summary of commands", html_file_name);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -120,246 +190,101 @@ void Banner(int argc, char* argv[])
|
|||
//---------------------------------------------------------------------------
|
||||
bool Init()
|
||||
{
|
||||
// Interrupt handler settings
|
||||
if (signal(SIGINT, KillHandler) == SIG_ERR) {
|
||||
return FALSE;
|
||||
}
|
||||
if (signal(SIGHUP, KillHandler) == SIG_ERR) {
|
||||
return FALSE;
|
||||
}
|
||||
if (signal(SIGTERM, KillHandler) == SIG_ERR) {
|
||||
return FALSE;
|
||||
}
|
||||
// Interrupt handler settings
|
||||
if (signal(SIGINT, KillHandler) == SIG_ERR)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
if (signal(SIGHUP, KillHandler) == SIG_ERR)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
if (signal(SIGTERM, KillHandler) == SIG_ERR)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// GPIO Initialization
|
||||
bus = new GPIOBUS();
|
||||
if (!bus->Init()) {
|
||||
// GPIO Initialization
|
||||
bus = new GPIOBUS();
|
||||
if (!bus->Init())
|
||||
{
|
||||
LOGERROR("Unable to intiailize the GPIO bus. Exiting....");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Bus Reset
|
||||
bus->Reset();
|
||||
|
||||
// Other
|
||||
running = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
BOOL get_pin_value(DWORD data, int pin)
|
||||
{
|
||||
return (data >> pin) & 1;
|
||||
}
|
||||
|
||||
BYTE get_data_field(DWORD data)
|
||||
{
|
||||
DWORD data_out =
|
||||
((data >> (PIN_DT0 - 0)) & (1 << 7)) |
|
||||
((data >> (PIN_DT1 - 1)) & (1 << 6)) |
|
||||
((data >> (PIN_DT2 - 2)) & (1 << 5)) |
|
||||
((data >> (PIN_DT3 - 3)) & (1 << 4)) |
|
||||
((data >> (PIN_DT4 - 4)) & (1 << 3)) |
|
||||
((data >> (PIN_DT5 - 5)) & (1 << 2)) |
|
||||
((data >> (PIN_DT6 - 6)) & (1 << 1)) |
|
||||
((data >> (PIN_DT7 - 7)) & (1 << 0));
|
||||
|
||||
return (BYTE)data_out;
|
||||
}
|
||||
|
||||
void vcd_output_if_changed_phase(FILE *fp, DWORD data, int pin, char symbol)
|
||||
{
|
||||
BUS::phase_t new_value = GPIOBUS::GetPhaseRaw(data);
|
||||
if (prev_value[pin] != new_value)
|
||||
{
|
||||
prev_value[pin] = new_value;
|
||||
fprintf(fp, "s%s %c\n", GPIOBUS::GetPhaseStrRaw(new_value), symbol);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void vcd_output_if_changed_bool(FILE *fp, DWORD data, int pin, char symbol)
|
||||
{
|
||||
BOOL new_value = get_pin_value(data,pin);
|
||||
if (prev_value[pin] != new_value)
|
||||
{
|
||||
prev_value[pin] = new_value;
|
||||
fprintf(fp, "%d%c\n", new_value, symbol);
|
||||
}
|
||||
}
|
||||
// Bus Reset
|
||||
bus->Reset();
|
||||
|
||||
void vcd_output_if_changed_byte(FILE *fp, DWORD data, int pin, char symbol)
|
||||
{
|
||||
BYTE new_value = get_data_field(data);
|
||||
if(prev_value[pin] != new_value)
|
||||
{
|
||||
prev_value[pin] = new_value;
|
||||
fprintf(fp, "b%d%d%d%d%d%d%d%d %c\n",
|
||||
get_pin_value(data,PIN_DT7),
|
||||
get_pin_value(data,PIN_DT6),
|
||||
get_pin_value(data,PIN_DT5),
|
||||
get_pin_value(data,PIN_DT4),
|
||||
get_pin_value(data,PIN_DT3),
|
||||
get_pin_value(data,PIN_DT2),
|
||||
get_pin_value(data,PIN_DT1),
|
||||
get_pin_value(data,PIN_DT0), symbol);
|
||||
}
|
||||
}
|
||||
// Other
|
||||
running = false;
|
||||
|
||||
void create_value_change_dump()
|
||||
{
|
||||
LOGINFO("Creating Value Change Dump file (%s)", log_file_name);
|
||||
FILE *fp = fopen(log_file_name,"w");
|
||||
|
||||
// Get the current time
|
||||
time_t rawtime;
|
||||
time(&rawtime);
|
||||
struct tm *timeinfo = localtime(&rawtime);
|
||||
char timestamp[256];
|
||||
strftime (timestamp,sizeof(timestamp),"%d-%m-%Y %H-%M-%S",timeinfo);
|
||||
|
||||
fprintf(fp, "$date\n");
|
||||
fprintf(fp, "%s\n", timestamp);
|
||||
fprintf(fp, "$end\n");
|
||||
fprintf(fp, "$version\n");
|
||||
fprintf(fp, " VCD generator tool version info text.\n");
|
||||
fprintf(fp, "$end\n");
|
||||
fprintf(fp, "$comment\n");
|
||||
fprintf(fp, " Tool build date:%s\n", __TIMESTAMP__);
|
||||
fprintf(fp, "$end\n");
|
||||
fprintf(fp, "$timescale 1 ns $end\n");
|
||||
fprintf(fp, "$scope module logic $end\n");
|
||||
fprintf(fp, "$var wire 1 %c BSY $end\n", SYMBOL_PIN_BSY);
|
||||
fprintf(fp, "$var wire 1 %c SEL $end\n", SYMBOL_PIN_SEL);
|
||||
fprintf(fp, "$var wire 1 %c CD $end\n", SYMBOL_PIN_CD);
|
||||
fprintf(fp, "$var wire 1 %c IO $end\n", SYMBOL_PIN_IO);
|
||||
fprintf(fp, "$var wire 1 %c MSG $end\n", SYMBOL_PIN_MSG);
|
||||
fprintf(fp, "$var wire 1 %c REQ $end\n", SYMBOL_PIN_REQ);
|
||||
fprintf(fp, "$var wire 1 %c ACK $end\n", SYMBOL_PIN_ACK);
|
||||
fprintf(fp, "$var wire 1 %c ATN $end\n", SYMBOL_PIN_ATN);
|
||||
fprintf(fp, "$var wire 1 %c RST $end\n", SYMBOL_PIN_RST);
|
||||
fprintf(fp, "$var wire 8 %c data $end\n", SYMBOL_PIN_DAT);
|
||||
fprintf(fp, "$var string 1 %c phase $end\n", SYMBOL_PIN_PHASE);
|
||||
fprintf(fp, "$upscope $end\n");
|
||||
fprintf(fp, "$enddefinitions $end\n");
|
||||
|
||||
// Initial values - default to zeros
|
||||
fprintf(fp, "$dumpvars\n");
|
||||
fprintf(fp, "0%c\n", SYMBOL_PIN_BSY);
|
||||
fprintf(fp, "0%c\n", SYMBOL_PIN_SEL);
|
||||
fprintf(fp, "0%c\n", SYMBOL_PIN_CD);
|
||||
fprintf(fp, "0%c\n", SYMBOL_PIN_IO);
|
||||
fprintf(fp, "0%c\n", SYMBOL_PIN_MSG);
|
||||
fprintf(fp, "0%c\n", SYMBOL_PIN_REQ);
|
||||
fprintf(fp, "0%c\n", SYMBOL_PIN_ACK);
|
||||
fprintf(fp, "0%c\n", SYMBOL_PIN_ATN);
|
||||
fprintf(fp, "0%c\n", SYMBOL_PIN_RST);
|
||||
fprintf(fp, "b00000000 %c\n", SYMBOL_PIN_DAT);
|
||||
fprintf(fp, "$end\n");
|
||||
|
||||
DWORD i = 0;
|
||||
while (i < data_idx)
|
||||
{
|
||||
ostringstream s;
|
||||
s << (uint64_t)(data_buffer[i].timestamp*ns_per_loop);
|
||||
fprintf(fp, "#%s\n",s.str().c_str());
|
||||
vcd_output_if_changed_bool(fp, data_buffer[i].data, PIN_BSY, SYMBOL_PIN_BSY);
|
||||
vcd_output_if_changed_bool(fp, data_buffer[i].data, PIN_SEL, SYMBOL_PIN_SEL);
|
||||
vcd_output_if_changed_bool(fp, data_buffer[i].data, PIN_CD, SYMBOL_PIN_CD);
|
||||
vcd_output_if_changed_bool(fp, data_buffer[i].data, PIN_IO, SYMBOL_PIN_IO);
|
||||
vcd_output_if_changed_bool(fp, data_buffer[i].data, PIN_MSG, SYMBOL_PIN_MSG);
|
||||
vcd_output_if_changed_bool(fp, data_buffer[i].data, PIN_REQ, SYMBOL_PIN_REQ);
|
||||
vcd_output_if_changed_bool(fp, data_buffer[i].data, PIN_ACK, SYMBOL_PIN_ACK);
|
||||
vcd_output_if_changed_bool(fp, data_buffer[i].data, PIN_ATN, SYMBOL_PIN_ATN);
|
||||
vcd_output_if_changed_bool(fp, data_buffer[i].data, PIN_RST, SYMBOL_PIN_RST);
|
||||
vcd_output_if_changed_byte(fp, data_buffer[i].data, PIN_DT0, SYMBOL_PIN_DAT);
|
||||
vcd_output_if_changed_phase(fp, data_buffer[i].data, PIN_PHASE, SYMBOL_PIN_PHASE);
|
||||
i++;
|
||||
}
|
||||
fclose(fp);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Cleanup()
|
||||
{
|
||||
LOGINFO("Stopping data collection....");
|
||||
create_value_change_dump();
|
||||
if (!import_data)
|
||||
{
|
||||
LOGINFO("Stopping data collection....");
|
||||
}
|
||||
LOGINFO(" ");
|
||||
LOGINFO("Generating %s...", vcd_file_name);
|
||||
scsimon_generate_value_change_dump(vcd_file_name, data_buffer, data_idx);
|
||||
LOGINFO("Generating %s...", json_file_name);
|
||||
scsimon_generate_json(json_file_name, data_buffer, data_idx);
|
||||
LOGINFO("Generating %s...", html_file_name);
|
||||
scsimon_generate_html(html_file_name, data_buffer, data_idx);
|
||||
|
||||
// Cleanup the Bus
|
||||
bus->Cleanup();
|
||||
|
||||
delete bus;
|
||||
if (bus)
|
||||
{
|
||||
// Cleanup the Bus
|
||||
bus->Cleanup();
|
||||
delete bus;
|
||||
}
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
// Reset the bus
|
||||
bus->Reset();
|
||||
// Reset the bus
|
||||
bus->Reset();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Pin the thread to a specific CPU
|
||||
// Pin the thread to a specific CPU (Only applies to Linux)
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
#ifdef __linux__
|
||||
void FixCpu(int cpu)
|
||||
{
|
||||
// Get the number of CPUs
|
||||
cpu_set_t cpuset;
|
||||
CPU_ZERO(&cpuset);
|
||||
sched_getaffinity(0, sizeof(cpu_set_t), &cpuset);
|
||||
int cpus = CPU_COUNT(&cpuset);
|
||||
// Get the number of CPUs
|
||||
cpu_set_t cpuset;
|
||||
CPU_ZERO(&cpuset);
|
||||
sched_getaffinity(0, sizeof(cpu_set_t), &cpuset);
|
||||
int cpus = CPU_COUNT(&cpuset);
|
||||
|
||||
// Set the thread affinity
|
||||
if (cpu < cpus) {
|
||||
CPU_ZERO(&cpuset);
|
||||
CPU_SET(cpu, &cpuset);
|
||||
sched_setaffinity(0, sizeof(cpu_set_t), &cpuset);
|
||||
}
|
||||
// Set the thread affinity
|
||||
if (cpu < cpus)
|
||||
{
|
||||
CPU_ZERO(&cpuset);
|
||||
CPU_SET(cpu, &cpuset);
|
||||
sched_setaffinity(0, sizeof(cpu_set_t), &cpuset);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
static DWORD high_bits = 0x0;
|
||||
static DWORD low_bits = 0xFFFFFFFF;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Main processing
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
int main(int argc, char* argv[])
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
ostringstream s;
|
||||
|
||||
#ifdef DEBUG
|
||||
DWORD prev_high = high_bits;
|
||||
DWORD prev_low = low_bits;
|
||||
#endif
|
||||
DWORD prev_sample = 0xFFFFFFFF;
|
||||
DWORD this_sample = 0;
|
||||
struct sched_param schparam;
|
||||
timeval start_time;
|
||||
timeval stop_time;
|
||||
uint64_t loop_count = 0;
|
||||
timeval time_diff;
|
||||
uint64_t elapsed_us;
|
||||
int str_len;
|
||||
|
||||
// If there is an argument specified and it is NOT -h or --help
|
||||
if((argc > 1) && (strcmp(argv[1], "-h")) && (strcmp(argv[1], "--help"))){
|
||||
str_len = strlen(argv[1]);
|
||||
if ((str_len >= 1) && (str_len < _MAX_FNAME))
|
||||
{
|
||||
strncpy(log_file_name, argv[1], sizeof(log_file_name));
|
||||
// Append .vcd if its not already there
|
||||
if((str_len < 4) || strcasecmp(log_file_name + (str_len - 4), ".vcd")) {
|
||||
strcat(log_file_name, ".vcd");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Invalid log name specified. Using log.vcd");
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
spdlog::set_level(spdlog::level::trace);
|
||||
|
@ -367,53 +292,98 @@ int main(int argc, char* argv[])
|
|||
spdlog::set_level(spdlog::level::info);
|
||||
#endif
|
||||
spdlog::set_pattern("%^[%l]%$ %v");
|
||||
// Output the Banner
|
||||
Banner(argc, argv);
|
||||
memset(data_buffer,0,sizeof(data_buffer));
|
||||
|
||||
// Initialize
|
||||
int ret = 0;
|
||||
if (!Init()) {
|
||||
ret = EPERM;
|
||||
goto init_exit;
|
||||
}
|
||||
print_copyright_text(argc, argv);
|
||||
parse_arguments(argc, argv);
|
||||
|
||||
// Reset
|
||||
Reset();
|
||||
#ifdef DEBUG
|
||||
DWORD prev_high = high_bits;
|
||||
DWORD prev_low = low_bits;
|
||||
#endif
|
||||
ostringstream s;
|
||||
DWORD prev_sample = 0xFFFFFFFF;
|
||||
DWORD this_sample = 0;
|
||||
timeval start_time;
|
||||
timeval stop_time;
|
||||
uint64_t loop_count = 0;
|
||||
timeval time_diff;
|
||||
uint64_t elapsed_us;
|
||||
|
||||
if (print_help)
|
||||
{
|
||||
print_help_text(argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// Output the Banner
|
||||
Banner(argc, argv);
|
||||
|
||||
data_buffer = (data_capture *)malloc(sizeof(data_capture_t) * buff_size);
|
||||
bzero(data_buffer, sizeof(data_capture_t) * buff_size);
|
||||
|
||||
if (import_data)
|
||||
{
|
||||
data_idx = scsimon_read_json(input_file_name, data_buffer, buff_size);
|
||||
if (data_idx > 0)
|
||||
{
|
||||
LOGDEBUG("Read %d samples from %s", data_idx, input_file_name);
|
||||
Cleanup();
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
LOGINFO(" ");
|
||||
LOGINFO("Now collecting data.... Press CTRL-C to stop.")
|
||||
LOGINFO(" ");
|
||||
|
||||
// Initialize
|
||||
int ret = 0;
|
||||
if (!Init())
|
||||
{
|
||||
ret = EPERM;
|
||||
goto init_exit;
|
||||
}
|
||||
|
||||
// Reset
|
||||
Reset();
|
||||
|
||||
#ifdef __linux__
|
||||
// Set the affinity to a specific processor core
|
||||
FixCpu(3);
|
||||
FixCpu(3);
|
||||
|
||||
// Scheduling policy setting (highest priority)
|
||||
schparam.sched_priority = sched_get_priority_max(SCHED_FIFO);
|
||||
sched_setscheduler(0, SCHED_FIFO, &schparam);
|
||||
// Scheduling policy setting (highest priority)
|
||||
struct sched_param schparam;
|
||||
schparam.sched_priority = sched_get_priority_max(SCHED_FIFO);
|
||||
sched_setscheduler(0, SCHED_FIFO, &schparam);
|
||||
#endif
|
||||
|
||||
// Start execution
|
||||
running = true;
|
||||
bus->SetACT(FALSE);
|
||||
// Start execution
|
||||
running = true;
|
||||
bus->SetACT(FALSE);
|
||||
|
||||
(void)gettimeofday(&start_time, NULL);
|
||||
|
||||
LOGDEBUG("ALL_SCSI_PINS %08X\n",ALL_SCSI_PINS);
|
||||
LOGDEBUG("ALL_SCSI_PINS %08X\n", ALL_SCSI_PINS);
|
||||
|
||||
// Main Loop
|
||||
while (running) {
|
||||
// Work initialization
|
||||
this_sample = (bus->Aquire() & ALL_SCSI_PINS);
|
||||
while (running)
|
||||
{
|
||||
// Work initialization
|
||||
this_sample = (bus->Aquire() & ALL_SCSI_PINS);
|
||||
loop_count++;
|
||||
if (loop_count > LLONG_MAX -1)
|
||||
if (loop_count > LLONG_MAX - 1)
|
||||
{
|
||||
LOGINFO("Maximum amount of time has elapsed. SCSIMON is terminating.");
|
||||
running=false;
|
||||
running = false;
|
||||
}
|
||||
if (data_idx >= (MAX_BUFF_SIZE-2))
|
||||
if (data_idx >= (buff_size - 2))
|
||||
{
|
||||
LOGINFO("Internal data buffer is full. SCSIMON is terminating.");
|
||||
running=false;
|
||||
running = false;
|
||||
}
|
||||
|
||||
if (this_sample != prev_sample)
|
||||
{
|
||||
if (this_sample != prev_sample)
|
||||
{
|
||||
|
||||
#ifdef DEBUG
|
||||
// This is intended to be a debug check to see if every pin is set
|
||||
|
@ -422,27 +392,28 @@ int main(int argc, char* argv[])
|
|||
low_bits &= this_sample;
|
||||
if ((high_bits != prev_high) || (low_bits != prev_low))
|
||||
{
|
||||
LOGDEBUG(" %08X %08X\n",high_bits, low_bits);
|
||||
LOGDEBUG(" %08X %08X\n", high_bits, low_bits);
|
||||
}
|
||||
prev_high = high_bits;
|
||||
prev_low = low_bits;
|
||||
if((data_idx % 1000) == 0){
|
||||
s.str("");
|
||||
s << "Collected " << data_idx << " samples...";
|
||||
LOGDEBUG("%s", s.str().c_str());
|
||||
if ((data_idx % 1000) == 0)
|
||||
{
|
||||
s.str("");
|
||||
s << "Collected " << data_idx << " samples...";
|
||||
LOGDEBUG("%s", s.str().c_str());
|
||||
}
|
||||
#endif
|
||||
data_buffer[data_idx].data = this_sample;
|
||||
data_buffer[data_idx].timestamp = loop_count;
|
||||
data_idx++;
|
||||
prev_sample = this_sample;
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Collect one last sample, otherwise it looks like the end of the data was cut off
|
||||
if (data_idx < MAX_BUFF_SIZE)
|
||||
if (data_idx < buff_size)
|
||||
{
|
||||
data_buffer[data_idx].data = this_sample;
|
||||
data_buffer[data_idx].timestamp = loop_count;
|
||||
|
@ -453,7 +424,7 @@ int main(int argc, char* argv[])
|
|||
|
||||
timersub(&stop_time, &start_time, &time_diff);
|
||||
|
||||
elapsed_us = ((time_diff.tv_sec*1000000) + time_diff.tv_usec);
|
||||
elapsed_us = ((time_diff.tv_sec * 1000000) + time_diff.tv_usec);
|
||||
s.str("");
|
||||
s << "Elapsed time: " << elapsed_us << " microseconds (" << elapsed_us / 1000000 << " seconds)";
|
||||
LOGINFO("%s", s.str().c_str());
|
||||
|
@ -461,14 +432,14 @@ int main(int argc, char* argv[])
|
|||
s << "Collected " << data_idx << " changes";
|
||||
LOGINFO("%s", s.str().c_str());
|
||||
|
||||
// Note: ns_per_loop is a global variable that is used by Cleanup() to printout the timestamps.
|
||||
// Note: ns_per_loop is a global variable that is used by Cleanup() to printout the timestamps.
|
||||
ns_per_loop = (elapsed_us * 1000) / (double)loop_count;
|
||||
s.str("");
|
||||
s << "Read the SCSI bus " << loop_count << " times with an average of " << ns_per_loop << " ns for each read";
|
||||
LOGINFO("%s", s.str().c_str());
|
||||
|
||||
Cleanup();
|
||||
Cleanup();
|
||||
|
||||
init_exit:
|
||||
exit(ret);
|
||||
exit(ret);
|
||||
}
|
||||
|
|
|
@ -24,9 +24,12 @@ A separate mocking solution will be needed for this interface.
|
|||
It is recommended to run pylint against new code to protect against bugs
|
||||
and keep the code readable and maintainable.
|
||||
The local pylint configuration lives in .pylintrc
|
||||
In order for pylint to recognize venv libraries, the pylint-venv package is required.
|
||||
|
||||
```
|
||||
sudo apt install pylint3
|
||||
sudo pip install pylint-venv
|
||||
source venv/bin/activate
|
||||
pylint3 python_source_file.py
|
||||
```
|
||||
|
||||
|
@ -53,25 +56,59 @@ We use the Flask-Babel library and Flask/Jinja2 extension for i18n.
|
|||
|
||||
It uses the 'pybabel' command line tool for extracting and compiling localizations.
|
||||
Activate the Python venv in src/web/ to use it:
|
||||
|
||||
```
|
||||
$ cd src/web/
|
||||
$ source venv/bin/activate
|
||||
$ pybabel --help
|
||||
```
|
||||
|
||||
To create a new localization, it needs to be added to accept_languages in
|
||||
the get_locale() method, and also to localizer.cpp in the RaSCSI C++ code.
|
||||
To create a new localization, it needs to be added to the LANGAUGES constant in
|
||||
web/settings.py. To localize messages coming from the RaSCSI backend, update also code in
|
||||
raspberrypi/localizer.cpp in the RaSCSI C++ code.
|
||||
|
||||
Once this is done, follow the steps in the [Flask-Babel documentation](https://flask-babel.tkte.ch/#translating-applications)
|
||||
to generate the messages.po for the new language.
|
||||
|
||||
Updating an existing messages.po is also covered above.
|
||||
Updating the strings in an existing messages.po is also covered above.
|
||||
|
||||
When you are ready to contribute new or updated localizations, use the same Gitflow Workflow as used for any code contributions to submit PRs against the develop branch.
|
||||
|
||||
### Working with PO files
|
||||
|
||||
See the [GNU gettext documentation](https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html) for an introduction to the PO file format.
|
||||
|
||||
We make heavy use of __python-format__ for formatting, for instance:
|
||||
```
|
||||
#: file_cmds.py:353
|
||||
#, python-format
|
||||
msgid "%(file_name)s downloaded to %(save_dir)s"
|
||||
msgstr "Laddade ner %(file_name)s till %(save_dir)s"
|
||||
```
|
||||
|
||||
There are also a few instances of formatting in JavaScript:
|
||||
```
|
||||
#: templates/index.html:381
|
||||
msgid "Server responded with code: {{statusCode}}"
|
||||
msgstr "Servern svarade med kod: {{statusCode}}"
|
||||
```
|
||||
|
||||
And with html tags:
|
||||
```
|
||||
#: templates/index.html:304
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Emulates a SCSI DaynaPORT Ethernet Adapter. <a href=\"%(url)s\">Host "
|
||||
"drivers and configuration required</a>."
|
||||
msgstr ""
|
||||
"Emulerar en SCSI DaynaPORT ethernet-adapter. <a href=\"%(url)s\">Kräver "
|
||||
"drivrutiner och inställningar</a>."
|
||||
```
|
||||
|
||||
### (Optional) See translation stats for a localization
|
||||
Install the gettext package and use msgfmt to see the translation progress.
|
||||
|
||||
```
|
||||
$ sudo apt install gettext
|
||||
$ cd src/web/
|
||||
$ msgfmt --statistics translations/sv/LC_MESSAGES/messages.po
|
||||
215 translated messages, 1 untranslated message.
|
||||
```
|
||||
|
|
|
@ -418,5 +418,17 @@
|
|||
"file_type": null,
|
||||
"description": "Boots DECstations and VAXstations. Use only with workstations of this vintage.",
|
||||
"url": ""
|
||||
},
|
||||
{
|
||||
"device_type": "SCCD",
|
||||
"vendor": "MATSHITA",
|
||||
"product": "CD-ROM CR-8005 ",
|
||||
"revision": "1.0k",
|
||||
"block_size": 2048,
|
||||
"size": null,
|
||||
"name": "Apple CD 600e",
|
||||
"file_type": null,
|
||||
"description": "Emulates Apple CD ROM drive for use with Macintosh computers.",
|
||||
"url": ""
|
||||
}
|
||||
]
|
||||
|
|
|
@ -66,7 +66,8 @@ def list_images():
|
|||
command = proto.PbCommand()
|
||||
command.operation = proto.PbOperation.DEFAULT_IMAGE_FILES_INFO
|
||||
command.params["token"] = current_app.config["TOKEN"]
|
||||
command.params["locale"] = session["language"]
|
||||
if "language" in session.keys():
|
||||
command.params["locale"] = session["language"]
|
||||
|
||||
data = send_pb_command(command.SerializeToString())
|
||||
result = proto.PbResult()
|
||||
|
@ -123,7 +124,8 @@ def create_new_image(file_name, file_type, size):
|
|||
command = proto.PbCommand()
|
||||
command.operation = proto.PbOperation.CREATE_IMAGE
|
||||
command.params["token"] = current_app.config["TOKEN"]
|
||||
command.params["locale"] = session["language"]
|
||||
if "language" in session.keys():
|
||||
command.params["locale"] = session["language"]
|
||||
|
||||
command.params["file"] = file_name + "." + file_type
|
||||
command.params["size"] = str(size)
|
||||
|
@ -144,7 +146,8 @@ def delete_image(file_name):
|
|||
command = proto.PbCommand()
|
||||
command.operation = proto.PbOperation.DELETE_IMAGE
|
||||
command.params["token"] = current_app.config["TOKEN"]
|
||||
command.params["locale"] = session["language"]
|
||||
if "language" in session.keys():
|
||||
command.params["locale"] = session["language"]
|
||||
|
||||
command.params["file"] = file_name
|
||||
|
||||
|
@ -163,7 +166,8 @@ def rename_image(file_name, new_file_name):
|
|||
command = proto.PbCommand()
|
||||
command.operation = proto.PbOperation.RENAME_IMAGE
|
||||
command.params["token"] = current_app.config["TOKEN"]
|
||||
command.params["locale"] = session["language"]
|
||||
if "language" in session.keys():
|
||||
command.params["locale"] = session["language"]
|
||||
|
||||
command.params["from"] = file_name
|
||||
command.params["to"] = new_file_name
|
||||
|
@ -275,7 +279,7 @@ def download_file_to_iso(url, *iso_args):
|
|||
tmp_full_path = tmp_dir + file_name
|
||||
iso_filename = f"{server_info['image_dir']}/{file_name}.iso"
|
||||
|
||||
req_proc = download_to_dir(url, tmp_dir)
|
||||
req_proc = download_to_dir(url, tmp_dir, file_name)
|
||||
|
||||
if not req_proc["status"]:
|
||||
return {"status": False, "msg": req_proc["msg"]}
|
||||
|
@ -300,18 +304,16 @@ def download_file_to_iso(url, *iso_args):
|
|||
delete_file(tmp_full_path)
|
||||
|
||||
try:
|
||||
iso_proc = (
|
||||
run(
|
||||
[
|
||||
"genisoimage",
|
||||
*iso_args,
|
||||
"-o",
|
||||
iso_filename,
|
||||
tmp_dir,
|
||||
],
|
||||
capture_output=True,
|
||||
check=True,
|
||||
)
|
||||
run(
|
||||
[
|
||||
"genisoimage",
|
||||
*iso_args,
|
||||
"-o",
|
||||
iso_filename,
|
||||
tmp_dir,
|
||||
],
|
||||
capture_output=True,
|
||||
check=True,
|
||||
)
|
||||
except CalledProcessError as error:
|
||||
logging.warning("Executed shell command: %s", " ".join(error.cmd))
|
||||
|
@ -320,18 +322,20 @@ def download_file_to_iso(url, *iso_args):
|
|||
|
||||
return {
|
||||
"status": True,
|
||||
"msg": _(u"Created CD-ROM ISO image with arguments \"%(value)s\"", value=" ".join(iso_args)),
|
||||
"msg": _(
|
||||
u"Created CD-ROM ISO image with arguments \"%(value)s\"",
|
||||
value=" ".join(iso_args),
|
||||
),
|
||||
"file_name": iso_filename,
|
||||
}
|
||||
|
||||
|
||||
def download_to_dir(url, save_dir):
|
||||
def download_to_dir(url, save_dir, file_name):
|
||||
"""
|
||||
Takes (str) url, (str) save_dir
|
||||
Takes (str) url, (str) save_dir, (str) file_name
|
||||
Returns (dict) with (bool) status and (str) msg
|
||||
"""
|
||||
import requests
|
||||
file_name = PurePath(url).name
|
||||
logging.info("Making a request to download %s", url)
|
||||
|
||||
try:
|
||||
|
@ -393,7 +397,10 @@ def write_config(file_name):
|
|||
json_file,
|
||||
indent=4
|
||||
)
|
||||
return {"status": True, "msg": _(u"Saved configuration file to %(file_name)s", file_name=file_name)}
|
||||
return {
|
||||
"status": True,
|
||||
"msg": _(u"Saved configuration file to %(file_name)s", file_name=file_name),
|
||||
}
|
||||
except (IOError, ValueError, EOFError, TypeError) as error:
|
||||
logging.error(str(error))
|
||||
delete_file(file_name)
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
Module for commands sent to the RaSCSI backend service.
|
||||
"""
|
||||
|
||||
from settings import REMOVABLE_DEVICE_TYPES
|
||||
from socket_cmds import send_pb_command
|
||||
from flask import current_app, session
|
||||
from flask_babel import _
|
||||
import rascsi_interface_pb2 as proto
|
||||
from settings import REMOVABLE_DEVICE_TYPES
|
||||
from socket_cmds import send_pb_command
|
||||
|
||||
|
||||
def get_server_info():
|
||||
|
@ -25,7 +25,8 @@ def get_server_info():
|
|||
command = proto.PbCommand()
|
||||
command.operation = proto.PbOperation.SERVER_INFO
|
||||
command.params["token"] = current_app.config["TOKEN"]
|
||||
command.params["locale"] = session["language"]
|
||||
if "language" in session.keys():
|
||||
command.params["locale"] = session["language"]
|
||||
|
||||
data = send_pb_command(command.SerializeToString())
|
||||
result = proto.PbResult()
|
||||
|
@ -84,7 +85,8 @@ def get_reserved_ids():
|
|||
command = proto.PbCommand()
|
||||
command.operation = proto.PbOperation.RESERVED_IDS_INFO
|
||||
command.params["token"] = current_app.config["TOKEN"]
|
||||
command.params["locale"] = session["language"]
|
||||
if "language" in session.keys():
|
||||
command.params["locale"] = session["language"]
|
||||
|
||||
data = send_pb_command(command.SerializeToString())
|
||||
result = proto.PbResult()
|
||||
|
@ -106,7 +108,8 @@ def get_network_info():
|
|||
command = proto.PbCommand()
|
||||
command.operation = proto.PbOperation.NETWORK_INTERFACES_INFO
|
||||
command.params["token"] = current_app.config["TOKEN"]
|
||||
command.params["locale"] = session["language"]
|
||||
if "language" in session.keys():
|
||||
command.params["locale"] = session["language"]
|
||||
|
||||
data = send_pb_command(command.SerializeToString())
|
||||
result = proto.PbResult()
|
||||
|
@ -125,7 +128,8 @@ def get_device_types():
|
|||
command = proto.PbCommand()
|
||||
command.operation = proto.PbOperation.DEVICE_TYPES_INFO
|
||||
command.params["token"] = current_app.config["TOKEN"]
|
||||
command.params["locale"] = session["language"]
|
||||
if "language" in session.keys():
|
||||
command.params["locale"] = session["language"]
|
||||
|
||||
data = send_pb_command(command.SerializeToString())
|
||||
result = proto.PbResult()
|
||||
|
@ -148,7 +152,8 @@ def get_image_files_info():
|
|||
command = proto.PbCommand()
|
||||
command.operation = proto.PbOperation.DEFAULT_IMAGE_FILES_INFO
|
||||
command.params["token"] = current_app.config["TOKEN"]
|
||||
command.params["locale"] = session["language"]
|
||||
if "language" in session.keys():
|
||||
command.params["locale"] = session["language"]
|
||||
|
||||
data = send_pb_command(command.SerializeToString())
|
||||
result = proto.PbResult()
|
||||
|
@ -177,7 +182,8 @@ def attach_image(scsi_id, **kwargs):
|
|||
"""
|
||||
command = proto.PbCommand()
|
||||
command.params["token"] = current_app.config["TOKEN"]
|
||||
command.params["locale"] = session["language"]
|
||||
if "language" in session.keys():
|
||||
command.params["locale"] = session["language"]
|
||||
devices = proto.PbDeviceDefinition()
|
||||
devices.id = int(scsi_id)
|
||||
|
||||
|
@ -253,7 +259,8 @@ def detach_by_id(scsi_id, unit=None):
|
|||
command.operation = proto.PbOperation.DETACH
|
||||
command.devices.append(devices)
|
||||
command.params["token"] = current_app.config["TOKEN"]
|
||||
command.params["locale"] = session["language"]
|
||||
if "language" in session.keys():
|
||||
command.params["locale"] = session["language"]
|
||||
|
||||
data = send_pb_command(command.SerializeToString())
|
||||
result = proto.PbResult()
|
||||
|
@ -269,7 +276,8 @@ def detach_all():
|
|||
command = proto.PbCommand()
|
||||
command.operation = proto.PbOperation.DETACH_ALL
|
||||
command.params["token"] = current_app.config["TOKEN"]
|
||||
command.params["locale"] = session["language"]
|
||||
if "language" in session.keys():
|
||||
command.params["locale"] = session["language"]
|
||||
|
||||
data = send_pb_command(command.SerializeToString())
|
||||
result = proto.PbResult()
|
||||
|
@ -292,7 +300,8 @@ def eject_by_id(scsi_id, unit=None):
|
|||
command.operation = proto.PbOperation.EJECT
|
||||
command.devices.append(devices)
|
||||
command.params["token"] = current_app.config["TOKEN"]
|
||||
command.params["locale"] = session["language"]
|
||||
if "language" in session.keys():
|
||||
command.params["locale"] = session["language"]
|
||||
|
||||
data = send_pb_command(command.SerializeToString())
|
||||
result = proto.PbResult()
|
||||
|
@ -312,7 +321,8 @@ def list_devices(scsi_id=None, unit=None):
|
|||
command = proto.PbCommand()
|
||||
command.operation = proto.PbOperation.DEVICES_INFO
|
||||
command.params["token"] = current_app.config["TOKEN"]
|
||||
command.params["locale"] = session["language"]
|
||||
if "language" in session.keys():
|
||||
command.params["locale"] = session["language"]
|
||||
|
||||
# If method is called with scsi_id parameter, return the info on those devices
|
||||
# Otherwise, return the info on all attached devices
|
||||
|
@ -390,7 +400,8 @@ def reserve_scsi_ids(reserved_scsi_ids):
|
|||
command.operation = proto.PbOperation.RESERVE_IDS
|
||||
command.params["ids"] = ",".join(reserved_scsi_ids)
|
||||
command.params["token"] = current_app.config["TOKEN"]
|
||||
command.params["locale"] = session["language"]
|
||||
if "language" in session.keys():
|
||||
command.params["locale"] = session["language"]
|
||||
|
||||
data = send_pb_command(command.SerializeToString())
|
||||
result = proto.PbResult()
|
||||
|
@ -408,7 +419,8 @@ def set_log_level(log_level):
|
|||
command.operation = proto.PbOperation.LOG_LEVEL
|
||||
command.params["level"] = str(log_level)
|
||||
command.params["token"] = current_app.config["TOKEN"]
|
||||
command.params["locale"] = session["language"]
|
||||
if "language" in session.keys():
|
||||
command.params["locale"] = session["language"]
|
||||
|
||||
data = send_pb_command(command.SerializeToString())
|
||||
result = proto.PbResult()
|
||||
|
@ -426,7 +438,8 @@ def shutdown_pi(mode):
|
|||
command.operation = proto.PbOperation.SHUT_DOWN
|
||||
command.params["mode"] = str(mode)
|
||||
command.params["token"] = current_app.config["TOKEN"]
|
||||
command.params["locale"] = session["language"]
|
||||
if "language" in session.keys():
|
||||
command.params["locale"] = session["language"]
|
||||
|
||||
data = send_pb_command(command.SerializeToString())
|
||||
result = proto.PbResult()
|
||||
|
@ -443,7 +456,8 @@ def is_token_auth():
|
|||
command = proto.PbCommand()
|
||||
command.operation = proto.PbOperation.CHECK_AUTHENTICATION
|
||||
command.params["token"] = current_app.config["TOKEN"]
|
||||
command.params["locale"] = session["language"]
|
||||
if "language" in session.keys():
|
||||
command.params["locale"] = session["language"]
|
||||
|
||||
data = send_pb_command(command.SerializeToString())
|
||||
result = proto.PbResult()
|
||||
|
|
|
@ -32,4 +32,4 @@ RESERVATIONS = ["" for x in range(0, 8)]
|
|||
AUTH_GROUP = "rascsi"
|
||||
|
||||
# The language locales supported by RaSCSI
|
||||
LANGUAGES = ["en", "de", "sv"]
|
||||
LANGUAGES = ["en", "de", "sv", "fr", "es"]
|
||||
|
|
|
@ -3,9 +3,9 @@ Module for sending and receiving data over a socket connection with the RaSCSI b
|
|||
"""
|
||||
|
||||
import logging
|
||||
from time import sleep
|
||||
from flask import abort
|
||||
from flask_babel import _
|
||||
from time import sleep
|
||||
|
||||
def send_pb_command(payload):
|
||||
"""
|
||||
|
|
|
@ -34,9 +34,13 @@ fi
|
|||
# Test for two known broken venv states
|
||||
if test -e venv; then
|
||||
GOOD_VENV=true
|
||||
! test -e venv/bin/activate && GOOD_VENV=false
|
||||
pip3 list 1> /dev/null
|
||||
test $? -eq 1 && GOOD_VENV=false
|
||||
if ! test -e venv/bin/activate; then
|
||||
GOOD_VENV=false
|
||||
else
|
||||
source venv/bin/activate
|
||||
pip3 list 1> /dev/null
|
||||
test $? -eq 1 && GOOD_VENV=false
|
||||
fi
|
||||
if ! "$GOOD_VENV"; then
|
||||
echo "Deleting bad python venv"
|
||||
sudo rm -rf venv
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -372,7 +372,25 @@
|
|||
forceChunking: true,
|
||||
url: '/files/upload',
|
||||
maxFilesize: {{ max_file_size }}, // MB
|
||||
chunkSize: 1000000 // bytes
|
||||
chunkSize: 1000000, // bytes
|
||||
dictDefaultMessage: "{{ _("Drop files here to upload") }}",
|
||||
dictFallbackMessage: "{{ _("Your browser does not support drag'n'drop file uploads.") }}",
|
||||
dictFallbackText: "{{ _("Please use the fallback form below to upload your files like in the olden days.") }}",
|
||||
dictFileTooBig: "{{ _("File is too big: {{filesize}}MB. Max filesize: {{maxFilesize}}MB.") }}",
|
||||
dictInvalidFileType: "{{ _("You can't upload files of this type.") }}",
|
||||
dictResponseError: "{{ _("Server responded with code: {{statusCode}}") }}",
|
||||
dictCancelUpload:" {{ _("Cancel upload") }}",
|
||||
dictUploadCanceled: "{{ _("Upload canceled.") }}",
|
||||
dictCancelUploadConfirmation: "{{ _("Are you sure you want to cancel this upload?") }}",
|
||||
dictRemoveFile: "{{ _("Remove file") }}",
|
||||
dictMaxFilesExceeded: "{{ _("You can not upload any more files.") }}",
|
||||
dictFileSizeUnits: {
|
||||
tb: "{{ _("TB") }}",
|
||||
gb: "{{ _("GB") }}",
|
||||
mb: "{{ _("MB") }}",
|
||||
kb: "{{ _("KB") }}",
|
||||
b: "{{ _("b") }}"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: RaSCSI 68kmla Edition\n"
|
||||
"Report-Msgid-Bugs-To: https://github.com/akuker/RASCSI/issues\n"
|
||||
"POT-Creation-Date: 2021-12-26 21:59-0800\n"
|
||||
"POT-Creation-Date: 2021-12-28 14:39-0800\n"
|
||||
"PO-Revision-Date: 2021-12-24 16:16-0800\n"
|
||||
"Last-Translator: Daniel Markstedt <markstedt@gmail.com>\n"
|
||||
"Language: sv\n"
|
||||
|
@ -41,53 +41,53 @@ msgstr "Kunde ej flytta filen till %(target_path)s"
|
|||
#: file_cmds.py:323
|
||||
#, python-format
|
||||
msgid "Created CD-ROM ISO image with arguments \"%(value)s\""
|
||||
msgstr "Skapade en CD-ROM ISO-fil med argumenten \"%(value)s\""
|
||||
msgstr "Skapade en cd-rom ISO-fil med argumentet \"%(value)s\""
|
||||
|
||||
#: file_cmds.py:353
|
||||
#: file_cmds.py:354
|
||||
#, python-format
|
||||
msgid "%(file_name)s downloaded to %(save_dir)s"
|
||||
msgstr "Laddade ner %(file_name)s till %(save_dir)s"
|
||||
|
||||
#: file_cmds.py:396
|
||||
#: file_cmds.py:399
|
||||
#, python-format
|
||||
msgid "Saved configuration file to %(file_name)s"
|
||||
msgstr "Sparade konfigurationsfilen som %(file_name)s"
|
||||
|
||||
#: file_cmds.py:406
|
||||
#: file_cmds.py:410
|
||||
#, python-format
|
||||
msgid "Could not write to file: %(file_name)s"
|
||||
msgstr "Kunde ej skriva till filen %(file_name)s"
|
||||
|
||||
#: file_cmds.py:464
|
||||
#: file_cmds.py:468
|
||||
msgid "Invalid configuration file format"
|
||||
msgstr "Ogiltigt konfigurationsfilformat"
|
||||
|
||||
#: file_cmds.py:467
|
||||
#: file_cmds.py:471
|
||||
#, python-format
|
||||
msgid "Loaded configurations from: %(file_name)s"
|
||||
msgstr "Laddade konfigurationer från %(file_name)s"
|
||||
|
||||
#: file_cmds.py:476
|
||||
#: file_cmds.py:480
|
||||
#, python-format
|
||||
msgid "Could not read configuration file: %(file_name)s"
|
||||
msgstr "Kunde ej läsa konfigurationer från filen %(file_name)s"
|
||||
|
||||
#: file_cmds.py:493
|
||||
#: file_cmds.py:497
|
||||
#, python-format
|
||||
msgid "Created properties file: %(file_path)s"
|
||||
msgstr "Skapade egenskapsfilen %(file_path)s"
|
||||
|
||||
#: file_cmds.py:504
|
||||
#: file_cmds.py:508
|
||||
#, python-format
|
||||
msgid "Could not write to properties file: %(file_path)s"
|
||||
msgstr "Kunde ej spara egenskaper till filen %(file_path)s"
|
||||
|
||||
#: file_cmds.py:520
|
||||
#: file_cmds.py:524
|
||||
#, python-format
|
||||
msgid "Read properties from file: %(file_path)s"
|
||||
msgstr "Läste egenskaper från filen %(file_path)s"
|
||||
|
||||
#: file_cmds.py:530
|
||||
#: file_cmds.py:534
|
||||
#, python-format
|
||||
msgid "Could not read properties from file: %(file_path)s"
|
||||
msgstr "Kunde ej läsa egenskaper från filen %(file_path)s"
|
||||
|
@ -113,7 +113,7 @@ msgid ""
|
|||
" crashed."
|
||||
msgstr ""
|
||||
"RaSCSIs webbgränssnitt kunde inte ansluta till RaSCSI på "
|
||||
"%(host)s:%(port)s med felmeddelande %(error_msg)s. RaSCSI-processen är "
|
||||
"%(host)s:%(port)s med felmeddelandet %(error_msg)s. RaSCSI-processen är "
|
||||
"antingen avslagen eller har krashat."
|
||||
|
||||
#: socket_cmds.py:79
|
||||
|
@ -132,7 +132,7 @@ msgstr ""
|
|||
"RaSCSIs webbgränssnitt fick en ogiltig respons från RaSCSI. Gå tillbaks "
|
||||
"och försök igen. Om samma fel upprepas så rapportera en bugg."
|
||||
|
||||
#: web.py:97
|
||||
#: web.py:119
|
||||
msgid ""
|
||||
"RaSCSI is password protected. Start the Web Interface with the --password"
|
||||
" parameter."
|
||||
|
@ -140,71 +140,71 @@ msgstr ""
|
|||
"RaSCSI är lösenordsskyddat. Start webbgränssnittet med parametern "
|
||||
"--password ."
|
||||
|
||||
#: web.py:191
|
||||
#: web.py:220
|
||||
#, python-format
|
||||
msgid "Could not read drive properties from %(properties_file)s"
|
||||
msgstr "Kunde ej läsa egenskaper från %(properties_file)s"
|
||||
|
||||
#: web.py:255
|
||||
#: web.py:290
|
||||
#, python-format
|
||||
msgid "You must log in with credentials for a user in the '%(group)s' group"
|
||||
msgstr "Du måste logga in som en användare som tillhör %(group)s-gruppen"
|
||||
|
||||
#: web.py:308 web.py:843
|
||||
#: web.py:348 web.py:887
|
||||
#, python-format
|
||||
msgid "Image file created: %(file_name)s"
|
||||
msgstr "Skapade skivbildfil: %(file_name)s"
|
||||
msgstr "Skapade skivbildsfil %(file_name)s"
|
||||
|
||||
#: web.py:433
|
||||
#: web.py:473
|
||||
msgid "An error occurred when fetching logs."
|
||||
msgstr "Ett fel inträffade när vi skaffade loggar."
|
||||
|
||||
#: web.py:448
|
||||
#: web.py:488
|
||||
#, python-format
|
||||
msgid "Log level set to %(value)s"
|
||||
msgstr "Ställde in loggnivån till %(value)s"
|
||||
msgstr "Bytte loggnivån till %(value)s"
|
||||
|
||||
#: web.py:467
|
||||
#: web.py:507
|
||||
#, python-format
|
||||
msgid "Please follow the instructions at %(url)s"
|
||||
msgstr "Följ instruktionerna på %(url)s"
|
||||
|
||||
#: web.py:471
|
||||
#: web.py:511
|
||||
msgid "Configure IPv4 forwarding before using a wireless network device."
|
||||
msgstr ""
|
||||
"Ställ in IPv4-vidarebefodring innan du använder en trådlös "
|
||||
"nätverksadapter."
|
||||
"Ställ in IPv4-vidarebefodring innan du använder ett trådlöst "
|
||||
"nätverksgränssnitt."
|
||||
|
||||
#: web.py:475
|
||||
#: web.py:515
|
||||
msgid "Configure NAT before using a wireless network device."
|
||||
msgstr "Ställ in NAT innan du använder en trådlös nätverksadapter."
|
||||
msgstr "Ställ in NAT innan du använder ett trådlöst nätverksgränssnitt."
|
||||
|
||||
#: web.py:480 web.py:484
|
||||
#: web.py:520 web.py:524
|
||||
msgid "Configure the network bridge before using a wired network device."
|
||||
msgstr "Ställ in nätverksbryggan innan du använder ett nätverksgränssnitt."
|
||||
|
||||
#: web.py:497
|
||||
#: web.py:537
|
||||
#, python-format
|
||||
msgid "Attached DaynaPORT to SCSI ID %(id_number)s"
|
||||
msgstr "Anslöt DaynaPORT till SCSI-id %(id_number)s"
|
||||
|
||||
#: web.py:545
|
||||
#: web.py:585
|
||||
#, python-format
|
||||
msgid "Attached %(file_name)s to SCSI ID %(id_number)s LUN %(unit_number)s"
|
||||
msgstr "Anslöt %(file_name)s till SCSI-id %(id_number)s LUN %(unit_number)s"
|
||||
|
||||
#: web.py:548
|
||||
#: web.py:588
|
||||
#, python-format
|
||||
msgid ""
|
||||
"The image file size %(file_size)s bytes is not a multiple of "
|
||||
"%(block_size)s. RaSCSI will ignore the trailing data. The image may be "
|
||||
"corrupted, so proceed with caution."
|
||||
msgstr ""
|
||||
"Filstorleken %(file_size)s bytes är inte en multipel av %(block_size)s. "
|
||||
"Filstorleken %(file_size)s byte är inte en multipel av %(block_size)s. "
|
||||
"RaSCSI ignorerar den överflödiga datan. Skivbilden är möjligen förstörd, "
|
||||
"så var försiktig när du använder den."
|
||||
|
||||
#: web.py:554
|
||||
#: web.py:594
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Failed to attach %(file_name)s to SCSI ID %(id_number)s LUN "
|
||||
|
@ -213,133 +213,127 @@ msgstr ""
|
|||
"Kunde inte ansluta %(file_name)s till SCSI-id %(id_number)s LUN "
|
||||
"%(unit_number)s"
|
||||
|
||||
#: web.py:568
|
||||
#: web.py:608
|
||||
msgid "Detached all SCSI devices"
|
||||
msgstr "Kopplade ifrån alla SCSI-enheter"
|
||||
|
||||
#: web.py:585
|
||||
#: web.py:625
|
||||
#, python-format
|
||||
msgid "Detached SCSI ID %(id_number)s LUN %(unit_number)s"
|
||||
msgstr "Kopplade ifrån SCSI-id %(id_number)s LUN %(unit_number)s"
|
||||
|
||||
#: web.py:589
|
||||
#: web.py:629
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Failed to detach %(file_name)s from SCSI ID %(id_number)s LUN "
|
||||
"%(unit_number)s"
|
||||
msgid "Failed to detach SCSI ID %(id_number)s LUN %(unit_number)s"
|
||||
msgstr ""
|
||||
"Kunde ej koppla ifrån %(file_name)s från SCSI-id %(id_number)s LUN "
|
||||
"%(unit_number)s"
|
||||
"Kunde ej koppla ifrån SCSI-id %(id_number)s LUN %(unit_number)s"
|
||||
|
||||
#: web.py:606
|
||||
#: web.py:646
|
||||
#, python-format
|
||||
msgid "Ejected SCSI ID %(id_number)s LUN %(unit_number)s"
|
||||
msgstr "Utmatade SCSI-id %(id_number)s LUN %(unit_number)s"
|
||||
|
||||
#: web.py:610
|
||||
#: web.py:650
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Failed to eject %(file_name)s from SCSI ID %(id_number)s LUN "
|
||||
"%(unit_number)s"
|
||||
msgid "Failed to eject SCSI ID %(id_number)s LUN %(unit_number)s"
|
||||
msgstr ""
|
||||
"Kunde ej utmata %(file_name)s från SCSI-id %(id_number)s LUN "
|
||||
"%(unit_number)s"
|
||||
"Kunde ej mata ut skiva från SCSI-id %(id_number)s LUN %(unit_number)s"
|
||||
|
||||
#: web.py:633
|
||||
#: web.py:673
|
||||
msgid "DEVICE INFO"
|
||||
msgstr "ENHETSDATA"
|
||||
|
||||
#: web.py:635
|
||||
#: web.py:675
|
||||
#, python-format
|
||||
msgid "SCSI ID: %(id_number)s"
|
||||
msgstr "SCSI-id: %(id_number)s"
|
||||
|
||||
#: web.py:636
|
||||
#: web.py:676
|
||||
#, python-format
|
||||
msgid "LUN: %(unit_number)s"
|
||||
msgstr "LUN: %(unit_number)s"
|
||||
|
||||
#: web.py:637
|
||||
#: web.py:677
|
||||
#, python-format
|
||||
msgid "Type: %(device_type)s"
|
||||
msgstr "Typ: %(device_type)s"
|
||||
|
||||
#: web.py:638
|
||||
#: web.py:678
|
||||
#, python-format
|
||||
msgid "Status: %(device_status)s"
|
||||
msgstr "Status: %(device_status)s"
|
||||
|
||||
#: web.py:639
|
||||
#: web.py:679
|
||||
#, python-format
|
||||
msgid "File: %(image_file)s"
|
||||
msgstr "Fil: %(image_file)s"
|
||||
|
||||
#: web.py:640
|
||||
#: web.py:680
|
||||
#, python-format
|
||||
msgid "Parameters: %(value)s"
|
||||
msgstr "Parametrar: %(value)s"
|
||||
|
||||
#: web.py:641
|
||||
#: web.py:681
|
||||
#, python-format
|
||||
msgid "Vendor: %(value)s"
|
||||
msgstr "Tillverkare: %(value)s"
|
||||
|
||||
#: web.py:642
|
||||
#: web.py:682
|
||||
#, python-format
|
||||
msgid "Product: %(value)s"
|
||||
msgstr "Produkt: %(value)s"
|
||||
|
||||
#: web.py:643
|
||||
#: web.py:683
|
||||
#, python-format
|
||||
msgid "Revision: %(revision_number)s"
|
||||
msgstr "Revision: %(revision_number)s"
|
||||
|
||||
#: web.py:644
|
||||
#: web.py:684
|
||||
#, python-format
|
||||
msgid "Block Size: %(value)s bytes"
|
||||
msgstr "Blockstorlek: %(value)s bytes"
|
||||
msgstr "Blockstorlek: %(value)s byte"
|
||||
|
||||
#: web.py:645
|
||||
#: web.py:685
|
||||
#, python-format
|
||||
msgid "Image Size: %(value)s bytes"
|
||||
msgstr "Skivbildsstorlek: %(value)s bytes"
|
||||
msgstr "Skivbildsstorlek: %(value)s byte"
|
||||
|
||||
#: web.py:664
|
||||
#: web.py:704
|
||||
#, python-format
|
||||
msgid "Reserved SCSI ID %(id_number)s"
|
||||
msgstr "Reserverat SCSI-id %(id_number)s"
|
||||
|
||||
#: web.py:667
|
||||
#: web.py:707
|
||||
#, python-format
|
||||
msgid "Failed to reserve SCSI ID %(id_number)s"
|
||||
msgstr "Kunde ej reservera SCSI-id %(id_number)s"
|
||||
|
||||
#: web.py:683
|
||||
#: web.py:723
|
||||
#, python-format
|
||||
msgid "Released the reservation for SCSI ID %(id_number)s"
|
||||
msgstr "Avreserverade SCSI-id %(id_number)s"
|
||||
|
||||
#: web.py:686
|
||||
#: web.py:726
|
||||
#, python-format
|
||||
msgid "Failed to release the reservation for SCSI ID %(id_number)s"
|
||||
msgstr "Kunde ej avreservera SCSI-id %(id_number)s"
|
||||
|
||||
#: web.py:724
|
||||
#: web.py:764
|
||||
#, python-format
|
||||
msgid "Saved image as: %(file_name)s"
|
||||
msgstr "Sparade bildfilen som %(file_name)s"
|
||||
|
||||
#: web.py:726
|
||||
#: web.py:766
|
||||
#, python-format
|
||||
msgid "Failed to create CD-ROM image from %(url)s"
|
||||
msgstr "Kunde ej skapa CD-ROM-bildfil från %(url)s"
|
||||
|
||||
#: web.py:732
|
||||
#: web.py:772
|
||||
#, python-format
|
||||
msgid "Attached to SCSI ID %(id_number)s"
|
||||
msgstr "Anslöt till SCSI-id %(id_number)s"
|
||||
|
||||
#: web.py:735
|
||||
#: web.py:775
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Failed to attach image to SCSI ID %(id_number)s. Try attaching it "
|
||||
|
@ -348,55 +342,60 @@ msgstr ""
|
|||
"Kunde ej ansluta bildfilen till SCSI-id %(id_number)s. Försök ansluta den"
|
||||
" manuellt."
|
||||
|
||||
#: web.py:754 web.py:771
|
||||
#: web.py:794 web.py:811
|
||||
#, python-format
|
||||
msgid "Failed to download file from %(url)s"
|
||||
msgstr "Kunde ej ladda ner filen från %(url)s"
|
||||
|
||||
#: web.py:802
|
||||
#: web.py:842
|
||||
msgid "The file already exists!"
|
||||
msgstr "Filen existerar redan!"
|
||||
|
||||
#: web.py:810
|
||||
#: web.py:850
|
||||
msgid "Unable to write the file to disk!"
|
||||
msgstr "Kunde ej skriva filen till skivan!"
|
||||
|
||||
#: web.py:821
|
||||
#: web.py:865
|
||||
msgid "Transferred file corrupted!"
|
||||
msgstr "Den överförda filen är skadad!"
|
||||
|
||||
#: web.py:827
|
||||
#: web.py:871
|
||||
msgid "File upload successful!"
|
||||
msgstr "Filen har laddas upp!"
|
||||
|
||||
#: web.py:870
|
||||
#: web.py:914
|
||||
#, python-format
|
||||
msgid "Image file deleted: %(file_name)s"
|
||||
msgstr "Skivbildfilen %(file_name)s har blivit raderad"
|
||||
msgstr "Filen %(file_name)s har blivit raderad"
|
||||
|
||||
#: web.py:900
|
||||
#: web.py:944
|
||||
#, python-format
|
||||
msgid "Image file renamed to: %(file_name)s"
|
||||
msgstr "Skivbildfilen har blivit omdöpt till %(file_name)s"
|
||||
msgstr "Filen har blivit omdöpt till %(file_name)s"
|
||||
|
||||
#: web.py:937
|
||||
#: web.py:981
|
||||
msgid "Aborted unzip: File(s) with the same name already exists."
|
||||
msgstr "Uppackning stoppad: En eller flera filer med samma namn existerar."
|
||||
msgstr "Uppackning stoppad: En eller flera filer med samma namn existerar redan."
|
||||
|
||||
#: web.py:939
|
||||
#: web.py:983
|
||||
msgid "Unzipped the following files:"
|
||||
msgstr "Packade up dessa filer:"
|
||||
|
||||
#: web.py:943
|
||||
#: web.py:987
|
||||
#, python-format
|
||||
msgid "Properties file(s) have been moved to %(directory)s"
|
||||
msgstr "En eller flera egenskapsfiler har blivit flyttade till %(directory)s"
|
||||
|
||||
#: web.py:946
|
||||
#: web.py:990
|
||||
#, python-format
|
||||
msgid "Failed to unzip %(zip_file)s"
|
||||
msgstr "Kunde ej packa up %(zip_file)s"
|
||||
|
||||
#: web.py:1004
|
||||
#, python-format
|
||||
msgid "Changed Web Interface language to %(locale)s"
|
||||
msgstr "Bytte webbgränssnittets språk till %(locale)s"
|
||||
|
||||
#: templates/base.html:4
|
||||
msgid "RaSCSI Control Page"
|
||||
msgstr "RaSCSI kontrollsida"
|
||||
|
@ -514,7 +513,7 @@ msgid "Save as:"
|
|||
msgstr "Spara som:"
|
||||
|
||||
#: templates/drives.html:41 templates/drives.html:88 templates/drives.html:131
|
||||
#: templates/index.html:531
|
||||
#: templates/index.html:549
|
||||
msgid "Create"
|
||||
msgstr "Skapa"
|
||||
|
||||
|
@ -557,7 +556,7 @@ msgid ""
|
|||
"Save and load device configurations, stored as json files in "
|
||||
"<tt>%(config_dir)s</tt>"
|
||||
msgstr ""
|
||||
"Spara och ladda enhetskonfigurationer. Sparas som json-format i "
|
||||
"Spara och ladda enhetskonfigurationer. Sparas i json-format vid "
|
||||
"<tt>%(config_dir)s</tt>"
|
||||
|
||||
#: templates/index.html:11
|
||||
|
@ -626,7 +625,7 @@ msgstr "Anslut"
|
|||
|
||||
#: templates/index.html:98
|
||||
msgid "Eject Disk? WARNING: On Mac OS, eject the Disk in the Finder instead!"
|
||||
msgstr "Mata ut skiva? VARNING: På Mac OS, mata ut skivan i Finder istället!"
|
||||
msgstr "Mata ut skiva? VARNING: På Mac OS bör du mata ut skivan i Finder istället!"
|
||||
|
||||
#: templates/index.html:101
|
||||
msgid "Eject"
|
||||
|
@ -678,8 +677,8 @@ msgid ""
|
|||
"Manage image files in the active RaSCSI image directory: "
|
||||
"<tt>%(directory)s</tt> with a scan depth of %(scan_depth)s."
|
||||
msgstr ""
|
||||
"Hantera filer i den aktiva skivbildsfilskatalogen: <tt>%(directory)s</tt>"
|
||||
" med hierarkiskt djup %(scan_depth)s."
|
||||
"Hantera filer i den aktiva skivbildskatalogen: <tt>%(directory)s</tt> med"
|
||||
" hierarkiskt djup %(scan_depth)s."
|
||||
|
||||
#: templates/index.html:156
|
||||
#, python-format
|
||||
|
@ -721,9 +720,9 @@ msgstr "Packa upp"
|
|||
|
||||
#: templates/index.html:204 templates/index.html:218
|
||||
msgid "Unzipping a single file..."
|
||||
msgstr "Packar upp en enda fil..."
|
||||
msgstr "Packar upp endast en fil..."
|
||||
|
||||
#: templates/index.html:233 templates/index.html:530
|
||||
#: templates/index.html:233 templates/index.html:390 templates/index.html:548
|
||||
msgid "MB"
|
||||
msgstr "MB"
|
||||
|
||||
|
@ -763,7 +762,7 @@ msgid ""
|
|||
"Emulates a SCSI DaynaPORT Ethernet Adapter. <a href=\"%(url)s\">Host "
|
||||
"drivers and configuration required</a>."
|
||||
msgstr ""
|
||||
"Emulerar en SCSI DaynaPORT ethernet-adapter. <a href=\"%(url)s\">Kräver "
|
||||
"Emulerar ett SCSI DaynaPORT ethernet-gränssnitt. <a href=\"%(url)s\">Kräver "
|
||||
"drivrutiner och inställningar</a>."
|
||||
|
||||
#: templates/index.html:306
|
||||
|
@ -799,14 +798,14 @@ msgstr "Gränssnitt:"
|
|||
msgid "Static IP (optional):"
|
||||
msgstr "Statisk adress (tillval):"
|
||||
|
||||
#: templates/index.html:329 templates/index.html:455
|
||||
#: templates/index.html:329 templates/index.html:473
|
||||
msgid "SCSI ID:"
|
||||
msgstr "SCSI-id:"
|
||||
|
||||
#: templates/index.html:343
|
||||
#, python-format
|
||||
msgid "Macproxy is running at %(ip_addr)s (default port 5000)"
|
||||
msgstr "Macproxy är tillgängligt på %(ip_addr)s (förvald port 5000)"
|
||||
msgstr "Macproxy är tillgängligt på %(ip_addr)s (vanligtvis port 5000)"
|
||||
|
||||
#: templates/index.html:345
|
||||
#, python-format
|
||||
|
@ -815,7 +814,7 @@ msgid ""
|
|||
"vintage browser. It's not just for Macs!"
|
||||
msgstr ""
|
||||
"Installera <a href=\"%(url)s\">Macproxy</a> och surfa på nätet med gamla "
|
||||
"webbläsare. Den är inte bara för Macar!"
|
||||
"webbläsare. Den är inte bara till för Macar!"
|
||||
|
||||
#: templates/index.html:351
|
||||
msgid "Upload File"
|
||||
|
@ -838,56 +837,122 @@ msgid ""
|
|||
msgstr ""
|
||||
"Om RaSCSI inte känner igen en filtyp kan du försöka döpa om "
|
||||
"hårddiskbildfiler till '.hds', cd-bildfiler till '.iso', och utmatbara "
|
||||
"bildfiler till '.hdr' innan du laddar upp den."
|
||||
"bildfiler till '.hdr' innan du laddar upp dem."
|
||||
|
||||
#: templates/index.html:356
|
||||
#, python-format
|
||||
msgid "Recognized file types: %(valid_file_suffix)s"
|
||||
msgstr "Kända filtyper: %(valid_file_suffix)s"
|
||||
|
||||
#: templates/index.html:376
|
||||
msgid "Drop files here to upload"
|
||||
msgstr "Släpp filer här för att ladda upp"
|
||||
|
||||
#: templates/index.html:377
|
||||
msgid "Your browser does not support drag'n'drop file uploads."
|
||||
msgstr "Din webbläsare stöder ej filuppladdning via dra och släpp."
|
||||
|
||||
#: templates/index.html:378
|
||||
msgid ""
|
||||
"Please use the fallback form below to upload your files like in the olden"
|
||||
" days."
|
||||
msgstr ""
|
||||
"Använd reservformuläret nedan för att ladda upp dina filer på gammaldags "
|
||||
"vis."
|
||||
|
||||
#: templates/index.html:379
|
||||
msgid "File is too big: {{filesize}}MB. Max filesize: {{maxFilesize}}MB."
|
||||
msgstr ""
|
||||
"Filen är för stor: {{filesize}}MB. Största möjliga storlek: "
|
||||
"{{maxFilesize}}MB."
|
||||
|
||||
#: templates/index.html:380
|
||||
msgid "You can't upload files of this type."
|
||||
msgstr "Du kan ej ladda upp filer av den här typen."
|
||||
|
||||
#: templates/index.html:381
|
||||
msgid "Server responded with code: {{statusCode}}"
|
||||
msgstr "Servern svarade med kod: {{statusCode}}"
|
||||
|
||||
#: templates/index.html:382
|
||||
msgid "Cancel upload"
|
||||
msgstr "Avbryt uppladdning"
|
||||
|
||||
#: templates/index.html:383
|
||||
msgid "Download File to Images"
|
||||
msgstr "Ladda ner fil till skivbildsfilskatalogen"
|
||||
msgid "Upload canceled."
|
||||
msgstr "Uppladdningen avbröts."
|
||||
|
||||
#: templates/index.html:384
|
||||
msgid "Are you sure you want to cancel this upload?"
|
||||
msgstr "Är du säker på att du vill avbryta uppladdningen?"
|
||||
|
||||
#: templates/index.html:385
|
||||
msgid "Remove file"
|
||||
msgstr "Radera fil"
|
||||
|
||||
#: templates/index.html:386
|
||||
msgid "You can not upload any more files."
|
||||
msgstr "Du kan inte ladda upp några fler filer."
|
||||
|
||||
#: templates/index.html:388
|
||||
msgid "TB"
|
||||
msgstr "TB"
|
||||
|
||||
#: templates/index.html:389
|
||||
msgid "GB"
|
||||
msgstr "GB"
|
||||
|
||||
#: templates/index.html:391
|
||||
msgid "KB"
|
||||
msgstr "KB"
|
||||
|
||||
#: templates/index.html:392
|
||||
msgid "b"
|
||||
msgstr "b"
|
||||
|
||||
#: templates/index.html:401
|
||||
msgid "Download File to Images"
|
||||
msgstr "Ladda ner fil till skivbildskatalogen"
|
||||
|
||||
#: templates/index.html:404
|
||||
#, python-format
|
||||
msgid "Given a URL, download that file to the <tt>%(directory)s</tt> directory."
|
||||
msgstr "Ta ett url och ladda ner en fil till katalogen <tt>%(directory)s</tt>"
|
||||
msgstr "Ta en webbadress och ladda ner en fil till katalogen <tt>%(directory)s</tt>"
|
||||
|
||||
#: templates/index.html:394 templates/index.html:420 templates/index.html:464
|
||||
#: templates/index.html:412 templates/index.html:438 templates/index.html:482
|
||||
msgid "URL:"
|
||||
msgstr "Url:"
|
||||
msgstr "Webbadress:"
|
||||
|
||||
#: templates/index.html:395 templates/index.html:421 templates/index.html:465
|
||||
#: templates/index.html:413 templates/index.html:439 templates/index.html:483
|
||||
msgid "URL"
|
||||
msgstr "Url"
|
||||
msgstr "Webbadress"
|
||||
|
||||
#: templates/index.html:396 templates/index.html:422
|
||||
#: templates/index.html:414 templates/index.html:440
|
||||
msgid "Download"
|
||||
msgstr "Ladda ner"
|
||||
|
||||
#: templates/index.html:396
|
||||
#: templates/index.html:414
|
||||
msgid "Downloading File to Images..."
|
||||
msgstr "Laddar ner filen till skivbildsfilskatalogen..."
|
||||
msgstr "Laddar ner filen till skivbildskatalogen..."
|
||||
|
||||
#: templates/index.html:406
|
||||
#: templates/index.html:424
|
||||
msgid "Download File to AppleShare"
|
||||
msgstr "Ladda ner fil till AppleShare"
|
||||
|
||||
#: templates/index.html:409
|
||||
#: templates/index.html:427
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Given a URL, download that file to the <tt>%(directory)s</tt> directory "
|
||||
"and share it over AFP."
|
||||
msgstr ""
|
||||
"Ta ett url och ladda ner en fil till katalogen <tt>%(directory)s</tt> och"
|
||||
"Ta en webbadress och ladda ner en fil till katalogen <tt>%(directory)s</tt> och"
|
||||
" fildela den över AFP."
|
||||
|
||||
#: templates/index.html:410
|
||||
#: templates/index.html:428
|
||||
msgid "Manage the files you download here through AppleShare on your vintage Mac."
|
||||
msgstr "Hantera dessa filer via AppleShare på en klassisk Mac."
|
||||
msgstr "Hantera dessa filer via AppleShare på din gamla Mac."
|
||||
|
||||
#: templates/index.html:411
|
||||
#: templates/index.html:429
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Requires <a href=\"%(url)s\">Netatalk</a> to be installed and configured "
|
||||
|
@ -896,25 +961,25 @@ msgstr ""
|
|||
"Kräver att <a href=\"%(url)s\">Netatalk</a> är installerat och inställt "
|
||||
"på lämpligt vis för ditt nätverk."
|
||||
|
||||
#: templates/index.html:422
|
||||
#: templates/index.html:440
|
||||
msgid "Downloading File to AppleShare..."
|
||||
msgstr "Laddar ner fil till AppleShare..."
|
||||
|
||||
#: templates/index.html:429
|
||||
#: templates/index.html:447
|
||||
msgid "The AppleShare server is running. No active connections."
|
||||
msgstr "AppleShare-servern är aktiv. Inga klienter är anslutna."
|
||||
|
||||
#: templates/index.html:431
|
||||
#: templates/index.html:449
|
||||
#, python-format
|
||||
msgid "%(value)d active AFP connection"
|
||||
msgstr "%(value)d aktiv AFP-klient"
|
||||
|
||||
#: templates/index.html:433
|
||||
#: templates/index.html:451
|
||||
#, python-format
|
||||
msgid "%(value)d active AFP connections"
|
||||
msgstr "%(value)d aktiva AFP-klienter"
|
||||
|
||||
#: templates/index.html:436
|
||||
#: templates/index.html:454
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Install <a href=\"%(url)s\">Netatalk</a> to use the AppleShare File "
|
||||
|
@ -923,56 +988,56 @@ msgstr ""
|
|||
"Installera <a href=\"%(url)s\">Netatalk</a> innan du kan använda "
|
||||
"AppleShare-fildelning."
|
||||
|
||||
#: templates/index.html:443
|
||||
#: templates/index.html:461
|
||||
msgid "Download File and Create CD-ROM image"
|
||||
msgstr "Ladda ner fil och skapa en cd-bildfil"
|
||||
|
||||
#: templates/index.html:446
|
||||
#: templates/index.html:464
|
||||
msgid ""
|
||||
"Create an ISO file system CD-ROM image with the downloaded file, and "
|
||||
"mount it on the given SCSI ID."
|
||||
msgstr ""
|
||||
"Skapar en cd-bildfil med ISO-filsystem som innehåller den nedladdade "
|
||||
"filen. Sedan ansluts den till det angivna SCSI-idt."
|
||||
"filen. Sedan ansluts den till det angivna SCSI-id:t."
|
||||
|
||||
#: templates/index.html:447
|
||||
#: templates/index.html:465
|
||||
msgid "HFS is for Mac OS, Joliet for Windows, and Rock Ridge for POSIX."
|
||||
msgstr "HFS är för Mac OS, Joliet för Windows, samt Rock Ridge för POSIX."
|
||||
|
||||
#: templates/index.html:448
|
||||
#: templates/index.html:466
|
||||
#, python-format
|
||||
msgid "On Mac OS, a <a href=\"%(url)s\">compatible CD-ROM driver</a> is required."
|
||||
msgstr "På Mac OS krävs <a href=\"%(url)s\">kompatibla cd-drivrutiner</a>."
|
||||
|
||||
#: templates/index.html:449
|
||||
#: templates/index.html:467
|
||||
msgid ""
|
||||
"If the downloaded file is a zip archive, we will attempt to unzip it and "
|
||||
"store the resulting files."
|
||||
msgstr ""
|
||||
"Om den nedladdade filen är en zip-fil så försöker vi packa up den och "
|
||||
"spara de uppackade filerna på cd-bildfilen"
|
||||
"spara de uppackade filerna på cd-bildfilen."
|
||||
|
||||
#: templates/index.html:466 templates/index.html:511
|
||||
#: templates/index.html:484 templates/index.html:529
|
||||
msgid "Type:"
|
||||
msgstr "Typ:"
|
||||
|
||||
#: templates/index.html:487
|
||||
#: templates/index.html:505
|
||||
msgid "Download and Mount CD-ROM image"
|
||||
msgstr "Ladda ner och mata in cd-bildfil"
|
||||
|
||||
#: templates/index.html:487
|
||||
#: templates/index.html:505
|
||||
msgid "Downloading File and generating CD-ROM image..."
|
||||
msgstr "Laddar ner fil och tillverkar cd-bildfil..."
|
||||
|
||||
#: templates/index.html:497
|
||||
#: templates/index.html:515
|
||||
msgid "Create Empty Disk Image File"
|
||||
msgstr "Skapa en tom skivbilsdfil"
|
||||
|
||||
#: templates/index.html:500
|
||||
#: templates/index.html:518
|
||||
msgid "The Generic image type is recommended for most computer platforms."
|
||||
msgstr "Bildfilsformatet 'Generic' är rekommederad för de flesta datorsystem."
|
||||
|
||||
#: templates/index.html:501
|
||||
#: templates/index.html:519
|
||||
msgid ""
|
||||
"APPLE GENUINE (.hda) and NEC GENUINE (.hdn) image types will make RaSCSI "
|
||||
"behave as a particular drive type that are recognized by Mac and PC98 "
|
||||
|
@ -982,52 +1047,52 @@ msgstr ""
|
|||
"RaSCSI beter sig som en typ av hårddisk som Macar och PC98-datorer känner"
|
||||
" igen."
|
||||
|
||||
#: templates/index.html:502
|
||||
#: templates/index.html:520
|
||||
msgid ""
|
||||
"SASI images should only be used on the original Sharp X68000, or other "
|
||||
"legacy systems that utilize this pre-SCSI standard."
|
||||
msgstr ""
|
||||
"Bildfilsformatet SASI bör endast användas för den första Sharp "
|
||||
"X68000-modellen eller andra riktigt gamla system som använder denna "
|
||||
"Bildfilsformatet SASI bör endast användas med tidiga Sharp "
|
||||
"X68000-modeller, eller andra riktigt gamla system som använder denna "
|
||||
"föregångare till SCSI."
|
||||
|
||||
#: templates/index.html:509
|
||||
#: templates/index.html:527
|
||||
msgid "File Name:"
|
||||
msgstr "Filnamn:"
|
||||
|
||||
#: templates/index.html:510
|
||||
#: templates/index.html:528
|
||||
msgid "File Name"
|
||||
msgstr "Filnamn"
|
||||
|
||||
#: templates/index.html:514
|
||||
#: templates/index.html:532
|
||||
msgid "SCSI Hard Disk image (Generic) [.hds]"
|
||||
msgstr "SCSI-hårddisk (Generic) [.hds]"
|
||||
|
||||
#: templates/index.html:517
|
||||
#: templates/index.html:535
|
||||
msgid "SCSI Hard Disk image (APPLE GENUINE) [.hda]"
|
||||
msgstr "SCSI-hårddisk (APPLE GENUINE) [.hda]"
|
||||
|
||||
#: templates/index.html:520
|
||||
#: templates/index.html:538
|
||||
msgid "SCSI Hard Disk image (NEC GENUINE) [.hdn]"
|
||||
msgstr "SCSI-hårddisk (NEC GENUINE) [.hdn]"
|
||||
|
||||
#: templates/index.html:523
|
||||
#: templates/index.html:541
|
||||
msgid "SCSI Removable Media Disk image (Generic) [.hdr]"
|
||||
msgstr "SCSI utmatbart medium (Generic) [.hdr]"
|
||||
|
||||
#: templates/index.html:526
|
||||
#: templates/index.html:544
|
||||
msgid "SASI Hard Disk image (Legacy) [.hdf]"
|
||||
msgstr "SASI-hårddisk (föråldrat) [.hdf]"
|
||||
|
||||
#: templates/index.html:529
|
||||
#: templates/index.html:547
|
||||
msgid "Size:"
|
||||
msgstr "Storlek:"
|
||||
|
||||
#: templates/index.html:541
|
||||
#: templates/index.html:559
|
||||
msgid "Create Named Drive"
|
||||
msgstr "Skapa benämnd skiva"
|
||||
|
||||
#: templates/index.html:544
|
||||
#: templates/index.html:562
|
||||
msgid ""
|
||||
"Create pairs of images and properties files from a list of real-life "
|
||||
"drives."
|
||||
|
@ -1035,7 +1100,7 @@ msgstr ""
|
|||
"Skapar ett par av skivbilds- och egenskapsfiler från en lista av verkliga"
|
||||
" enheter."
|
||||
|
||||
#: templates/index.html:545
|
||||
#: templates/index.html:563
|
||||
msgid ""
|
||||
"This will make RaSCSI use certain vendor strings and block sizes that may"
|
||||
" improve compatibility with certain systems."
|
||||
|
@ -1043,86 +1108,103 @@ msgstr ""
|
|||
"På så vis kommer RaSCSI använda vissa tillverkarattribut och "
|
||||
"blockstorlekar som kan hjälpa till med kompatibilitet."
|
||||
|
||||
#: templates/index.html:548
|
||||
#: templates/index.html:566
|
||||
msgid "Create a named disk image that mimics real-life drives"
|
||||
msgstr "Skapa en benämnd skivbildfil som låstas vara en riktig enhet"
|
||||
|
||||
#: templates/index.html:554
|
||||
#: templates/index.html:572
|
||||
msgid "Logging"
|
||||
msgstr "Loggar"
|
||||
|
||||
#: templates/index.html:557
|
||||
#: templates/index.html:575
|
||||
msgid "Fetch a certain number of lines of system logs with the given scope."
|
||||
msgstr "Skaffar ett visst antal loggar för en viss systemprocess."
|
||||
|
||||
#: templates/index.html:564
|
||||
#: templates/index.html:582
|
||||
msgid "Log Lines:"
|
||||
msgstr "Antal loggar:"
|
||||
|
||||
#: templates/index.html:566
|
||||
#: templates/index.html:584
|
||||
msgid "Scope:"
|
||||
msgstr "Process:"
|
||||
|
||||
#: templates/index.html:578
|
||||
#: templates/index.html:596
|
||||
msgid "Show Logs"
|
||||
msgstr "Skaffa loggar"
|
||||
|
||||
#: templates/index.html:588
|
||||
#: templates/index.html:606
|
||||
msgid "Server Log Level"
|
||||
msgstr "Serverns loggnivå"
|
||||
|
||||
#: templates/index.html:591
|
||||
#: templates/index.html:609
|
||||
msgid "Change the log level of the RaSCSI backend process."
|
||||
msgstr "Ändra loggnivån för RaSCSI-servern"
|
||||
msgstr "Byt loggnivån för RaSCSI-servern"
|
||||
|
||||
#: templates/index.html:592
|
||||
#: templates/index.html:610
|
||||
msgid "The current dropdown selection indicates the active log level."
|
||||
msgstr "Det nuvarande valet i rullgardinsmenyn påvisar aktiv loggnivå."
|
||||
|
||||
#: templates/index.html:599
|
||||
#: templates/index.html:617
|
||||
msgid "Log Level:"
|
||||
msgstr "Loggnivå:"
|
||||
|
||||
#: templates/index.html:607
|
||||
#: templates/index.html:625
|
||||
msgid "Set Log Level"
|
||||
msgstr "Ställ in loggnivå"
|
||||
msgstr "Byt loggnivå"
|
||||
|
||||
#: templates/index.html:617
|
||||
#: templates/index.html:635
|
||||
msgid "Language"
|
||||
msgstr "Språk"
|
||||
|
||||
#: templates/index.html:638
|
||||
msgid "Change the Web Interface language."
|
||||
msgstr "Byt webbgränssnittets språk."
|
||||
|
||||
#: templates/index.html:645
|
||||
msgid "Language:"
|
||||
msgstr "Språk:"
|
||||
|
||||
#: templates/index.html:653
|
||||
msgid "Change Language"
|
||||
msgstr "Byt språk"
|
||||
|
||||
#: templates/index.html:663
|
||||
msgid "Raspberry Pi Operations"
|
||||
msgstr "Raspberry Pi-kommandon"
|
||||
|
||||
#: templates/index.html:620
|
||||
#: templates/index.html:666
|
||||
msgid "Reboot or shut down the Raspberry Pi that RaSCSI is running on."
|
||||
msgstr "Starta om eller stäng av Raspberry Pi-systemet som RaSCSI körs på."
|
||||
|
||||
#: templates/index.html:621
|
||||
#: templates/index.html:667
|
||||
msgid ""
|
||||
"IMPORTANT: Always shut down the Pi before turning off the power. Failing "
|
||||
"to do so may lead to data loss."
|
||||
msgstr ""
|
||||
"VIKTIGT: Stäng alltid av Pi-systemet innan du stänger av strömmen. Det "
|
||||
"finns risk för dataförlust."
|
||||
"VIKTIGT: Stäng alltid av Pi-systemet innan du kopplar ur strömmen. På "
|
||||
"så vis undviker du risken att förlora data."
|
||||
|
||||
#: templates/index.html:627
|
||||
#: templates/index.html:673
|
||||
msgid "Reboot the Raspberry Pi?"
|
||||
msgstr "Vill du starta om din Raspberry Pi?"
|
||||
|
||||
#: templates/index.html:627
|
||||
#: templates/index.html:673
|
||||
msgid "Rebooting the Raspberry Pi..."
|
||||
msgstr "Startar om Raspberry Pi..."
|
||||
|
||||
#: templates/index.html:628
|
||||
#: templates/index.html:674
|
||||
msgid "Reboot Raspberry Pi"
|
||||
msgstr "Starta om Raspberry Pi"
|
||||
|
||||
#: templates/index.html:632
|
||||
#: templates/index.html:678
|
||||
msgid "Shut down the Raspberry Pi?"
|
||||
msgstr "Vill du stänga av din Raspberry Pi?"
|
||||
|
||||
#: templates/index.html:632
|
||||
#: templates/index.html:678
|
||||
msgid "Shutting down the Raspberry Pi..."
|
||||
msgstr "Stänger av Raspberry Pi..."
|
||||
|
||||
#: templates/index.html:633
|
||||
#: templates/index.html:679
|
||||
msgid "Shut Down Raspberry Pi"
|
||||
msgstr "Stäng av Raspberry Pi"
|
||||
|
||||
|
|
|
@ -4,9 +4,9 @@ Module for the Flask app rendering and endpoints
|
|||
|
||||
import logging
|
||||
import argparse
|
||||
from sys import argv
|
||||
from pathlib import Path
|
||||
from functools import wraps
|
||||
from hashlib import md5
|
||||
|
||||
from flask import (
|
||||
Flask,
|
||||
|
@ -93,10 +93,13 @@ def get_locale():
|
|||
try:
|
||||
language = session["language"]
|
||||
except KeyError:
|
||||
language = None
|
||||
if language is not None:
|
||||
language = ""
|
||||
logging.warning("The default locale could not be detected. Falling back to English.")
|
||||
if language:
|
||||
return language
|
||||
return request.accept_languages.best_match(LANGUAGES)
|
||||
# Hardcoded fallback to "en" when the user agent does not send an accept-language header
|
||||
language = request.accept_languages.best_match(LANGUAGES) or "en"
|
||||
return language
|
||||
|
||||
|
||||
def get_supported_locales():
|
||||
|
@ -115,7 +118,13 @@ def index():
|
|||
Sets up data structures for and renders the index page
|
||||
"""
|
||||
if not is_token_auth()["status"] and not APP.config["TOKEN"]:
|
||||
abort(403, _(u"RaSCSI is password protected. Start the Web Interface with the --password parameter."))
|
||||
abort(
|
||||
403,
|
||||
_(
|
||||
u"RaSCSI is password protected. "
|
||||
u"Start the Web Interface with the --password parameter."
|
||||
),
|
||||
)
|
||||
|
||||
locales = get_supported_locales()
|
||||
server_info = get_server_info()
|
||||
|
@ -211,7 +220,13 @@ def drive_list():
|
|||
return redirect(url_for("index"))
|
||||
conf = process["conf"]
|
||||
else:
|
||||
flash(_("Could not read drive properties from %(properties_file)s", properties_file=drive_properties), "error")
|
||||
flash(
|
||||
_(
|
||||
"Could not read drive properties from %(properties_file)s",
|
||||
properties_file=drive_properties,
|
||||
),
|
||||
"error",
|
||||
)
|
||||
return redirect(url_for("index"))
|
||||
|
||||
hd_conf = []
|
||||
|
@ -275,7 +290,13 @@ def login():
|
|||
if authenticate(str(username), str(password)):
|
||||
session["username"] = request.form["username"]
|
||||
return redirect(url_for("index"))
|
||||
flash(_(u"You must log in with credentials for a user in the '%(group)s' group", group=AUTH_GROUP), "error")
|
||||
flash(
|
||||
_(
|
||||
u"You must log in with credentials for a user in the '%(group)s' group",
|
||||
group=AUTH_GROUP,
|
||||
),
|
||||
"error",
|
||||
)
|
||||
return redirect(url_for("index"))
|
||||
|
||||
|
||||
|
@ -413,7 +434,7 @@ def config_load():
|
|||
|
||||
flash(process['msg'], "error")
|
||||
return redirect(url_for("index"))
|
||||
elif "delete" in request.form:
|
||||
if "delete" in request.form:
|
||||
process = delete_file(f"{CFG_DIR}/{file_name}")
|
||||
if process["status"]:
|
||||
flash(process["msg"])
|
||||
|
@ -609,8 +630,8 @@ def detach():
|
|||
id_number=scsi_id, unit_number=unit))
|
||||
return redirect(url_for("index"))
|
||||
|
||||
flash(_(u"Failed to detach %(file_name)s from SCSI ID %(id_number)s LUN %(unit_number)s",
|
||||
file_name=file_name, id_number=scsi_id, unit_number=unit), "error")
|
||||
flash(_(u"Failed to detach SCSI ID %(id_number)s LUN %(unit_number)s",
|
||||
id_number=scsi_id, unit_number=unit), "error")
|
||||
flash(process["msg"], "error")
|
||||
return redirect(url_for("index"))
|
||||
|
||||
|
@ -630,8 +651,8 @@ def eject():
|
|||
id_number=scsi_id, unit_number=unit))
|
||||
return redirect(url_for("index"))
|
||||
|
||||
flash(_(u"Failed to eject %(file_name)s from SCSI ID %(id_number)s LUN %(unit_number)s",
|
||||
file_name=file_name, id_number=scsi_id, unit_number=unit), "error")
|
||||
flash(_(u"Failed to eject SCSI ID %(id_number)s LUN %(unit_number)s",
|
||||
id_number=scsi_id, unit_number=unit), "error")
|
||||
flash(process["msg"], "error")
|
||||
return redirect(url_for("index"))
|
||||
|
||||
|
@ -769,7 +790,7 @@ def download_img():
|
|||
"""
|
||||
url = request.form.get("url")
|
||||
server_info = get_server_info()
|
||||
process = download_to_dir(url, server_info["image_dir"])
|
||||
process = download_to_dir(url, server_info["image_dir"], Path(url).name)
|
||||
if process["status"]:
|
||||
flash(process["msg"])
|
||||
return redirect(url_for("index"))
|
||||
|
@ -786,7 +807,19 @@ def download_afp():
|
|||
Downloads a remote file onto the AFP shared dir on the Pi
|
||||
"""
|
||||
url = request.form.get("url")
|
||||
process = download_to_dir(url, AFP_DIR)
|
||||
file_name = Path(url).name
|
||||
# Shorten file names longer than 31 chars, the HFS upper limit
|
||||
# Append a hash of the removed piece of the file name to make it unique
|
||||
# The format of the hash is a # followed by the first four symbols of the md4 hash
|
||||
if len(file_name) > 31:
|
||||
chars_to_cut = len(file_name) - 31
|
||||
file_name_stem = Path(file_name).stem
|
||||
file_name_suffix = Path(file_name).suffix
|
||||
discarded_portion = file_name_stem[:-abs(chars_to_cut)]
|
||||
stem_remainder = file_name_stem[:(26 - len(file_name_suffix))]
|
||||
appendix_hash = (md5(discarded_portion.encode("utf-8"))).hexdigest().upper()
|
||||
file_name = stem_remainder + "#" + appendix_hash[:4] + file_name_suffix
|
||||
process = download_to_dir(url, AFP_DIR, file_name)
|
||||
if process["status"]:
|
||||
flash(process["msg"])
|
||||
return redirect(url_for("index"))
|
||||
|
@ -837,10 +870,14 @@ def upload_file():
|
|||
if current_chunk + 1 == total_chunks:
|
||||
# Validate the resulting file size after writing the last chunk
|
||||
if path.getsize(save_path) != int(request.form["dztotalfilesize"]):
|
||||
log.error("Finished transferring %s, "
|
||||
"but it has a size mismatch with the original file."
|
||||
"Got %s but we expected %s.",
|
||||
file_object.filename, path.getsize(save_path), request.form['dztotalfilesize'])
|
||||
log.error(
|
||||
"Finished transferring %s, "
|
||||
"but it has a size mismatch with the original file. "
|
||||
"Got %s but we expected %s.",
|
||||
file_object.filename,
|
||||
path.getsize(save_path),
|
||||
request.form['dztotalfilesize'],
|
||||
)
|
||||
return make_response(_(u"Transferred file corrupted!"), 500)
|
||||
|
||||
log.info("File %s has been uploaded successfully", file_object.filename)
|
||||
|
@ -973,6 +1010,9 @@ def unzip():
|
|||
|
||||
@APP.route("/language", methods=["POST"])
|
||||
def change_language():
|
||||
"""
|
||||
Changes the session language locale and refreshes the Flask app context
|
||||
"""
|
||||
locale = request.form.get("locale")
|
||||
session["language"] = locale
|
||||
refresh()
|
||||
|
@ -1013,9 +1053,9 @@ if __name__ == "__main__":
|
|||
action="store",
|
||||
help="Token password string for authenticating with RaSCSI",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
APP.config["TOKEN"] = args.password
|
||||
arguments = parser.parse_args()
|
||||
APP.config["TOKEN"] = arguments.password
|
||||
|
||||
import bjoern
|
||||
print("Serving rascsi-web...")
|
||||
bjoern.run(APP, "0.0.0.0", args.port)
|
||||
bjoern.run(APP, "0.0.0.0", arguments.port)
|
||||
|
|
Loading…
Reference in New Issue