+++ /dev/null
-SCSI2SD is distributed under the GNU General Public License version 3. Please
-find the license in the file gplv3.txt
-
-The additional license terms apply:
-
-////////////////////////////////////////////////////////////////////////////////////
-Code generated via STM32CubeMX:
-
-COPYRIGHT(c) 2015 STMicroelectronics
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
- 1. Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
- 3. Neither the name of STMicroelectronics nor the names of its contributors
- may be used to endorse or promote products derived from this software
- without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-////////////////////////////////////////////////////////////////////////////////////
-ARM CMSIS, distributed with STM32CubeMX:
-
-Copyright (c) 2009 - 2015 ARM LIMITED
-
-All rights reserved.
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-- Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-- Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-- Neither the name of ARM nor the names of its contributors may be used
- to endorse or promote products derived from this software without
- specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
-
-
<groupId>com.codesrc</groupId>
<artifactId>scsi2sd-util</artifactId>
<version>1.0-SNAPSHOT</version>
- <packaging>jar</packaging>
+ <modules>
+ <module>scsi2sd.io</module>
+ <module>scsi2sd.ui</module>
+ </modules>
+ <packaging>pom</packaging>
<name>SCSI2SD Utility</name>
<url>http://www.codesrc.com</url>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
- <build>
- <directory>target</directory>
- <outputDirectory>target/classes</outputDirectory>
- <finalName>${project.artifactId}-${project.version}</finalName>
-
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-compiler-plugin</artifactId>
- <version>3.3</version>
- <configuration>
- <source>1.8</source>
- <target>1.8</target>
- </configuration>
- </plugin>
- <plugin>
- <groupId>com.zenjava</groupId>
- <artifactId>javafx-maven-plugin</artifactId>
- <version>8.8.3</version>
- <configuration>
- <mainClass>com.codesrc.scsi2sd.App</mainClass>
- <vendor>com.codesrc</vendor>
- <needMenu>true</needMenu>
- <appName>SCSI2SD Utility</appName>
- <additionalAppResources>doc</additionalAppResources>
- </configuration>
- <executions>
- <execution>
- <!-- required before build-native -->
- <id>create-jfxjar</id>
- <phase>package</phase>
- <goals>
- <goal>build-jar</goal>
- </goals>
- </execution>
- <execution>
- <id>create-native</id>
- <phase>package</phase>
- <goals>
- <goal>build-native</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
- </plugins>
- </build>
-
-
- <dependencies>
-<!--
- <dependency>
- <groupId>javafx-packager</groupId>
- <artifactId>javafx-packager</artifactId>
- <version>1.8.0_20</version>
- <scope>system</scope>
- <systemPath>${java.home}/../lib/ant-javafx.jar</systemPath>
- </dependency>
--->
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-context</artifactId>
- <version>4.3.8.RELEASE</version>
- <exclusions>
- <exclusion>
- <groupId>commons-logging</groupId>
- <artifactId>commons-logging</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
-
- <dependency>
- <groupId>org.controlsfx</groupId>
- <artifactId>controlsfx</artifactId>
- <version>8.40.12</version>
- </dependency>
-
- <!-- LogBack dependencies -->
- <dependency>
- <groupId>ch.qos.logback</groupId>
- <artifactId>logback-classic</artifactId>
- <version>1.2.3</version>
- </dependency>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>jcl-over-slf4j</artifactId>
- <version>1.7.25</version>
- </dependency>
- </dependencies>
</project>
--- /dev/null
+<project
+ xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>com.codesrc</groupId>
+ <artifactId>scsi2sd-util</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>scsi2sd.io</artifactId>
+ <packaging>jar</packaging>
+
+ <name>scsi2sd.io</name>
+ <url>http://www.codesrc.com</url>
+ <developers>
+ <developer>
+ <name>Michael McMaster</name>
+ <email>michael@codesrc.com</email>
+ </developer>
+ </developers>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+
+ <build>
+ <directory>target</directory>
+ <outputDirectory>target/classes</outputDirectory>
+ <finalName>${project.artifactId}-${project.version}</finalName>
+
+ <resources>
+ <resource>
+ <directory>doc</directory>
+ </resource>
+ <resource>
+ <directory>src/main/resources</directory>
+ </resource>
+
+ </resources>
+
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.8.0</version>
+ <configuration>
+ <source>10</source>
+ <target>10</target>
+ </configuration>
+ </plugin>
+
+
+ <!--<plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <version>3.1.1</version>
+ <executions>
+ <execution>
+ <id>copy-dependencies</id>
+ <phase>package</phase>
+ <goals>
+ <goal>copy-dependencies</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>${project.build.directory}/install</outputDirectory>
+ <overWriteReleases>false</overWriteReleases>
+ <overWriteSnapshots>false</overWriteSnapshots>
+ <overWriteIfNewer>true</overWriteIfNewer>
+ <excludeGroupIds>org.hid4java,net.java.dev.jna</excludeGroupIds>
+ <excludeScope>test</excludeScope>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>-->
+
+ <plugin>
+ <groupId>org.moditect</groupId>
+ <artifactId>moditect-maven-plugin</artifactId>
+ <version>1.0.0.Beta2</version>
+ <executions>
+ <execution>
+ <id>add-module-infos</id>
+ <phase>generate-resources</phase>
+ <goals>
+ <goal>add-module-info</goal>
+ </goals>
+
+ <configuration>
+ <outputDirectory>${project.build.directory}/install</outputDirectory>
+ <modules>
+ <module>
+ <artifact>
+ <groupId>org.hid4java</groupId>
+ <artifactId>hid4java</artifactId>
+ <version>0.5.0</version>
+ </artifact>
+ <moduleInfoSource>
+ open module hid4java {
+ requires jna;
+ exports org.hid4java;
+ exports org.hid4java.jna to jna;
+ exports org.hid4java.event to com.codesrc.scsi2sd.io;
+
+ // native libraries. Use jimage on the jlink'd module file
+ // to list the relevant directories (which get
+ // turned into packages)
+ // (disabled and open'd entire module because the
+ // hyphen in the directory names causes parse problems)
+ //exports darwin;
+ //exports win32-amd64;
+ //exports linux-amd64;
+ //exports linux-x86-64;
+ }
+ </moduleInfoSource>
+ </module>
+
+ <module>
+ <artifact>
+ <groupId>net.java.dev.jna</groupId>
+ <artifactId>jna</artifactId>
+ <version>5.5.0</version>
+ </artifact>
+ <moduleInfoSource>
+ // Open is required to access the native library resources
+ open module jna {
+ exports com.sun.jna;
+ requires java.logging;
+ }
+ </moduleInfoSource>
+ </module>
+ </modules>
+ </configuration>
+
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+
+ <dependencies>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <version>1.8.0-beta2</version>
+ </dependency>
+
+ <dependency>
+ <groupId>net.java.dev.jna</groupId>
+ <artifactId>jna</artifactId>
+ <version>5.2.0</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.hid4java</groupId>
+ <artifactId>hid4java</artifactId>
+ <version>0.5.0</version>
+ <exclusions>
+ <exclusion> <!-- declare the exclusion here -->
+ <groupId>net.java.dev.jna</groupId>
+ <artifactId>jna</artifactId>
+ </exclusion>
+ </exclusions>
+
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.12</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
+
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
+ <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_10">
+ <output url="file://$MODULE_DIR$/target/classes" />
+ <output-test url="file://$MODULE_DIR$/target/test-classes" />
+ <content url="file://$MODULE_DIR$">
+ <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
+ <sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
+ <sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
+ <excludeFolder url="file://$MODULE_DIR$/target" />
+ </content>
+ <orderEntry type="inheritedJdk" />
+ <orderEntry type="sourceFolder" forTests="false" />
+ <orderEntry type="library" name="Maven: org.slf4j:slf4j-api:1.8.0-beta2" level="project" />
+ <orderEntry type="library" name="Maven: net.java.dev.jna:jna:5.2.0" level="project" />
+ <orderEntry type="library" name="Maven: org.hid4java:hid4java:0.5.0" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: junit:junit:4.12" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: org.hamcrest:hamcrest-core:1.3" level="project" />
+ </component>
+</module>
\ No newline at end of file
--- /dev/null
+// Copyright (C) 2019 Michael McMaster <michael@codesrc.com>
+//
+// This file is part of scsi2sd-util.
+//
+// scsi2sd-util is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// scsi2sd-util is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with scsi2sd-util. If not, see <https://www.gnu.org/licenses/>.
+
+package com.codesrc.scsi2sd.io;
+
+public enum Commands {
+ NONE, // Invalid
+
+ // Command content:
+ // uint8_t S2S_CFG_PING
+ // Response:
+ // S2S_CFG_STATUS
+ PING,
+
+ // Command content:
+ // uint8_t S2S_CFG_WRITEFLASH
+ // uint8_t[256] flashData
+ // uint8_t flashArray
+ // uint8_t flashRow
+ // Response:
+ // S2S_CFG_STATUS
+ WRITEFLASH,
+
+ // Command content:
+ // uint8_t S2S_CFG_READFLASH
+ // uint8_t flashArray
+ // uint8_t flashRow
+ // Response:
+ // 256 bytes of flash
+ READFLASH,
+
+ // Command content:
+ // uint8_t S2S_CFG_REBOOT
+ // Response: None.
+ REBOOT,
+
+ // Command content:
+ // uint8_t S2S_CFG_INFO
+ // Response:
+ // uint8_t[16] CSD
+ // uint8_t[16] CID
+ SDINFO,
+
+ // Command content:
+ // uint8_t S2S_CFG_SCSITEST
+ // Response:
+ // S2S_CFG_STATUS
+ // uint8_t result code (0 = passed)
+ SCSITEST,
+
+ // Command content:
+ // uint8_t S2S_CFG_DEVINFO
+ // Response:
+ // uint16_t protocol version (MSB)
+ // uint16_t firmware version (MSB)
+ // uint32_t SD capacity(MSB)
+ DEVINFO,
+
+ // Command content:
+ // uint8_t S2S_CFG_SD_WRITE
+ // uint32_t Sector Number (MSB)
+ // uint8_t[512] data
+ // Response:
+ // S2S_CFG_STATUS
+ SD_WRITE,
+
+ // Command content:
+ // uint8_t S2S_CFG_SD_READ
+ // uint32_t Sector Number (MSB)
+ // Response:
+ // 512 bytes of data
+ SD_READ,
+
+ // Command content:
+ // uint8_t S2S_CFG_DEBUG
+ // Response:
+ DEBUG,
+}
--- /dev/null
+// Copyright (C) 2019 Michael McMaster <michael@codesrc.com>
+//
+// This file is part of scsi2sd-util.
+//
+// scsi2sd-util is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// scsi2sd-util is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with scsi2sd-util. If not, see <https://www.gnu.org/licenses/>.
+
+package com.codesrc.scsi2sd.io;
+
+import java.util.Arrays;
+
+// scsi2sd custom protocol for sending packet data over a USB HID
+// interface,
+class HidPacketProtocol {
+ static final int USBHID_LEN = 64;
+
+ // Maximum packet payload length. Must be large enough to support a SD sector
+ // + sector number
+ static final int HIDPACKET_MAX_LEN = 520;
+
+ private enum State { IDLE, PARTIAL, COMPLETE };
+ private class PacketState {
+ PacketState() {
+ this.reset();
+ }
+
+ void reset() {
+ this.state = State.IDLE;
+ this.chunk = 0;
+ this.offset = 0;
+ }
+
+ byte[] buffer = new byte[HIDPACKET_MAX_LEN];
+ State state;
+ int chunk;
+ int offset; // Current offset into buffer.
+ }
+
+ private PacketState rx = new PacketState();
+ private PacketState tx = new PacketState();
+
+ // Process data received over USB HID
+ public void receiveHIDData(byte[] bytes) {
+ if (bytes.length < 2) {
+ // Invalid. We need at least a chunk number and payload length.
+ this.rx.reset();
+ return;
+ }
+
+ int chunk = bytes[0] & 0x7F;
+ boolean isFinal = (bytes[0] & 0x80) == 0x80;
+ int payloadLen = uint8ToInt(bytes[1]);
+ if ((payloadLen > (bytes.length - 2)) || // short packet
+ (payloadLen + this.rx.offset > this.rx.buffer.length)) { // buffer overflow
+ this.rx.reset();
+ return;
+ }
+
+ if (chunk == 0) {
+ // Initial chunk
+ this.rx.reset();
+ System.arraycopy(bytes, 2, this.rx.buffer, 0, payloadLen);
+ this.rx.offset = payloadLen;
+ this.rx.state = State.PARTIAL;
+ }
+ else if ((this.rx.state == State.PARTIAL) && (chunk == this.rx.chunk + 1)) {
+ System.arraycopy(bytes, 2, this.rx.buffer, this.rx.offset, payloadLen);
+ this.rx.offset += payloadLen;
+ this.rx.chunk++;
+ }
+ else if (chunk == this.rx.chunk) {
+ // duplicated packet. ignore.
+ }
+ else {
+ // invalid. Maybe we missed some data.
+ this.rx.reset();
+ }
+
+ if ((this.rx.state == State.PARTIAL) && isFinal)
+ {
+ this.rx.state = State.COMPLETE;
+ }
+ }
+
+ public byte[] getPacket() {
+ if (this.rx.state == State.COMPLETE) {
+ byte[] result = Arrays.copyOf(this.rx.buffer, this.rx.offset);
+ this.rx.reset();
+ return result;
+ } else {
+ return null;
+ }
+ }
+
+ public void sendPacket(byte[] packet)
+ {
+ if (packet.length <= this.tx.buffer.length) {
+ this.tx.state = State.PARTIAL;
+ this.tx.chunk = 0;
+ this.tx.offset = packet.length;
+ System.arraycopy(packet, 0, this.tx.buffer, 0, packet.length);
+ }
+ else {
+ this.tx.reset();
+ }
+ }
+
+ public byte[] getHIDBytes() {
+ if ((this.tx.state != State.PARTIAL) || (this.tx.offset <= 0))
+ {
+ return null;
+ }
+
+ byte[] hidBuffer = new byte[USBHID_LEN];
+ hidBuffer[0] = intToUint8(this.tx.chunk);
+ this.tx.chunk++;
+ int payload;
+ if (this.tx.offset <= USBHID_LEN - 2)
+ {
+ hidBuffer[0] = intToUint8(hidBuffer[0] | 0x80);
+ payload = this.tx.offset;
+ this.tx.state = State.IDLE;
+ }
+ else
+ {
+ payload = USBHID_LEN - 2;
+ }
+
+ this.tx.offset -= payload;
+ hidBuffer[1] = intToUint8(payload);
+ System.arraycopy(this.tx.buffer, 0, hidBuffer, 2, payload);
+
+ // memmove
+ for (int i = payload; i < this.tx.buffer.length; ++i)
+ {
+ this.tx.buffer[i - payload] = this.tx.buffer[i];
+ }
+
+ return hidBuffer;
+ }
+
+
+ public static int uint8ToInt(byte data) {
+ return (int) data & 0xFF;
+ }
+
+ public static byte intToUint8(int data) {
+ return (byte) (data & 0xFF);
+ }
+}
--- /dev/null
+// Copyright (C) 2019 Michael McMaster <michael@codesrc.com>
+//
+// This file is part of scsi2sd-util.
+//
+// scsi2sd-util is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// scsi2sd-util is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with scsi2sd-util. If not, see <https://www.gnu.org/licenses/>.
+
+package com.codesrc.scsi2sd.io;
+
+import org.hid4java.HidDevice;
+
+public class HidPacketProtocolDevice {
+
+ private HidDevice hidDevice;
+ private HidPacketProtocol protocol;
+
+ public HidPacketProtocolDevice(HidDevice hidDevice) {
+ this.hidDevice = hidDevice;
+ this.protocol = new HidPacketProtocol();
+ }
+
+ public byte[] sendHIDPacket(byte[] cmd, int responseLength)
+ {
+ assert(cmd.length <= HidPacketProtocol.HIDPACKET_MAX_LEN);
+
+ this.protocol.sendPacket(cmd);
+
+ byte[] chunk = this.protocol.getHIDBytes();
+ while (chunk != null)
+ {
+ int result = -1;
+ for (int retry = 0; retry < 10 && result <= 0; ++retry)
+ {
+ result = this.hidDevice.write(chunk, chunk.length, (byte)0x00);
+ }
+
+ if (result <= 0)
+ {
+ throw new RuntimeException("USB HID write failure: " + this.hidDevice.getLastErrorMessage());
+ }
+ chunk = this.protocol.getHIDBytes();
+ }
+
+ byte[] readBuffer = new byte[HidPacketProtocol.HIDPACKET_MAX_LEN];
+ byte[] resp = this.protocol.getPacket();
+ for (int retry = 0; retry < responseLength * 2 && resp == null; ++retry)
+ {
+ this.hidDevice.read(readBuffer); // Will block
+ this.protocol.receiveHIDData(readBuffer);
+ resp = this.protocol.getPacket();
+ }
+
+ if (resp == null)
+ {
+ throw new RuntimeException("SCSI2SD USB protocol error");
+ }
+ return resp;
+ }
+}
--- /dev/null
+// Copyright (C) 2019 Michael McMaster <michael@codesrc.com>
+//
+// This file is part of scsi2sd-util.
+//
+// scsi2sd-util is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// scsi2sd-util is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with scsi2sd-util. If not, see <https://www.gnu.org/licenses/>.
+
+package com.codesrc.scsi2sd.io;
+
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.function.Consumer;
+
+public class SimpleEvent<EventParamT> {
+ private ConcurrentLinkedQueue<Consumer<EventParamT>> observers = new ConcurrentLinkedQueue<Consumer<EventParamT>>();
+
+ public void subscribe(Consumer<EventParamT> observer) {
+ observers.add(observer);
+ }
+
+ public void unsubscribe(Consumer<EventParamT> observer) {
+ observers.remove(observer);
+ }
+
+ public void trigger(EventParamT param) {
+ for (Consumer<EventParamT> observer : observers) {
+ observer.accept(param);
+ }
+ }
+}
--- /dev/null
+// Copyright (C) 2019 Michael McMaster <michael@codesrc.com>
+//
+// This file is part of scsi2sd-util.
+//
+// scsi2sd-util is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// scsi2sd-util is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with scsi2sd-util. If not, see <https://www.gnu.org/licenses/>.
+
+package com.codesrc.scsi2sd.io;
+
+/**
+ * Created by michael on 27/08/18.
+ */
+public interface UsbDevice {
+ String getHardwareDescription();
+
+ int getFirmwareVersion();
+ String getFirmwareDescription();
+ int getSdCapacity();
+
+ int getMaxDisks();
+ byte[] readBoardConfig();
+
+ byte[] readDiskConfig(int index);
+
+ void saveBoardConfig(byte[] data);
+ void saveDiskConfig(int index, byte[] data);
+ void saveCommit();
+
+ boolean supportsTerminator();
+ boolean supportsSynchronous();
+}
--- /dev/null
+// Copyright (C) 2019 Michael McMaster <michael@codesrc.com>
+//
+// This file is part of scsi2sd-util.
+//
+// scsi2sd-util is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// scsi2sd-util is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with scsi2sd-util. If not, see <https://www.gnu.org/licenses/>.
+
+package com.codesrc.scsi2sd.io;
+
+/**
+ * Created by michael on 27/08/18.
+ */
+public class UsbDeviceConnectedEvent {
+ private UsbDevice usbDevice;
+
+ public UsbDeviceConnectedEvent(UsbDevice usbDevice) {
+ this.usbDevice = usbDevice;
+ }
+
+ public UsbDevice getUsbDevice() {
+ return usbDevice;
+ }
+}
+
+
--- /dev/null
+// Copyright (C) 2019 Michael McMaster <michael@codesrc.com>
+//
+// This file is part of scsi2sd-util.
+//
+// scsi2sd-util is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// scsi2sd-util is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with scsi2sd-util. If not, see <https://www.gnu.org/licenses/>.
+
+package com.codesrc.scsi2sd.io;
+
+
+/**
+ * Created by michael on 27/08/18.
+ */
+public class UsbDeviceDisconnectedEvent {
+ private UsbDevice usbDevice;
+
+ public UsbDeviceDisconnectedEvent(UsbDevice device) {
+ this.usbDevice = usbDevice;
+ }
+
+ public UsbDevice getUsbDevice() {
+ return usbDevice;
+ }
+}
--- /dev/null
+// Copyright (C) 2019 Michael McMaster <michael@codesrc.com>
+//
+// This file is part of scsi2sd-util.
+//
+// scsi2sd-util is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// scsi2sd-util is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with scsi2sd-util. If not, see <https://www.gnu.org/licenses/>.
+
+package com.codesrc.scsi2sd.io;
+
+/**
+ * Created by michael on 27/08/18.
+ */
+public class UsbDeviceFailedEvent {
+ private String devicePath;
+ private String message;
+
+ public UsbDeviceFailedEvent(String devicePath, String message) {
+ this.devicePath = devicePath;
+ this.message = message;
+ }
+
+ public String getUsbDevicePath() {
+ return devicePath;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+}
+
+
--- /dev/null
+// Copyright (C) 2019 Michael McMaster <michael@codesrc.com>
+//
+// This file is part of scsi2sd-util.
+//
+// scsi2sd-util is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// scsi2sd-util is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with scsi2sd-util. If not, see <https://www.gnu.org/licenses/>.
+
+package com.codesrc.scsi2sd.io;
+
+import java.util.List;
+
+/**
+ * Created by michael on 27/08/18.
+ */
+public interface UsbDeviceManager {
+
+ List<UsbDevice> getDevices();
+ void shutdown();
+
+ SimpleEvent<UsbDeviceConnectedEvent> getDeviceConnectedEvent();
+ SimpleEvent<UsbDeviceDisconnectedEvent> getDeviceDisconnectedEvent();
+
+ SimpleEvent<UsbDeviceFailedEvent> getDeviceFailedEvent();
+
+ static UsbDeviceManager getInstance() {
+ return UsbDeviceManagerImpl.getInstance();
+ }
+
+}
--- /dev/null
+// Copyright (C) 2019 Michael McMaster <michael@codesrc.com>
+//
+// This file is part of scsi2sd-util.
+//
+// scsi2sd-util is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// scsi2sd-util is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with scsi2sd-util. If not, see <https://www.gnu.org/licenses/>.
+
+package com.codesrc.scsi2sd.io;
+
+import org.hid4java.*;
+import org.hid4java.event.HidServicesEvent;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.*;
+
+class UsbDeviceManagerImpl implements UsbDeviceManager, HidServicesListener {
+ private static org.slf4j.Logger LOGGER = LoggerFactory.getLogger(UsbDeviceManagerImpl.class.getPackageName());
+ private static UsbDeviceManagerImpl INSTANCE = new UsbDeviceManagerImpl();
+
+ private SimpleEvent<UsbDeviceConnectedEvent> deviceConnectedEvent = new SimpleEvent<>();
+ private SimpleEvent<UsbDeviceDisconnectedEvent> deviceDisconnectedEvent = new SimpleEvent<>();
+ private SimpleEvent<UsbDeviceFailedEvent> deviceFailedEvent = new SimpleEvent<>();
+
+ private final ScheduledExecutorService scheduler;
+
+
+ private HidServices hidServices;
+ private Map<HidDevice, UsbDevice> devices = new ConcurrentHashMap<>();
+
+ public static UsbDeviceManager getInstance() {
+ return INSTANCE;
+ }
+
+ public UsbDeviceManagerImpl()
+ {
+ scheduler = Executors.newScheduledThreadPool(1);
+
+ LOGGER.debug("Initialising UsbDeviceManagerImpl");
+
+ HidServicesSpecification spec = new HidServicesSpecification();
+ spec.setScanMode(ScanMode.NO_SCAN);
+
+ hidServices = HidManager.getHidServices(spec);
+ hidServices.getAttachedHidDevices().forEach(d -> this.attached(d));
+ hidServices.addHidServicesListener(this);
+
+ scheduler.scheduleWithFixedDelay(() -> this.poll(), 1, 1, TimeUnit.SECONDS);
+
+ LOGGER.debug("Initialised UsbDeviceManagerImpl");
+ }
+
+ @Override
+ public void shutdown()
+ {
+ scheduler.shutdown();
+ scheduler.shutdownNow(); // Cancel currently executing tasks
+
+ // Wait a while for tasks to respond to being cancelled
+ try {
+ if (!scheduler.awaitTermination(60, TimeUnit.SECONDS)) {
+ LOGGER.error("Scheduler did not terminate");
+ }
+ hidServices.shutdown();
+ }
+ catch (InterruptedException ie) {
+ Thread.currentThread().interrupt();
+ }
+ }
+
+ @Override
+ public List<UsbDevice> getDevices() {
+ return new ArrayList<>(devices.values());
+ }
+
+ private void poll() {
+ LOGGER.trace("Polling Usb Devices");
+
+ try {
+ hidServices.scan();
+ } catch (Exception e)
+ {
+ LOGGER.error("Failure scanning USB devices", e);
+ }
+
+ LOGGER.trace("Polling Complete");
+ }
+
+ public SimpleEvent<UsbDeviceConnectedEvent> getDeviceConnectedEvent() {
+ return deviceConnectedEvent;
+ }
+
+ public SimpleEvent<UsbDeviceDisconnectedEvent> getDeviceDisconnectedEvent() {
+ return deviceDisconnectedEvent;
+ }
+
+ public SimpleEvent<UsbDeviceFailedEvent> getDeviceFailedEvent() {
+ return deviceFailedEvent;
+ }
+
+ @Override
+ public void hidDeviceAttached(HidServicesEvent hidServicesEvent) {
+ try {
+ LOGGER.debug("Usb Device attached {}", hidServicesEvent.getHidDevice().getPath());
+
+ this.attached(hidServicesEvent.getHidDevice());
+ } catch (Exception e) {
+ LOGGER.error("Exception in UsbDeviceManagerImpl.hidDeviceAttached", e);
+ }
+ }
+
+ @Override
+ public void hidDeviceDetached(HidServicesEvent hidServicesEvent) {
+ try {
+ LOGGER.debug("Usb Device detached {}", hidServicesEvent.getHidDevice().getPath());
+ this.detached(hidServicesEvent.getHidDevice());
+ } catch (Exception e) {
+ LOGGER.error("Exception in UsbDeviceManagerImpl.hidDeviceDettached", e);
+ }
+
+ }
+
+ @Override
+ public void hidFailure(HidServicesEvent hidServicesEvent) {
+ LOGGER.warn("Usb Device failure {}", hidServicesEvent.toString());
+ }
+
+ private void detached(HidDevice hidDevice) {
+ UsbDevice attachedDevice = devices.get(hidDevice);
+ if (attachedDevice != null) {
+ devices.remove(attachedDevice);
+
+ LOGGER.info("Detached SCSI2SD");
+
+ this.deviceDisconnectedEvent.trigger(new UsbDeviceDisconnectedEvent(attachedDevice));
+ }
+ if (hidDevice.isOpen()) {
+ hidDevice.close();
+ }
+ }
+
+ private void attached(HidDevice hidDevice) {
+ if (devices.containsKey(hidDevice)) {
+ // Why are we getting this again ?
+ LOGGER.warn("Usb Device duplicate attach {}", hidDevice.getPath());
+
+ return;
+ }
+
+ if (!devices.isEmpty()) {
+ // UI only supports one device for now
+ return;
+ }
+
+ UsbDevice attachedDevice = null;
+
+ try {
+ if (hidDevice.getVendorId() == V6FirmwareUsbDevice.VENDOR_ID &&
+ hidDevice.getProductId() == V6FirmwareUsbDevice.PRODUCT_ID) {
+
+ attachedDevice = new V6FirmwareUsbDevice(hidDevice);
+ this.devices.put(hidDevice, attachedDevice);
+ } else if (hidDevice.getVendorId() == V3FirmwareUsbDevice.VENDOR_ID &&
+ hidDevice.getProductId() == V3FirmwareUsbDevice.PRODUCT_ID) {
+
+ if (hidDevice.getInterfaceNumber() == 0
+ || hidDevice.getUsagePage() == (short) 0xFF00) {
+
+ // Search for the 2nd interface.
+ for (HidDevice dbgDev : hidServices.getAttachedHidDevices()) {
+ if (dbgDev.getVendorId() == V3FirmwareUsbDevice.VENDOR_ID &&
+ dbgDev.getProductId() == V3FirmwareUsbDevice.PRODUCT_ID &&
+ (dbgDev.getInterfaceNumber() == 1 || hidDevice.getUsagePage() == (short) 0xFF01) &&
+ !this.devices.containsKey(dbgDev)) {
+ attachedDevice = new V3FirmwareUsbDevice(hidDevice, dbgDev);
+ this.devices.put(dbgDev, attachedDevice);
+ this.devices.put(hidDevice, attachedDevice);
+ }
+ }
+
+ } else if (hidDevice.getInterfaceNumber() == 1
+ || hidDevice.getUsagePage() == (short) 0xFF01) {
+
+ // Search for the 1st interface.
+ for (HidDevice cfgDev : hidServices.getAttachedHidDevices()) {
+ if (cfgDev.getVendorId() == V3FirmwareUsbDevice.VENDOR_ID &&
+ cfgDev.getProductId() == V3FirmwareUsbDevice.PRODUCT_ID &&
+ (cfgDev.getInterfaceNumber() == 0 || hidDevice.getUsagePage() == (short) 0xFF00) &&
+ !this.devices.containsKey(cfgDev)) {
+ attachedDevice = new V3FirmwareUsbDevice(cfgDev, hidDevice);
+ this.devices.put(cfgDev, attachedDevice);
+ this.devices.put(hidDevice, attachedDevice);
+ }
+ }
+ }
+ }
+
+ if (attachedDevice != null) {
+ LOGGER.info("Attached SCSI2SD.\n\tHardware: {}\n\tFirmware: {}",
+ attachedDevice.getHardwareDescription(),
+ attachedDevice.getFirmwareDescription());
+
+ deviceConnectedEvent.trigger((new UsbDeviceConnectedEvent(attachedDevice)));
+ }
+ } catch (RuntimeException e) {
+ deviceFailedEvent.trigger(new UsbDeviceFailedEvent(hidDevice.getPath(), e.getMessage()));
+ throw e;
+ }
+ }
+}
--- /dev/null
+// Copyright (C) 2019 Michael McMaster <michael@codesrc.com>
+//
+// This file is part of scsi2sd-util.
+//
+// scsi2sd-util is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// scsi2sd-util is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with scsi2sd-util. If not, see <https://www.gnu.org/licenses/>.
+
+package com.codesrc.scsi2sd.io;
+
+import org.hid4java.HidDevice;
+import org.hid4java.HidServices;
+import org.slf4j.LoggerFactory;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+public class V3FirmwareUsbDevice implements UsbDevice {
+ private static org.slf4j.Logger LOGGER = LoggerFactory.getLogger(V3FirmwareUsbDevice.class.getPackageName());
+
+ public static final short VENDOR_ID = 0x04B4; // Cypress
+ public static final short PRODUCT_ID = 0x1337; // SCSI2SD
+
+ private static final int MAX_SCSI_TARGETS = 4;
+ private static final int SCSI_CONFIG_ARRAY = 1;
+ private static final int SCSI_CONFIG_ROWS = 16;
+
+// 256 bytes data, 32 bytes ECC
+ private static final int SCSI_CONFIG_ROW_SIZE = 256;
+ private static final int SCSI_CONFIG_ROW_ECC = 288;
+ private static final int SCSI_CONFIG_BOARD_ROW = 187;
+ private static final int SCSI_CONFIG_0_ROW = 188;
+ private static final int SCSI_CONFIG_1_ROW = 204;
+ private static final int SCSI_CONFIG_2_ROW = 220;
+ private static final int SCSI_CONFIG_3_ROW = 236;
+ private static final int SCSI_CONFIG_4_ROW = 124;
+ private static final int SCSI_CONFIG_5_ROW = 140;
+ private static final int SCSI_CONFIG_6_ROW = 156;
+
+ private HidDevice configHidDevice;
+ private HidDevice debugHidDevice;
+ private HidPacketProtocolDevice protocolDevice;
+
+ private int firmwareVersion;
+ private int sDCapacity;
+
+ private byte[] boardConfigSector;
+ private Map<Integer, byte[]> diskConfigSector = new HashMap<>();
+
+
+ public V3FirmwareUsbDevice(HidDevice configHidDevice, HidDevice debugHidDevice) {
+ this.configHidDevice = configHidDevice;
+ this.debugHidDevice = debugHidDevice;
+ this.protocolDevice = new HidPacketProtocolDevice(configHidDevice);
+
+ if (!configHidDevice.isOpen())
+ {
+ if (!configHidDevice.open()) {
+ LOGGER.error("Failed to open USB device {}\n{}", configHidDevice.getPath(), configHidDevice.getLastErrorMessage());
+ throw new RuntimeException("Failed to open USB device.");
+ }
+ }
+ if (!debugHidDevice.isOpen())
+ {
+ if (!debugHidDevice.open()) {
+ LOGGER.error("Failed to open USB device {}\n{}", debugHidDevice.getPath(), debugHidDevice.getLastErrorMessage());
+ throw new RuntimeException("Failed to open USB device.");
+ }
+ }
+ this.readDebugData();
+ }
+
+ @Override
+ public String getHardwareDescription() {
+ switch (this.configHidDevice.getReleaseNumber()) {
+ case 0x3001:
+ return "3.5\" SCSI2SD V3";
+ //info.version = "V3.0";
+ //info.firmwareName = "SCSI2SD-V3.cyacd";
+ case 0x3002:
+ return "3.5\" SCSI2SD V4.1/V4.2/V5.0 or 2.5\" SCSI2SD for Apple Powerbook";
+ //info.version = "V4.1/V4.2/V5.0";
+ //info.firmwareName = "SCSI2SD-V4.cyacd";
+ case 0x3003:
+ return "3.5\" SCSI2SD V5.1";
+ //info.version = "V5.1";
+ //info.firmwareName = "SCSI2SD-V51.cyacd";
+ case 0x0055:
+ return "External DB25 SCSI2SD";
+ //info.version = "V5.5";
+ //info.firmwareName = "SCSI2SD-V55.cyacd";
+
+ }
+ return "Unknown";
+ }
+
+ @Override
+ public int getFirmwareVersion() {
+ return this.firmwareVersion;
+ }
+
+ @Override
+ public String getFirmwareDescription() {
+ StringBuilder out = new StringBuilder();
+ out.append(this.firmwareVersion >> 8)
+ .append('.')
+ .append((this.firmwareVersion & 0xF0) >> 4);
+
+ int rev = this.firmwareVersion & 0xF;
+ if (rev != 0)
+ {
+ out.append(".").append(rev);
+ }
+ return out.toString();
+ }
+
+ @Override
+ public int getSdCapacity() {
+ return this.sDCapacity;
+ }
+
+ @Override
+ public boolean supportsTerminator() {
+ switch (this.configHidDevice.getReleaseNumber()) {
+ case 0x3001:
+ return false; //"3.5\" SCSI2SD V3";
+ case 0x3002:
+ return false; //"3.5\" SCSI2SD V4.1/V4.2/V5.0 or 2.5\" SCSI2SD for Apple Powerbook";
+ case 0x3003:
+ return true; //"3.5\" SCSI2SD V5.1";
+ case 0x0055:
+ return false; //"External DB25 SCSI2SD";
+ }
+ return false;
+ }
+
+ @Override
+ public boolean supportsSynchronous() {
+ return false;
+ }
+
+
+ private void readDebugData()
+ {
+ byte[] data = new byte[64];
+ data[0] = 0; // report ID
+ this.debugHidDevice.read(data, 5000);
+
+ this.firmwareVersion = (data[62] << 8) | data[63];
+ this.sDCapacity =
+ (HidPacketProtocol.uint8ToInt(data[58]) << 24) |
+ (HidPacketProtocol.uint8ToInt(data[59]) << 16) |
+ (HidPacketProtocol.uint8ToInt(data[60]) << 8) |
+ (HidPacketProtocol.uint8ToInt(data[61]));
+ }
+
+ @Override
+ public int getMaxDisks()
+ {
+ return MAX_SCSI_TARGETS;
+ }
+
+ @Override
+ public byte[] readBoardConfig()
+ {
+ if (boardConfigSector == null) {
+ boardConfigSector = readFlash(SCSI_CONFIG_ARRAY, SCSI_CONFIG_BOARD_ROW);
+ }
+
+ return Arrays.copyOfRange(boardConfigSector, 0, 128);
+ }
+
+ @Override
+ public void saveBoardConfig(byte[] data) {
+ if (boardConfigSector == null) {
+ boardConfigSector = readFlash(SCSI_CONFIG_ARRAY, SCSI_CONFIG_BOARD_ROW);
+ }
+
+ System.arraycopy(data, 0, boardConfigSector, 0, 128);
+
+ }
+
+ @Override
+ public byte[] readDiskConfig(int index)
+ {
+ int flashRow = this.getFlashRow(index);
+
+ var data = this.diskConfigSector.computeIfAbsent(flashRow, (k) -> this.readFlash(SCSI_CONFIG_ARRAY, flashRow));
+ return Arrays.copyOfRange(data, 0, 128);
+ }
+
+ @Override
+ public void saveDiskConfig(int index, byte[] data) {
+ int flashRow = this.getFlashRow(index);
+
+ var cachedData = this.diskConfigSector.computeIfAbsent(flashRow, (k) -> this.readFlash(SCSI_CONFIG_ARRAY, flashRow));
+ System.arraycopy(data, 0, cachedData, 0, 128);
+ }
+
+
+ @Override
+ public void saveCommit() {
+ if (boardConfigSector != null) {
+ writeFlash(SCSI_CONFIG_ARRAY, SCSI_CONFIG_BOARD_ROW, boardConfigSector);
+ }
+
+ for (int i = 0; i < MAX_SCSI_TARGETS; ++i) {
+ int flashRow = this.getFlashRow(i);
+ if (this.diskConfigSector.containsKey(flashRow)) {
+ var data = this.diskConfigSector.get(flashRow);
+ writeFlash(SCSI_CONFIG_ARRAY, flashRow, data);
+ }
+ }
+ }
+
+ private byte[] readFlash(int flashArray, int flashRow)
+ {
+ byte[] cmd = {
+ (byte)Commands.READFLASH.ordinal(),
+ HidPacketProtocol.intToUint8(flashArray),
+ HidPacketProtocol.intToUint8(flashRow)
+ };
+
+ return protocolDevice.sendHIDPacket(cmd, 256);
+ }
+
+
+ private byte[] writeFlash(int flashArray, int flashRow, byte[] data)
+ {
+ var cmd = new byte[256+3];
+ cmd[0] =(byte)Commands.WRITEFLASH.ordinal();
+ cmd[257] = HidPacketProtocol.intToUint8(flashArray);
+ cmd[258] = HidPacketProtocol.intToUint8(flashRow);
+
+ System.arraycopy(data, 0, cmd, 1, 256);
+
+ return protocolDevice.sendHIDPacket(cmd, 1);
+ }
+
+ private int getFlashRow(int index) {
+ int flashRow;
+ switch (index) {
+ case 0: flashRow = SCSI_CONFIG_0_ROW; break;
+ case 1: flashRow = SCSI_CONFIG_1_ROW; break;
+ case 2: flashRow = SCSI_CONFIG_2_ROW; break;
+ case 3: flashRow = SCSI_CONFIG_3_ROW; break;
+ default: throw new IndexOutOfBoundsException();
+ }
+ return flashRow;
+ }
+}
--- /dev/null
+// Copyright (C) 2019 Michael McMaster <michael@codesrc.com>
+//
+// This file is part of scsi2sd-util.
+//
+// scsi2sd-util is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// scsi2sd-util is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with scsi2sd-util. If not, see <https://www.gnu.org/licenses/>.
+
+package com.codesrc.scsi2sd.io;
+
+import org.hid4java.HidDevice;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class V6FirmwareUsbDevice implements UsbDevice {
+ private static org.slf4j.Logger LOGGER = LoggerFactory.getLogger(V6FirmwareUsbDevice.class.getPackageName());
+
+ public static final short VENDOR_ID = 0x16D0; // MCS
+ public static final short PRODUCT_ID = 0x0BD4; // SCSI2SD
+
+ private HidDevice hidDevice;
+ private HidPacketProtocolDevice protocolDevice;
+
+ private int firmwareVersion;
+ private int sDCapacity;
+
+ private byte[] configSector0;
+ private byte[] configSector1;
+
+ public V6FirmwareUsbDevice(HidDevice hidDevice) {
+ this.hidDevice = hidDevice;
+ this.protocolDevice = new HidPacketProtocolDevice(hidDevice);
+
+ if (!hidDevice.isOpen()) {
+ if (!hidDevice.open()) {
+ LOGGER.error("Failed to open USB device {}\n{}", hidDevice.getPath(), hidDevice.getLastErrorMessage());
+ throw new RuntimeException("Failed to open USB device.");
+ }
+ }
+ this.readDebugData();
+ }
+
+ @Override
+ public String getHardwareDescription() {
+ return "3.5\" SCSI2SD V6";
+ }
+
+ @Override
+ public int getFirmwareVersion() {
+ return this.firmwareVersion;
+ }
+
+ @Override
+ public String getFirmwareDescription() {
+ StringBuilder out = new StringBuilder();
+ out.append(this.firmwareVersion >> 8)
+ .append('.')
+ .append((this.firmwareVersion & 0xF0) >> 4);
+
+ int rev = this.firmwareVersion & 0xF;
+ if (rev != 0)
+ {
+ out.append(".").append(rev);
+ }
+ return out.toString();
+ }
+
+ @Override
+ public int getSdCapacity() {
+ return this.sDCapacity;
+ }
+
+ @Override
+ public boolean supportsTerminator() {
+ return true;
+ }
+
+ @Override
+ public boolean supportsSynchronous() {
+ return true;
+ }
+
+ private void readDebugData()
+ {
+ // Newer devices only have a single HID interface, and present
+ // a command to obtain the data
+ byte[] cmd = { (byte)Commands.DEVINFO.ordinal(), (byte)0xDE, (byte)0xAD, (byte)0xBE, (byte)0xEF };
+
+ byte[] data = protocolDevice.sendHIDPacket(cmd, 6);
+
+ this.firmwareVersion = (data[0] << 8) | data[1];
+ this.sDCapacity =
+ (HidPacketProtocol.uint8ToInt(data[2]) << 24) |
+ (HidPacketProtocol.uint8ToInt(data[3]) << 16) |
+ (HidPacketProtocol.uint8ToInt(data[4]) << 8) |
+ (HidPacketProtocol.uint8ToInt(data[5]));
+ }
+
+ @Override
+ public int getMaxDisks()
+ {
+ return 7;
+ }
+
+ @Override
+ public byte[] readBoardConfig()
+ {
+ if (configSector0 == null) {
+ configSector0 = readSector(this.sDCapacity - 2);
+ }
+
+ return Arrays.copyOfRange(configSector0, 0, 128);
+ }
+
+ @Override
+ public void saveBoardConfig(byte[] data)
+ {
+ if (configSector0 == null) {
+ configSector0 = readSector(this.sDCapacity - 2);
+ }
+
+ System.arraycopy(data, 0, configSector0, 0, 128);
+ }
+
+ @Override
+ public void saveDiskConfig(int index, byte[] data)
+ {
+ if (configSector0 == null) {
+ configSector0 = readSector(this.sDCapacity - 2);
+ }
+ if (configSector1 == null) {
+ configSector1 = readSector(this.sDCapacity - 1);
+ }
+
+ if (index <= 2) {
+ var from = 128 + (index * 128);
+
+ System.arraycopy(data, 0, configSector0, from, 128);
+ }
+ else {
+ var from = (index - 3) * 128;
+ System.arraycopy(data, 0, configSector1, from, 128);
+ }
+
+ }
+
+ @Override
+ public void saveCommit() {
+ if (configSector0 != null) {
+ writeSector(this.sDCapacity - 2, configSector0);
+ }
+ if (configSector1 != null) {
+ writeSector(this.sDCapacity - 1, configSector1);
+ }
+ }
+
+ @Override
+ public byte[] readDiskConfig(int index)
+ {
+ if (configSector0 == null) {
+ configSector0 = readSector(this.sDCapacity - 2);
+ }
+ if (configSector1 == null) {
+ configSector1 = readSector(this.sDCapacity - 1);
+ }
+
+ if (index < 0 || index > this.getMaxDisks()) {
+ throw new IllegalArgumentException("Request for invalid disk index");
+ }
+
+ if (index <= 2) {
+ var from = 128 + (index * 128);
+ return Arrays.copyOfRange(configSector0, from, from + 128);
+ }
+ else {
+ var from = (index - 3) * 128;
+ return Arrays.copyOfRange(configSector1, from, from + 128);
+ }
+ }
+
+ private byte[] readSector(int sector)
+ {
+ byte[] cmd = {
+ (byte)Commands.SD_READ.ordinal(),
+ HidPacketProtocol.intToUint8(sector >> 24),
+ HidPacketProtocol.intToUint8(sector >> 16),
+ HidPacketProtocol.intToUint8(sector >> 8),
+ HidPacketProtocol.intToUint8(sector),
+ };
+
+ return protocolDevice.sendHIDPacket(cmd, 512);
+ }
+
+
+ private byte[] writeSector(int sector, byte[] data)
+ {
+ var cmd = new byte[512+5];
+ cmd[0] =(byte)Commands.SD_WRITE.ordinal();
+ cmd[1] = HidPacketProtocol.intToUint8(sector >> 24);
+ cmd[2] = HidPacketProtocol.intToUint8(sector >> 16);
+ cmd[3] = HidPacketProtocol.intToUint8(sector >> 8);
+ cmd[4] = HidPacketProtocol.intToUint8(sector);
+
+ for (int i = 0; i < data.length; ++i)
+ {
+ cmd[5 + i] = data[i];
+ }
+
+ return protocolDevice.sendHIDPacket(cmd, 1);
+ }
+}
--- /dev/null
+// Copyright (C) 2019 Michael McMaster <michael@codesrc.com>
+//
+// This file is part of scsi2sd-util.
+//
+// scsi2sd-util is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// scsi2sd-util is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with scsi2sd-util. If not, see <https://www.gnu.org/licenses/>.
+
+module com.codesrc.scsi2sd.io {
+ requires hid4java;
+ requires org.slf4j;
+
+ exports com.codesrc.scsi2sd.io;
+}
--- /dev/null
+// Copyright (C) 2019 Michael McMaster <michael@codesrc.com>
+//
+// This file is part of scsi2sd-util.
+//
+// scsi2sd-util is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// scsi2sd-util is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with scsi2sd-util. If not, see <https://www.gnu.org/licenses/>.
+
+package com.codesrc.scsi2sd.io;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.Arrays;
+
+public class HidPacketProtocolTest {
+
+ private void test(HidPacketProtocol protocol, byte[] in)
+ {
+ System.out.println(String.format("Testing packet of size %d", in.length));
+ protocol.sendPacket(in);
+ byte[] toSend = protocol.getHIDBytes();
+ while (toSend != null)
+ {
+ System.out.println("Transferring packet");
+ protocol.receiveHIDData(toSend);
+ toSend = protocol.getHIDBytes();
+ }
+
+ byte[] receivedPacket = protocol.getPacket();
+ System.out.println(String.format("Received length = %d", receivedPacket.length));
+ Assert.assertTrue(receivedPacket != null);
+ Assert.assertTrue(receivedPacket.length == in.length);
+ Assert.assertTrue(Arrays.equals(in, receivedPacket));
+ }
+
+ @Test
+ public void testSmall() {
+ byte[] small = {1,2,3,4,5,6,7,8,9,0};
+ HidPacketProtocol protocol = new HidPacketProtocol();
+ this.test(protocol, small);
+ }
+
+ @Test
+ public void testMed() {
+ byte[] med = {
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+ 1, 2, 3, 4
+ };
+
+ HidPacketProtocol protocol = new HidPacketProtocol();
+ this.test(protocol, med);
+ }
+
+ @Test
+ public void testBig() {
+ byte[] big = {
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0
+ };
+ HidPacketProtocol protocol = new HidPacketProtocol();
+ this.test(protocol, big);
+ }
+
+ @Test
+ public void testHuge() {
+ byte[] huge = {
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+ 1, 2, 3, 4, 5, 6
+ };
+ HidPacketProtocol protocol = new HidPacketProtocol();
+ this.test(protocol, huge);
+ }
+}
--- /dev/null
+SCSI2SD Utility
+Copyright (C) 2019 Michael McMaster <michael@codesrc.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+////////////////////////////////////////////////////////////////////////////////////
+
+The additional license terms apply for software distributed with this program:
+
+////////////////////////////////////////////////////////////////////////////////////
+http://fxexperience.com/controlsfx/
+
+/**
+ * Copyright (c) 2013, 2014, ControlsFX
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of ControlsFX, any associated website, nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+////////////////////////////////////////////////////////////////////////////////////
+https://github.com/gary-rowe/hid4java/blob/develop/LICENSE
+
+The MIT License (MIT)
+
+Copyright (c) 2014 Gary Rowe
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+////////////////////////////////////////////////////////////////////////////////////
+https://github.com/frexy/glyph-iconset
+Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)
+http://creativecommons.org/licenses/by-sa/4.0/
+////////////////////////////////////////////////////////////////////////////////////
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <artifactId>scsi2sd-util</artifactId>
+ <groupId>com.codesrc</groupId>
+ <version>1.0-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>scsi2sd.ui</artifactId>
+ <packaging>jar</packaging>
+
+ <name>scsi2sd.ui</name>
+ <url>http://www.codesrc.com</url>
+ <developers>
+ <developer>
+ <name>Michael McMaster</name>
+ <email>michael@codesrc.com</email>
+ </developer>
+ </developers>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+
+ <profiles>
+ <profile>
+ <id>linux</id>
+ <activation>
+ <os>
+ <family>unix</family>
+ <name>Linux</name>
+ </os>
+ </activation>
+ <properties>
+ <jmodPath>${project.build.directory}/../../build/linux/javafx-jmods-11.0.2</jmodPath>
+ </properties>
+ </profile>
+ <profile>
+ <id>mac</id>
+ <activation>
+ <os>
+ <family>mac</family>
+ </os>
+ </activation>
+ <properties>
+ <jmodPath>${project.build.directory}/../../build/mac/javafx-jmods-11.0.2</jmodPath>
+ </properties>
+ </profile>
+ <profile>
+ <id>windows</id>
+ <activation>
+ <os>
+ <family>windows</family>
+ </os>
+ </activation>
+ <properties>
+ <jmodPath>${project.build.directory}/../../build/windows/javafx-jmods-11.0.2</jmodPath>
+ </properties>
+ </profile>
+ </profiles>
+
+ <build>
+ <directory>target</directory>
+ <outputDirectory>target/classes</outputDirectory>
+ <finalName>${project.artifactId}-${project.version}</finalName>
+
+ <resources>
+ <resource>
+ <directory>doc</directory>
+ </resource>
+ <resource>
+ <directory>src/main/resources</directory>
+ </resource>
+
+ </resources>
+
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.8.0</version>
+ <configuration>
+ <source>10</source>
+ <target>10</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <!-- Build an executable JAR -->
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <version>3.1.1</version>
+ <configuration>
+ <archive>
+ <manifest>
+ <!-- <addClasspath>true</addClasspath> -->
+ <mainClass>com.codesrc.scsi2sd.App</mainClass>
+ </manifest>
+ </archive>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <version>3.1.1</version>
+ <executions>
+ <execution>
+ <id>copy-dependencies</id>
+ <phase>package</phase>
+ <goals>
+ <goal>copy-dependencies</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>${project.build.directory}/install</outputDirectory>
+ <overWriteReleases>false</overWriteReleases>
+ <overWriteSnapshots>true</overWriteSnapshots>
+ <overWriteIfNewer>true</overWriteIfNewer>
+ <excludeGroupIds>org.openjfx,org.hid4java,net.java.dev.jna</excludeGroupIds>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+
+
+ <plugin>
+ <groupId>org.moditect</groupId>
+ <artifactId>moditect-maven-plugin</artifactId>
+ <version>1.0.0.Beta2</version>
+ <executions>
+ <execution>
+ <id>add-module-infos</id>
+ <phase>generate-resources</phase>
+ <goals>
+ <goal>add-module-info</goal>
+ </goals>
+
+ <configuration>
+ <outputDirectory>${project.build.directory}/install</outputDirectory>
+ <modules>
+ <module>
+ <artifact>
+ <groupId>net.sf.jopt-simple</groupId>
+ <artifactId>jopt-simple</artifactId>
+ <version>6.0-alpha-3</version>
+ </artifact>
+ <moduleInfoSource>
+ module joptsimple {
+ exports joptsimple;
+ }
+ </moduleInfoSource>
+ </module>
+ </modules>
+ </configuration>
+ </execution>
+
+
+ <execution>
+ <id>create-runtime-image</id>
+ <phase>package</phase>
+ <goals>
+ <goal>create-runtime-image</goal>
+ </goals>
+ <configuration>
+ <modulePath>
+ <path>${project.build.directory}/scsi2sd.ui-1.0-SNAPSHOT.jar</path>
+ <path>${jmodPath}</path>
+ <path>${project.build.directory}/../../scsi2sd.io/target/install</path>
+ <path>${project.build.directory}/install</path>
+ </modulePath>
+ <modules>
+ <module>com.codesrc.scsi2sd.ui</module>
+ </modules>
+ <excludedResources>
+ </excludedResources>
+ <!--<baseJdk>version=11,vendor=openjdk,platform=linux-x64</baseJdk>-->
+ <launcher>
+ <name>scsi2sd-util</name>
+ <module>com.codesrc.scsi2sd.ui/com.codesrc.scsi2sd.App</module>
+ </launcher>
+ <outputDirectory>
+ ${project.build.directory}/jlink-image
+ </outputDirectory>
+ <stripDebug>true</stripDebug>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ </plugins>
+ </build>
+
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>scsi2sd.io</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <!-- https://mvnrepository.com/artifact/org.openjfx/javafx-base -->
+ <dependency>
+ <groupId>org.openjfx</groupId>
+ <artifactId>javafx-base</artifactId>
+ <version>11.0.2</version>
+ </dependency>
+
+ <!-- https://mvnrepository.com/artifact/org.openjfx/javafx-controls -->
+ <dependency>
+ <groupId>org.openjfx</groupId>
+ <artifactId>javafx-controls</artifactId>
+ <version>11.0.2</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.openjfx</groupId>
+ <artifactId>javafx-media</artifactId>
+ <version>11.0.2</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.openjfx</groupId>
+ <artifactId>javafx-web</artifactId>
+ <version>11.0.2</version>
+ </dependency>
+
+ <!-- https://mvnrepository.com/artifact/org.openjfx/javafx-fxml -->
+ <dependency>
+ <groupId>org.openjfx</groupId>
+ <artifactId>javafx-fxml</artifactId>
+ <version>11.0.2</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.controlsfx</groupId>
+ <artifactId>controlsfx</artifactId>
+ <version>11.0.0</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-jdk14</artifactId>
+ <version>1.8.0-beta2</version>
+ </dependency>
+
+ <dependency>
+ <groupId>net.sf.jopt-simple</groupId>
+ <artifactId>jopt-simple</artifactId>
+ <version>6.0-alpha-3</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.hid4java</groupId>
+ <artifactId>hid4java</artifactId>
+ <version>0.5.0</version>
+ </dependency>
+ </dependencies>
+</project>
--- /dev/null
+// Copyright (C) 2019 Michael McMaster <michael@codesrc.com>
+//
+// This file is part of scsi2sd-util.
+//
+// scsi2sd-util is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// scsi2sd-util is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with scsi2sd-util. If not, see <https://www.gnu.org/licenses/>.
+
+package com.codesrc.scsi2sd;
+
+import com.codesrc.scsi2sd.io.UsbDeviceManager;
+import com.codesrc.scsi2sd.presentation.FXWindow;
+import javafx.application.Application;
+import javafx.concurrent.Task;
+import javafx.concurrent.Worker;
+import javafx.scene.Scene;
+import javafx.scene.control.ProgressBar;
+import javafx.scene.effect.DropShadow;
+import javafx.scene.image.Image;
+import javafx.scene.image.ImageView;
+import javafx.scene.layout.Pane;
+import javafx.stage.Stage;
+import javafx.stage.StageStyle;
+import joptsimple.OptionParser;
+import joptsimple.OptionSet;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Properties;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class App extends Application {
+ private static AppOptions appOptions;
+
+ // Need to keep a reference or else weak-reference is garbage-collected and our debug
+ // log setting gets lost.
+ private static Logger usbLogger;
+
+ @Override
+ public void start(Stage stage) throws Exception {
+ final Stage splashStage = appOptions.isShowSplashScreen() ? showSplash(stage) : null;
+
+ Task<ScreensConfiguration> initTask = new Task<ScreensConfiguration>() {
+ @Override
+ protected ScreensConfiguration call() throws Exception {
+ // Spring framework startup
+ long startMs = System.currentTimeMillis();
+
+ AppContext appContext = new AppContext(appOptions);
+ ScreensConfiguration screens = new ScreensConfiguration(appContext);
+ screens.setPrimaryStage(stage);
+ long endMs = System.currentTimeMillis();
+ long sleepMs = 1200 - (endMs - startMs);
+
+ if (appOptions.isShowSplashScreen() && sleepMs > 0) {
+ Thread.sleep(sleepMs);
+ }
+ return screens;
+ }
+ };
+
+ new Thread(initTask).start();
+ initTask.stateProperty().addListener((observableValue, oldState, newState) -> {
+ if (newState == Worker.State.SUCCEEDED) {
+ FXWindow main = initTask.getValue().mainWindow();
+ main.show();
+ if (splashStage != null) {
+ splashStage.hide();
+ }
+ }
+ });
+ }
+
+ private Stage showSplash(Stage primaryStage) {
+ ImageView logo = new ImageView();
+ logo.setX(1);
+ logo.setY(1);
+ logo.setImage(new Image(App.class.getResourceAsStream("/img/splash.png")));
+
+ Pane splashRoot = new Pane();
+ splashRoot.setPrefWidth(logo.getImage().getWidth() + 2);
+ splashRoot.setPrefHeight(logo.getImage().getHeight() + 2);
+ splashRoot.getChildren().add(logo);
+
+ ProgressBar pb = new ProgressBar();
+ pb.setLayoutX(logo.getImage().getWidth() * 0.33);
+ pb.setLayoutY(logo.getImage().getHeight() * 0.90);
+ pb.setPrefWidth(logo.getImage().getWidth() * 0.33);
+ splashRoot.getChildren().add(pb);
+
+ splashRoot.setEffect(new DropShadow());
+
+ Scene splash = new Scene(splashRoot);
+ splash.getStylesheets().add(App.class.getResource("/css/splash.css").toString());
+ Stage splashStage = new Stage();
+ splashStage.initOwner(primaryStage);
+ splashStage.setScene(splash);
+ splashStage.initStyle(StageStyle.UNDECORATED);
+ splashStage.setTitle("codesrc SCSI2SD");
+
+ splashStage.show();
+ return splashStage;
+ }
+
+ private static void parseCommandLineOptions(String[] args) {
+ OptionParser parser = new OptionParser();
+ parser.acceptsAll(Arrays.asList("n", "nosplash"), "No splash screen delay");
+ parser.acceptsAll(Arrays.asList("h", "?", "help"), "Show help").forHelp();
+ parser.acceptsAll(Arrays.asList("d", "debug"), "Debug logging");
+
+
+ OptionSet options = parser.parse(args);
+ if (options.has("help")) {
+ try {
+ parser.printHelpOn(System.out);
+ System.exit(0);
+ } catch (IOException e) {
+ System.exit(1);
+ }
+ }
+
+ appOptions = new AppOptions();
+ appOptions.setShowSplashScreen(!options.has("n"));
+ appOptions.setDebugLogging(options.has("d"));
+
+ }
+
+ public static void main(String[] args) {
+
+ Properties appProperties = new Properties();
+ try (InputStream is = App.class.getResourceAsStream("/app.properties")) {
+ appProperties.load(is);
+ } catch (IOException e)
+ {
+ System.err.println("Could not load resources");
+ System.exit(1);
+ }
+
+ System.out.println(
+ "SCSI2SD Utility v" + appProperties.getProperty("com.codesrc.scsi2sd.app.version") + "\n" +
+ "Copyright (C) 2019 Michael McMaster <michael@codesrc.com>\n" +
+ "\n" +
+ "This program is free software: you can redistribute it and/or modify\n" +
+ "it under the terms of the GNU General Public License as published by\n" +
+ "the Free Software Foundation, either version 3 of the License, or\n" +
+ "(at your option) any later version.\n\n" +
+ "This program is distributed in the hope that it will be useful,\n" +
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" +
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" +
+ "GNU General Public License for more details.\n\n" +
+ "You should have received a copy of the GNU General Public License\n" +
+ "along with this program. If not, see <https://www.gnu.org/licenses/>.\n");
+
+ parseCommandLineOptions(args);
+
+ if (appOptions.isDebugLogging())
+ {
+ setDebugLevel();
+ }
+
+ launch(args);
+ }
+
+ public static void setDebugLevel() {
+ Level targetLevel = Level.ALL;
+ usbLogger = Logger.getLogger(UsbDeviceManager.class.getPackageName());
+ usbLogger.setLevel(targetLevel);
+ for (Handler handler : usbLogger.getHandlers()) {
+ handler.setLevel(targetLevel);
+ }
+ }
+}
--- /dev/null
+// Copyright (C) 2019 Michael McMaster <michael@codesrc.com>
+//
+// This file is part of scsi2sd-util.
+//
+// scsi2sd-util is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// scsi2sd-util is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with scsi2sd-util. If not, see <https://www.gnu.org/licenses/>.
+
+package com.codesrc.scsi2sd;
+
+import com.codesrc.scsi2sd.document.ActiveDocument;
+import com.codesrc.scsi2sd.io.UsbDeviceManager;
+import com.codesrc.scsi2sd.presentation.Desktop;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+public class AppContext {
+ private static String appPropertyResource = "app.properties";
+ private AppOptions appOptions;
+
+ private Properties appProperties;
+ private UsbDeviceManager usbDeviceManager;
+ private Desktop desktop;
+ private ActiveDocument activeDocument;
+
+ public AppContext(AppOptions appOptions) {
+ this.appOptions = appOptions;
+ }
+
+ public synchronized Properties getAppProperties() {
+ if (this.appProperties == null) {
+ this.appProperties = new Properties();
+
+ try (InputStream inputStream = getClass().getResourceAsStream("/app.properties")) {
+
+ if (inputStream == null)
+ System.err.println("null stream");
+ this.appProperties.load(inputStream);
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ }
+ }
+ return this.appProperties;
+ }
+
+ public synchronized Desktop getDesktop() {
+ if (this.desktop == null) {
+ this.desktop = new Desktop();
+ }
+ return this.desktop;
+ }
+
+ public synchronized UsbDeviceManager getUsbDeviceManager() {
+ if (this.usbDeviceManager == null) {
+ this.usbDeviceManager = UsbDeviceManager.getInstance();
+ }
+ return this.usbDeviceManager;
+ }
+
+ public synchronized ActiveDocument getActiveDocument() {
+ if (this.activeDocument == null) {
+ this.activeDocument = new ActiveDocument();
+ }
+ return this.activeDocument;
+ }
+}
--- /dev/null
+// Copyright (C) 2019 Michael McMaster <michael@codesrc.com>
+//
+// This file is part of scsi2sd-util.
+//
+// scsi2sd-util is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// scsi2sd-util is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with scsi2sd-util. If not, see <https://www.gnu.org/licenses/>.
+
+package com.codesrc.scsi2sd;
+
+/**
+ * Created by michael on 4/06/17.
+ */
+public class AppOptions {
+
+ private boolean showSplashScreen = true;
+ private boolean debugLogging = false;
+
+ public AppOptions() {
+
+ }
+
+ public boolean isShowSplashScreen() {
+ return showSplashScreen;
+ }
+
+ public void setShowSplashScreen(boolean showSplashScreen) {
+ this.showSplashScreen = showSplashScreen;
+ }
+
+ public boolean isDebugLogging() { return this.debugLogging; }
+
+ public void setDebugLogging(boolean debugLogging) {
+ this.debugLogging = debugLogging;
+ }
+}
--- /dev/null
+// Copyright (C) 2019 Michael McMaster <michael@codesrc.com>
+//
+// This file is part of scsi2sd-util.
+//
+// scsi2sd-util is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// scsi2sd-util is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with scsi2sd-util. If not, see <https://www.gnu.org/licenses/>.
+
+package com.codesrc.scsi2sd;
+
+import com.codesrc.scsi2sd.presentation.*;
+import javafx.stage.Stage;
+import javafx.stage.StageStyle;
+import javafx.util.Callback;
+
+import java.lang.reflect.InvocationTargetException;
+
+/**
+ * Suitable for use as a FXMLLoader ControllerFactory
+ */
+public class ScreensConfiguration implements Callback<Class<?>,Object> {
+
+ private AppContext appContext;
+ private Stage primaryStage;
+
+ public ScreensConfiguration(AppContext appContext) {
+ this.appContext = appContext;
+ }
+
+ public void setPrimaryStage(Stage primaryStage) {
+ this.primaryStage = primaryStage;
+ }
+
+ @Override
+ public Object call(Class<?> aClass) {
+ String methodName = "provide" + aClass.getSimpleName();
+ try {
+ return getClass().getMethod(methodName).invoke(this);
+ } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ public FXWindow mainWindow() {
+ return new FXWindow(this, getClass().getResource("/fx/main.fxml"), MainController.Title, primaryStage, StageStyle.DECORATED);
+ }
+
+ public FXWindow aboutWindow(FXWindow parentWindow) {
+ return new FXWindow(this, getClass().getResource("/fx/about.fxml"), "About SCSI2SD", parentWindow, StageStyle.DECORATED);
+ }
+
+ public MainController provideMainController() {
+ return new MainController(
+ this,
+ this.appContext.getUsbDeviceManager(),
+ this.appContext.getActiveDocument());
+ }
+
+ public AboutController provideAboutController() {
+ return new AboutController(
+ this,
+ this.appContext.getDesktop(),
+ this.appContext.getAppProperties());
+ }
+
+ public ConfigController provideConfigController() {
+ return new ConfigController(this, this.appContext.getActiveDocument());
+ }
+
+ public StatusTabController provideStatusTabController() {
+ return new StatusTabController(this, this.appContext.getUsbDeviceManager());
+ }
+
+ public DebugLogController provideDebugLogController() {
+ return new DebugLogController(this, this.appContext.getUsbDeviceManager());
+ }
+
+ public DiskConfigController provideDiskConfigController() {
+ return new DiskConfigController(this, this.appContext.getActiveDocument(), this.appContext.getUsbDeviceManager());
+ }
+
+}
--- /dev/null
+// Copyright (C) 2019 Michael McMaster <michael@codesrc.com>
+//
+// This file is part of scsi2sd-util.
+//
+// scsi2sd-util is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// scsi2sd-util is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with scsi2sd-util. If not, see <https://www.gnu.org/licenses/>.
+
+package com.codesrc.scsi2sd.document;
+
+import com.codesrc.scsi2sd.model.ConfigRoot;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+/**
+ * Created by michael on 28/05/17.
+ */
+public class ActiveDocument {
+
+ private ConcurrentLinkedQueue<DocumentObserver> observers = new ConcurrentLinkedQueue<DocumentObserver>();
+
+ private Map<String, Boolean> isModified = new ConcurrentHashMap<String, Boolean>();
+ private Map<String, Boolean> isValid = new ConcurrentHashMap<String, Boolean>();
+
+ private ConfigRoot originalDocument;
+ private ConfigRoot activeDocument;
+
+ private String originalDocumentName;
+ private boolean inLoad = false;
+
+ public void addObserver(DocumentObserver observer) {
+ observers.add(observer);
+ }
+
+ public void removeObserver(DocumentObserver observer) {
+ observers.remove(observer);
+ }
+
+ public synchronized boolean isModified() {
+ for (Boolean value : isModified.values())
+ {
+ if (value) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public void setModified(String source, boolean modified)
+ {
+ boolean wasModified;
+ boolean isNowModified;
+
+ synchronized(this) {
+ if (inLoad) {
+ return;
+ }
+
+ wasModified = this.isModified();
+
+ isModified.put(source, modified);
+
+ isNowModified = this.isModified();
+ }
+
+ if (wasModified != isNowModified) {
+ for (DocumentObserver observer : this.observers) {
+ observer.documentModified(this, isNowModified);
+ }
+ }
+ }
+
+ public synchronized boolean isValid() {
+ for (Boolean value : isValid.values())
+ {
+ if (!value) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public void setValid(String source, boolean valid)
+ {
+ boolean wasValid;
+ boolean isNowValid;
+
+ synchronized(this) {
+ wasValid = this.isValid();
+
+ isValid.put(source, valid);
+
+ isNowValid = this.isValid();
+ }
+
+ if (wasValid != isNowValid) {
+ for (DocumentObserver observer : this.observers) {
+ observer.documentValid(this, isNowValid);
+ }
+ }
+ }
+
+ public ConfigRoot getOriginalDocument() {
+ return this.originalDocument;
+ }
+
+ public String getOriginalDocumentName() {
+ return this.originalDocumentName;
+ }
+
+ public ConfigRoot getActiveDocument() {
+ return this.activeDocument;
+ }
+
+ public void loadDocument(ConfigRoot document, String originalDocumentName) {
+ synchronized (this) {
+ this.originalDocument = new ConfigRoot(document);
+ this.originalDocumentName = originalDocumentName;
+ this.activeDocument = document;
+ this.isModified.clear();
+ this.isValid.clear();
+ this.inLoad = true;
+ }
+
+ for (DocumentObserver observer : this.observers) {
+ observer.documentLoaded(this);
+ }
+
+ synchronized (this) {
+ this.inLoad = false;
+ }
+ }
+}
+
--- /dev/null
+// Copyright (C) 2019 Michael McMaster <michael@codesrc.com>
+//
+// This file is part of scsi2sd-util.
+//
+// scsi2sd-util is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// scsi2sd-util is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with scsi2sd-util. If not, see <https://www.gnu.org/licenses/>.
+
+package com.codesrc.scsi2sd.document;
+
+/**
+ * Created by michael on 28/05/17.
+ */
+public interface DocumentObserver {
+ void documentLoaded(ActiveDocument document);
+ void documentModified(ActiveDocument document, boolean isModified);
+ void documentValid(ActiveDocument document, boolean isValid);
+}
--- /dev/null
+// Copyright (C) 2019 Michael McMaster <michael@codesrc.com>
+//
+// This file is part of scsi2sd-util.
+//
+// scsi2sd-util is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// scsi2sd-util is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with scsi2sd-util. If not, see <https://www.gnu.org/licenses/>.
+
+package com.codesrc.scsi2sd.model;
+
+public interface BitEnum {
+ int getBit();
+}
--- /dev/null
+// Copyright (C) 2019 Michael McMaster <michael@codesrc.com>
+//
+// This file is part of scsi2sd-util.
+//
+// scsi2sd-util is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// scsi2sd-util is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with scsi2sd-util. If not, see <https://www.gnu.org/licenses/>.
+
+package com.codesrc.scsi2sd.model;
+
+import java.util.Set;
+
+public class BitUtil
+{
+
+ public static <T extends BitEnum> long getMask(Set<T> flags)
+ {
+ long result = 0;
+ for (T item : flags) {
+ result |= item.getBit();
+ }
+ return result;
+ }
+
+ public static long letohl(byte[] in, int offset)
+ {
+ return (((int) in[offset + 3] & 0xFF) << 24) |
+ (((int) in[offset + 2] & 0xFF) << 16) |
+ (((int) in[offset + 1] & 0xFF) << 8) |
+ ((int) in[offset] & 0xFF);
+ }
+
+ public static int letohs(byte[] in, int offset) {
+ return (((int) in[offset + 1] & 0xFF) << 8) |
+ ((int) in[offset] & 0xFF);
+ }
+
+
+ public static int uint8ToInt(byte data) {
+ return (int) data & 0xFF;
+ }
+
+ public static byte intToUint8(int data)
+ {
+ return (byte) (data & 0xFF);
+ }
+
+ public static byte longToUint8(long data)
+ {
+ return (byte) (data & 0xFF);
+ }
+}
--- /dev/null
+// Copyright (C) 2019 Michael McMaster <michael@codesrc.com>
+//
+// This file is part of scsi2sd-util.
+//
+// scsi2sd-util is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// scsi2sd-util is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with scsi2sd-util. If not, see <https://www.gnu.org/licenses/>.
+
+package com.codesrc.scsi2sd.model;
+
+import org.w3c.dom.Node;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+public class BoardConfig {
+ public static final int LENGTH = 128;
+
+ private Set<Flag> flags;
+
+ private int startupDelay; // Seconds
+
+ private int selectionDelay; // milliseconds
+
+ private Set<Flag6> flags6;
+
+ private Speed scsiSpeed;
+
+ public BoardConfig(BoardConfig other)
+ {
+ this.flags = new HashSet<>(other.flags);
+ this.startupDelay = other.startupDelay;
+ this.selectionDelay = other.selectionDelay;
+ this.flags6 = new HashSet<>(other.flags6);
+ this.scsiSpeed = other.scsiSpeed;
+ }
+
+ public BoardConfig() {
+ this.flags = new HashSet<>();
+ this.flags6 = new HashSet<>();
+ this.flags6.add(Flag6.S2S_CFG_ENABLE_TERMINATOR);
+
+ this.startupDelay = 0;
+ this.selectionDelay = 255; // "Auto".
+ this.scsiSpeed = Speed.S2S_CFG_SPEED_NoLimit;
+ }
+
+
+ public BoardConfig(byte[] in) {
+ if (in.length != LENGTH) {
+ throw new IllegalArgumentException("BoardConfig size incorrect");
+ }
+
+ flags = Flag.fromBitmask(in[4]);
+ startupDelay = (int)in[5] & 0xFF;
+ selectionDelay = (int)in[6] & 0xFF;
+ flags6 = Flag6.fromBitmask(in[7]);
+ scsiSpeed = Speed.fromBits(in[8]);
+ }
+
+ public byte[] asBytes() {
+ byte[] out = new byte[LENGTH];
+
+ out[0] = 'B'; out[1] = 'C'; out[2] = 'F'; out[3] = 'G';
+
+ out[4] = BitUtil.longToUint8(BitUtil.getMask(flags));
+ out[5] = BitUtil.intToUint8(startupDelay);
+ out[6] = BitUtil.intToUint8(selectionDelay);
+ out[7] = BitUtil.longToUint8(BitUtil.getMask(flags6));
+ out[8] = BitUtil.intToUint8(scsiSpeed.getValue());
+ return out;
+ }
+
+ public Set<Flag> getFlags() {
+ return flags;
+ }
+
+ public void setFlags(Set<Flag> flags) {
+ this.flags = flags;
+ }
+
+ public void setFlag(Flag flag, boolean value)
+ {
+ if (value)
+ {
+ this.flags.add(flag);
+ }
+ else
+ {
+ this.flags.remove(flag);
+ }
+ }
+
+ public void setFlag6(Flag6 flag, boolean value)
+ {
+ if (value)
+ {
+ this.flags6.add(flag);
+ }
+ else
+ {
+ this.flags6.remove(flag);
+ }
+ }
+
+ public int getStartupDelay() {
+ return startupDelay;
+ }
+
+ public void setStartupDelay(int startupDelay) {
+ this.startupDelay = startupDelay;
+ }
+
+ public int getSelectionDelay() {
+ return selectionDelay;
+ }
+
+ public void setSelectionDelay(int selectionDelay) {
+ this.selectionDelay = selectionDelay;
+ }
+
+ public Set<Flag6> getFlags6() {
+ return flags6;
+ }
+
+ public void setFlag6(Set<Flag6> flags6) {
+ this.flags6 = flags6;
+ }
+
+ public Speed getScsiSpeed() {
+ return scsiSpeed;
+ }
+
+ public void setScsiSpeed(Speed scsiSpeed) {
+ this.scsiSpeed = scsiSpeed;
+ }
+
+ public boolean isEnableTerminator() {
+ return flags6.contains(Flag6.S2S_CFG_ENABLE_TERMINATOR);
+ }
+
+ public void setEnableTerminator(boolean enableTerminator) {
+ this.flags6.add(Flag6.S2S_CFG_ENABLE_TERMINATOR);
+ }
+
+ public BoardConfig(Node node) {
+ var childNodes = node.getChildNodes();
+ var children = IntStream.range(0, childNodes.getLength())
+ .mapToObj(childNodes::item)
+ .filter(n -> n.getNodeType() == Node.ELEMENT_NODE)
+ .filter(n -> n.hasChildNodes() &&
+ n.getFirstChild().getNodeType() == Node.TEXT_NODE)
+ .collect(Collectors.toMap(n -> n.getNodeName(), n -> n.getFirstChild().getNodeValue().trim()));
+
+ this.flags = new HashSet<>();
+
+ if (children.getOrDefault("unitAttention", "false").equalsIgnoreCase("true")) {
+ flags.add(Flag.S2S_CFG_ENABLE_UNIT_ATTENTION);
+ }
+
+ if (children.getOrDefault("parity", "false").equalsIgnoreCase("true")) {
+
+ flags.add(Flag.S2S_CFG_ENABLE_PARITY);
+ }
+
+ if (children.getOrDefault("enableScsi2", "false").equalsIgnoreCase("true")) {
+ flags.add(Flag.S2S_CFG_ENABLE_SCSI2);
+ }
+
+ if (children.getOrDefault("selLatch", "false").equalsIgnoreCase("true")) {
+ flags.add(Flag.S2S_CFG_ENABLE_SEL_LATCH);
+ }
+
+ if (children.getOrDefault("mapLunsToIds", "false").equalsIgnoreCase("true")) {
+ flags.add(Flag.S2S_CFG_MAP_LUNS_TO_IDS);
+ }
+
+ this.flags6 = new HashSet<>();
+ if (children.getOrDefault("enableTerminator", "false").equalsIgnoreCase("true")) {
+ this.flags6.add(Flag6.S2S_CFG_ENABLE_TERMINATOR);
+ }
+
+ this.selectionDelay = 255;
+ var selDelayText = children.getOrDefault("selectionDelay", "255");
+ try {
+ var intValue = Integer.valueOf(selDelayText);
+ if (intValue >= 0 && intValue <= 255) {
+ this.selectionDelay = intValue;
+ }
+ } catch (NumberFormatException e) {
+ // Ignore rubbish data.
+ }
+
+ this.startupDelay = 0;
+ var startDelayText = children.getOrDefault("startupDelay", "0");
+ try {
+ var intValue = Integer.valueOf(startDelayText);
+ if (intValue >= 0 && intValue <= 255) {
+ this.startupDelay = intValue;
+ }
+ } catch (NumberFormatException e) {
+ // Ignore rubbish data.
+ }
+
+ this.scsiSpeed = Speed.S2S_CFG_SPEED_NoLimit;
+ var speedNodeText = children.getOrDefault("scsiSpeed", "0");
+ try {
+ var intValue = Integer.valueOf(speedNodeText);
+ switch (intValue) {
+ case 0: this.scsiSpeed = Speed.S2S_CFG_SPEED_NoLimit; break;
+ case 1: this.scsiSpeed = Speed.S2S_CFG_SPEED_ASYNC_15; break;
+ case 2: this.scsiSpeed = Speed.S2S_CFG_SPEED_ASYNC_33; break;
+ case 3: this.scsiSpeed = Speed.S2S_CFG_SPEED_ASYNC_50; break;
+ case 4: this.scsiSpeed = Speed.S2S_CFG_SPEED_SYNC_5; break;
+ case 5: this.scsiSpeed = Speed.S2S_CFG_SPEED_SYNC_10; break;
+ case 6: this.scsiSpeed = Speed.S2S_CFG_SPEED_TURBO; break;
+ default: this.scsiSpeed = Speed.S2S_CFG_SPEED_NoLimit; break;
+ }
+ } catch (NumberFormatException e) {
+ // Ignore rubbish data.
+ }
+ }
+
+ public String toXML()
+ {
+ var out = new StringBuilder();
+
+ out.append("<S2S_BoardCfg>\n")
+ .append(" <!-- ********************************************************\n")
+ .append(" Enable the onboard active terminator.\n")
+ .append(" Both ends of the SCSI chain should be terminated. Disable\n")
+ .append(" only if the SCSI2SD is in the middle of a chain with other\n")
+ .append(" devices.\n")
+ .append(" ********************************************************* -->\n")
+ .append( " <enableTerminator>")
+ .append(this.flags6.contains(Flag6.S2S_CFG_ENABLE_TERMINATOR) ? "true" : "false")
+ .append( "</enableTerminator>\n")
+
+ .append(" <unitAttention>")
+ .append(this.flags.contains(Flag.S2S_CFG_ENABLE_UNIT_ATTENTION) ? "true" : "false")
+ .append("</unitAttention>\n")
+
+ .append(" <parity>")
+ .append(this.flags.contains(Flag.S2S_CFG_ENABLE_PARITY) ? "true" : "false")
+ .append("</parity>\n")
+
+ .append(" <!-- ********************************************************\n")
+ .append(" Only set to true when using with a fast SCSI2 host\n ")
+ .append(" controller. This can cause problems with older/slower\n")
+ .append(" hardware.\n")
+ .append(" ********************************************************* -->\n")
+ .append(" <enableScsi2>")
+ .append(this.flags.contains(Flag.S2S_CFG_ENABLE_SCSI2) ? "true" : "false")
+ .append("</enableScsi2>\n")
+
+ .append(" <!-- ********************************************************\n")
+ .append(" Respond to very short duration selection attempts. This supports\n")
+ .append(" non-standard hardware, but is generally safe to enable.\n")
+ .append(" Required for Philips P2000C.\n")
+ .append(" ********************************************************* -->\n")
+ .append(" <selLatch>")
+ .append(this.flags.contains(Flag.S2S_CFG_ENABLE_SEL_LATCH) ? "true" : "false")
+ .append("</selLatch>\n")
+
+
+ .append(" <!-- ********************************************************\n")
+ .append(" Convert luns to IDs. The unit must already be configured to respond\n")
+ .append(" on the ID. Allows dual drives to be accessed from a \n")
+ .append(" XEBEC S1410 SASI bridge.\n")
+ .append(" eg. Configured for dual drives as IDs 0 and 1, but the XEBEC will\n")
+ .append(" access the second disk as ID0, lun 1.\n")
+ .append(" See ttp://bitsavers.trailing-edge.com/pdf/xebec/104524C_S1410Man_Aug83.pdf\n")
+ .append(" ********************************************************* -->\n")
+ .append(" <mapLunsToIds>")
+ .append(this.flags.contains(Flag.S2S_CFG_MAP_LUNS_TO_IDS) ? "true" : "false")
+ .append("</mapLunsToIds>\n")
+
+
+ .append(" <!-- ********************************************************\n")
+ .append(" Delay (in milliseconds) before responding to a SCSI selection.\n")
+ .append(" 255 (auto) sets it to 0 for SCSI2 hosts and 1ms otherwise.\n")
+ .append(" Some samplers need this set to 1 manually.\n")
+ .append(" ********************************************************* -->\n")
+ .append(" <selectionDelay>").append(this.selectionDelay).append("</selectionDelay>\n")
+
+ .append(" <!-- ********************************************************\n")
+ .append(" Startup delay (in seconds) before responding to the SCSI bus \n")
+ .append(" after power on. Default = 0.\n")
+ .append(" ********************************************************* -->\n")
+ .append(" <startupDelay>").append(this.startupDelay).append("</startupDelay>\n")
+
+ .append(" <!-- ********************************************************\n")
+ .append(" Speed limit the SCSI interface. This is the -max- speed the \n")
+ .append(" device will run at. The actual spee depends on the capability\n")
+ .append(" of the host controller.\n")
+ .append(" 0 No limit\n")
+ .append(" 1 Async 1.5MB/s\n")
+ .append(" 2 Async 3.3MB/s\n")
+ .append(" 3 Async 5MB/s\n")
+ .append(" 4 Sync 5MB/s\n")
+ .append(" 5 Sync 10MB/s\n")
+ .append(" ********************************************************* -->\n")
+ .append(" <scsiSpeed>").append(this.scsiSpeed.getValue()).append("</scsiSpeed>\n")
+ .append("</S2S_BoardCfg>\n");
+
+ return out.toString();
+ }
+}
--- /dev/null
+// Copyright (C) 2019 Michael McMaster <michael@codesrc.com>
+//
+// This file is part of scsi2sd-util.
+//
+// scsi2sd-util is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// scsi2sd-util is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with scsi2sd-util. If not, see <https://www.gnu.org/licenses/>.
+
+package com.codesrc.scsi2sd.model;
+
+public class ConfigRoot {
+ private BoardConfig boardConfig;
+ private DiskList diskList;
+
+ public ConfigRoot() {
+ }
+
+ // Deep copy ctor
+ public ConfigRoot(ConfigRoot other) {
+ if (other.boardConfig != null) {
+ this.boardConfig = new BoardConfig(other.boardConfig);
+ }
+
+ if (other.diskList != null) {
+ this.diskList = new DiskList(other.diskList);
+ }
+ }
+
+ public BoardConfig getBoardConfig() {
+ return boardConfig;
+ }
+
+ public void setBoardConfig(BoardConfig boardConfig) {
+ this.boardConfig = boardConfig;
+ }
+
+
+ public DiskList getDiskList() {
+ return diskList;
+ }
+
+ public void setDiskList(DiskList diskList) {
+ this.diskList = diskList;
+ }
+}
--- /dev/null
+// Copyright (C) 2019 Michael McMaster <michael@codesrc.com>
+//
+// This file is part of scsi2sd-util.
+//
+// scsi2sd-util is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// scsi2sd-util is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with scsi2sd-util. If not, see <https://www.gnu.org/licenses/>.
+
+package com.codesrc.scsi2sd.model;
+
+import java.util.*;
+
+public enum DeviceTypeEnum {
+ S2S_CFG_FIXED(0, "Hard Drive"),
+ S2S_CFG_REMOVEABLE(1, "Removable"),
+ S2S_CFG_OPTICAL(2, "CDROM"),
+ S2S_CFG_FLOPPY_14MB(3, "3.5\" Floppy"),
+ S2S_CFG_MO(4, "Magneto Optical"),
+ S2S_CFG_SEQUENTIAL(5, "Tape");
+
+ static DeviceTypeEnum fromValue(byte value) {
+ for (DeviceTypeEnum deviceType : EnumSet.allOf(DeviceTypeEnum.class)) {
+ if (deviceType.value == value)
+ {
+ return deviceType;
+ }
+ }
+ return S2S_CFG_FIXED;
+ }
+
+
+ private int value;
+ private String desc;
+
+ DeviceTypeEnum(int value, String desc) {
+ this.value = value;
+ this.desc = desc;
+ }
+
+ public int getValue() { return this.value; }
+
+ @Override
+ public String toString()
+ {
+ return this.desc;
+ }
+}
--- /dev/null
+// Copyright (C) 2019 Michael McMaster <michael@codesrc.com>
+//
+// This file is part of scsi2sd-util.
+//
+// scsi2sd-util is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// scsi2sd-util is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with scsi2sd-util. If not, see <https://www.gnu.org/licenses/>.
+
+package com.codesrc.scsi2sd.model;
+
+import org.w3c.dom.Node;
+
+import java.nio.charset.StandardCharsets;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+public class DiskConfig {
+ public static final int LENGTH = 128;
+ public static final int SD_SECTOR_SIZE = 512;
+
+ public enum Type {
+ RESERVED,
+ EMPTY,
+ DISK
+ }
+
+ private boolean active;
+ private int scsiId;
+ private Type type;
+ private long sdSectorStart;
+ private long scsiSectors;
+ private int bytesPerSector;
+ private DeviceTypeEnum deviceType;
+ private int deviceTypeModifier;
+
+ // Max allowed by legacy IBM-PC bios is 6 bits (63)
+ private int sectorsPerTrack;
+
+ // MS-Dos up to 7.10 will crash on >= 256 heads.
+ private int headsPerCylinder;
+
+ private String vendor; //[8]
+ private String prodId; //[16];
+ private String revision; //[4];
+ private String serial; //[16];
+
+ private Set<Quirks> quirks;
+
+ public DiskConfig(
+ Type type,
+ long sdSectorStart,
+ long sdSectors) {
+
+ this(type, sdSectorStart, sdSectors, SD_SECTOR_SIZE);
+ }
+
+ public DiskConfig(DiskConfig other) {
+ this.active = other.active;
+ this.scsiId = other.scsiId;
+ this.type = other.type;
+ this.sdSectorStart = other.sdSectorStart;
+ this.scsiSectors = other.scsiSectors;
+ this.bytesPerSector = other.bytesPerSector;
+ this.deviceType = other.deviceType;
+ this.deviceTypeModifier = other.deviceTypeModifier;
+ this.sectorsPerTrack = other.sectorsPerTrack;
+ this.headsPerCylinder = other.headsPerCylinder;
+ this.vendor = other.vendor;
+ this.prodId = other.prodId;
+ this.revision = other.revision;
+ this.serial = other.serial;
+ this.quirks = new HashSet<>(other.quirks);
+ }
+
+ public DiskConfig(
+ Type type,
+ long sdSectorStart,
+ long scsiSectors,
+ int bytesPerSector) {
+
+ this.scsiId = 0;
+ this.active = true;
+ this.type = type;
+ this.sdSectorStart = sdSectorStart;
+ this.scsiSectors = scsiSectors;
+ this.bytesPerSector = bytesPerSector;
+ this.deviceType = DeviceTypeEnum.S2S_CFG_FIXED;
+ this.deviceTypeModifier = 0;
+
+ this.sectorsPerTrack = 63;
+ this.headsPerCylinder = 255;
+
+ this.vendor = this.pad("codesrc", 8);
+ this.prodId = this.pad("SCSI2SD", 16);
+ this.revision = this.pad("1.0", 4);
+ this.serial = this.pad("12345678", 16);
+
+ this.quirks = new HashSet<Quirks>();
+ }
+
+ public DiskConfig(byte[] in) {
+ if (in.length != LENGTH) {
+ throw new IllegalArgumentException("DiskConfig size incorrect");
+ }
+
+ this.active = (in[0] & 0x80) != 0;
+ this.scsiId = in[0] & 0x7;
+ this.deviceType = DeviceTypeEnum.fromValue(in[1]);
+ this.deviceTypeModifier = BitUtil.uint8ToInt(in[3]);
+ this.type = Type.DISK;
+ this.sdSectorStart = BitUtil.letohl(in, 4);
+ this.scsiSectors = BitUtil.letohl(in, 8);
+ this.bytesPerSector = BitUtil.letohs(in, 12);
+
+ this.sectorsPerTrack = BitUtil.letohs(in, 14);
+ this.headsPerCylinder = BitUtil.letohs(in, 16);
+
+ this.vendor = new String(in, 18, 8, StandardCharsets.US_ASCII);
+ this.prodId = new String(in, 26, 16, StandardCharsets.US_ASCII);
+ this.revision = new String(in, 42, 4, StandardCharsets.US_ASCII);
+ this.serial = new String(in, 46, 16, StandardCharsets.US_ASCII);
+
+ this.quirks = Quirks.fromBitmask(BitUtil.letohs(in, 52));
+ }
+
+
+ public byte[] asBytes() {
+ byte[] out = new byte[LENGTH];
+
+ out[0] = BitUtil.intToUint8((this.scsiId & 0x07) | (this.active ? 0 : 0x80));
+
+ out[1] = BitUtil.intToUint8(this.deviceType.getValue());
+ out[2] = 0; // flagsDeprecated
+ out[3] = BitUtil.intToUint8(this.deviceTypeModifier);
+
+ out[4] = BitUtil.longToUint8(this.sdSectorStart);
+ out[5] = BitUtil.longToUint8(this.sdSectorStart >> 8);
+ out[6] = BitUtil.longToUint8(this.sdSectorStart >> 16);
+ out[7] = BitUtil.longToUint8(this.sdSectorStart >> 24);
+
+ out[8] = BitUtil.longToUint8(this.scsiSectors);
+ out[9] = BitUtil.longToUint8(this.scsiSectors >> 8);
+ out[10] = BitUtil.longToUint8(this.scsiSectors >> 16);
+ out[11] = BitUtil.longToUint8(this.scsiSectors >> 24);
+
+ out[12] = BitUtil.intToUint8(this.bytesPerSector);
+ out[13] = BitUtil.intToUint8(this.bytesPerSector >> 8);
+
+ out[14] = BitUtil.intToUint8(this.sectorsPerTrack);
+ out[15] = BitUtil.intToUint8(this.sectorsPerTrack >> 8);
+
+ out[16] = BitUtil.intToUint8(this.headsPerCylinder);
+ out[17] = BitUtil.intToUint8(this.headsPerCylinder >> 8);
+
+ System.arraycopy(this.vendor.getBytes(StandardCharsets.US_ASCII), 0, out, 18, 8);
+ System.arraycopy(this.prodId.getBytes(StandardCharsets.US_ASCII), 0, out, 26, 16);
+ System.arraycopy(this.revision.getBytes(StandardCharsets.US_ASCII), 0, out, 42, 4);
+ System.arraycopy(this.serial.getBytes(StandardCharsets.US_ASCII), 0, out, 46, 16);
+
+ var quirksMask = BitUtil.getMask(this.quirks);
+ out[52] = BitUtil.longToUint8(quirksMask);
+ out[53] = BitUtil.longToUint8(quirksMask >> 8);
+
+ return out;
+ }
+
+ public int getScsiId()
+ {
+ return this.scsiId;
+ }
+
+ public void setScsiId(int value)
+ {
+ this.scsiId = value & 0x7;
+ }
+
+ public Type getType() {
+ return this.type;
+ }
+
+ public boolean isActive() {
+ return active;
+ }
+
+ public void setActive(boolean active) {
+ this.active = active;
+ }
+
+ public DeviceTypeEnum getDeviceType()
+ {
+ return this.deviceType;
+ }
+
+ public void setDeviceType(DeviceTypeEnum deviceType)
+ {
+ this.deviceType = deviceType;
+ }
+
+ public int getDeviceTypeModifier() {
+ return this.deviceTypeModifier;
+ }
+
+ public void setDeviceTypeModifier(int deviceTypeModifier) {
+ this.deviceTypeModifier = deviceTypeModifier;
+ }
+
+ public long getSdSectorStart() {
+ return this.sdSectorStart;
+ }
+
+ public long getSdSectorEnd() {
+ return this.sdSectorStart + this.getSdSectors();
+ }
+
+ public void setSdSectorStart(long value) {
+ this.sdSectorStart = value;
+ }
+
+ public long getScsiSectors() {
+ return this.scsiSectors;
+ }
+
+ public void setScsiSectors(long value) {
+ this.scsiSectors = value;
+ }
+
+ public long getSdSectors() {
+ return ((this.scsiSectors * this.bytesPerSector) + (SD_SECTOR_SIZE - 1)) / SD_SECTOR_SIZE;
+ }
+
+ public int getBytesPerSector() {
+ return this.bytesPerSector;
+ }
+
+ public void setBytesPerSector(int value) {
+ this.bytesPerSector = value;
+ }
+
+ public Quirks getQuirksMode() {
+ if (this.quirks.isEmpty()) {
+ return Quirks.S2S_CFG_QUIRKS_NONE;
+ } else {
+ return this.quirks.iterator().next();
+ }
+ }
+
+ public void setQuirksMode(Quirks quirksMode) {
+ this.quirks.clear();
+ if (quirksMode != Quirks.S2S_CFG_QUIRKS_NONE) {
+ this.quirks.add(quirksMode);
+ }
+ }
+
+ public DiskUnit getBestUnit() {
+ var scsiSize = this.scsiSectors * this.bytesPerSector;
+
+ double base;
+ String suffix;
+ if (scsiSize >= 0.9 * 1024*1024*1024) {
+ return DiskUnit.GB;
+ }
+ else if (scsiSize >= 0.9 * 1024*1024) {
+ return DiskUnit.MB;
+ }
+ else
+ {
+ return DiskUnit.SECTOR;
+ }
+ }
+
+ public String getSizeString(DiskUnit unit, boolean showSuffix) {
+ var scsiSize = this.scsiSectors * this.bytesPerSector;
+
+ double base;
+ String suffix;
+ if (unit == DiskUnit.GB) {
+ base = scsiSize / (1024.0*1024*1024);
+ suffix = "GB";
+ }
+ else if (unit == DiskUnit.MB) {
+ base = scsiSize / (1024.0*1024);
+ suffix = "MB";
+ }
+ else {
+ base = this.scsiSectors;
+ suffix = "Sectors";
+ }
+
+ if (showSuffix) {
+ return String.format("%.2f %s", base, suffix);
+ }
+ else if (unit != DiskUnit.SECTOR)
+ {
+ return String.format("%.2f", base);
+ }
+ else
+ {
+ return String.format("%d", (long)base);
+ }
+ }
+
+ public String getVendor() {
+ return vendor;
+ }
+
+ public void setVendor(String vendor) {
+ this.vendor = this.pad(vendor, 8);
+ }
+
+ public String getProdId() {
+ return prodId;
+ }
+
+ public void setProdId(String prodId) {
+ this.prodId = this.pad(prodId, 16);
+ }
+
+ public String getRevision() {
+ return revision;
+ }
+
+ public void setRevision(String revision) {
+ this.revision = this.pad(revision, 4);
+ }
+
+ public String getSerial() {
+ return serial;
+ }
+
+ public void setSerial(String serial) {
+ this.serial = this.pad(serial, 16);
+ }
+
+ public int getSectorsPerTrack() {
+ return sectorsPerTrack;
+ }
+
+ public void setSectorsPerTrack(int sectorsPerTrack) {
+ this.sectorsPerTrack = sectorsPerTrack;
+ }
+
+ public int getHeadsPerCylinder() {
+ return headsPerCylinder;
+ }
+
+ public void setHeadsPerCylinder(int headsPerCylinder) {
+ this.headsPerCylinder = headsPerCylinder;
+ }
+
+ private String pad(String input, int count)
+ {
+ if (input.length() >= count)
+ {
+ return input.substring(0, count);
+ }
+ else
+ {
+ return " ".repeat(count - input.length()) + input;
+ }
+ }
+
+ public DiskConfig(Node node) {
+ this.type = Type.DISK;
+
+ var childNodes = node.getChildNodes();
+ var children = IntStream.range(0, childNodes.getLength())
+ .mapToObj(childNodes::item)
+ .filter(n -> n.getNodeType() == Node.ELEMENT_NODE)
+ .filter(n -> n.hasChildNodes() &&
+ n.getFirstChild().getNodeType() == Node.TEXT_NODE)
+ .collect(Collectors.toMap(n -> n.getNodeName(), n -> n.getFirstChild().getNodeValue().trim()));
+
+ this.scsiId = 0;
+ var idAttr = node.getAttributes().getNamedItem("id");
+ if (idAttr != null) {
+ try {
+ var id = Integer.valueOf(idAttr.getNodeValue());
+ if (id >= 0 && id <= 7) {
+ this.scsiId = id;
+ }
+ } catch (NumberFormatException e) {
+ // Ignore
+ }
+ }
+
+ if (children.getOrDefault("enabled", "true").equalsIgnoreCase("true")) {
+ this.active = true;
+ } else {
+ this.active = false;
+ }
+
+ this.quirks = new HashSet<>();
+ switch (children.getOrDefault("quirks", "").toLowerCase()) {
+ case "apple":
+ this.quirks.add(Quirks.S2S_CFG_QUIRKS_APPLE);
+ break;
+ case "omti":
+ this.quirks.add(Quirks.S2S_CFG_QUIRKS_OMTI);
+ break;
+ case "xebec":
+ this.quirks.add(Quirks.S2S_CFG_QUIRKS_XEBEC);
+ break;
+ case "vms":
+ this.quirks.add(Quirks.S2S_CFG_QUIRKS_VMS);
+ break;
+ }
+
+ this.deviceType = DeviceTypeEnum.S2S_CFG_FIXED;
+ var devTypeText = children.getOrDefault("deviceType", "0");
+ try {
+ var radix = 10;
+ if (devTypeText.toLowerCase().startsWith("0x")) {
+ radix = 16;
+ devTypeText = devTypeText.substring(2);
+ }
+ var byteValue = Byte.valueOf(devTypeText, radix);
+ this.deviceType = DeviceTypeEnum.fromValue(byteValue);
+ } catch (NumberFormatException e) {
+ }
+
+ this.deviceTypeModifier = 0;
+ var devTypeModText = children.getOrDefault("deviceTypeModifier", "0");
+ try {
+ var radix = 10;
+ if (devTypeModText.toLowerCase().startsWith("0x")) {
+ radix = 16;
+ devTypeModText = devTypeModText.substring(2);
+ }
+ this.deviceTypeModifier = Byte.valueOf(devTypeModText, radix);
+ } catch (NumberFormatException e) {
+ }
+
+
+ this.sdSectorStart = 0;
+ var sdSectorStartText = children.getOrDefault("sdSectorStart", "0");
+ try {
+ var longValue = Long.valueOf(sdSectorStartText);
+ if (longValue >= 0) {
+ this.sdSectorStart = longValue;
+ }
+ } catch (NumberFormatException e) {
+ }
+
+
+ this.scsiSectors = 1;
+ var scsiSectorsText = children.getOrDefault("scsiSectors", "1");
+ try {
+ var longValue = Long.valueOf(scsiSectorsText);
+ if (longValue >= 0) {
+ this.scsiSectors = longValue;
+ }
+ } catch (NumberFormatException e) {
+ }
+
+ this.bytesPerSector = 512;
+ var bytesPerSectorText = children.getOrDefault("bytesPerSector", "512");
+ try {
+ var intValue = Integer.valueOf(bytesPerSectorText);
+ if (intValue > 0 && intValue <= 65535) {
+ this.bytesPerSector = intValue;
+ }
+ } catch (NumberFormatException e) {
+ }
+
+ this.sectorsPerTrack = 63;
+ var sectorsPerTrackText = children.getOrDefault("sectorsPerTrack", "63");
+ try {
+ var intValue = Integer.valueOf(sectorsPerTrackText);
+ if (intValue > 0 && intValue <= 65535) {
+ this.sectorsPerTrack = intValue;
+ }
+ } catch (NumberFormatException e) {
+ }
+
+ this.headsPerCylinder = 255;
+ var headsPerCylinderText = children.getOrDefault("headsPerCylinder", "255");
+ try {
+ var intValue = Integer.valueOf(headsPerCylinderText);
+ if (intValue > 0 && intValue <= 65535) {
+ this.headsPerCylinder = intValue;
+ }
+ } catch (NumberFormatException e) {
+ }
+
+ this.vendor = this.pad(children.getOrDefault("vendor", "codesrc"), 8);
+ this.prodId = this.pad(children.getOrDefault("prodId", "SCSI2SD"), 16);
+ this.revision = this.pad(children.getOrDefault("revision", "1.0"), 4);
+ this.serial = this.pad(children.getOrDefault("serial", "12345678"), 16);
+ }
+
+ public String toXML() {
+ var out = new StringBuilder();
+
+ out.append("<SCSITarget id=\"").append(this.scsiId).append("\">\n")
+ .append(" <enabled>")
+ .append(this.active ? "true" : "false")
+ .append("</enabled>\n")
+
+ .append("\n")
+ .append(" <!-- ********************************************************\n")
+ .append(" Space separated list. Available options:\n")
+ .append(" apple\t\tReturns Apple-specific mode pages\n")
+ .append(" omti\t\tOMTI host non-standard link control\n")
+ .append(" xebec\t\tXEBEC ignore step options in control byte\n")
+ .append(" vms\t\tVMS treat 255 bytes as 254 in Inquiry length\n")
+ .append(" ********************************************************* -->\n")
+ .append(" <quirks>");
+
+ if (this.quirks.contains(Quirks.S2S_CFG_QUIRKS_APPLE)) {
+ out.append("apple");
+ }
+ else if (this.quirks.contains(Quirks.S2S_CFG_QUIRKS_OMTI)) {
+ out.append("omti");
+ }
+ else if (this.quirks.contains(Quirks.S2S_CFG_QUIRKS_XEBEC)) {
+ out.append("xebec");
+ }
+ else if (this.quirks.contains(Quirks.S2S_CFG_QUIRKS_VMS)) {
+ out.append("vms");
+ }
+
+ out.append("</quirks>\n")
+ .append("\n\n")
+ .append(" <!-- ********************************************************\n")
+ .append(" 0x0 Fixed hard drive.\n")
+ .append(" 0x1 Removable drive.\n")
+ .append(" 0x2 Optical drive (ie. CD drive).\n")
+ .append(" 0x3 1.44MB Floppy Drive.\n")
+ .append(" ********************************************************* -->\n")
+ .append(" <deviceType>0x")
+ .append(Integer.toString(this.deviceType.getValue(), 16))
+ .append("</deviceType>\n")
+
+ .append("\n\n")
+ .append(" <!-- ********************************************************\n")
+ .append(" Device type modifier is usually 0x00. Only change this if your\n")
+ .append(" OS requires some special value.\n")
+ .append("\n")
+ .append(" 0x4C Data General Micropolis disk\n")
+ .append(" ********************************************************* -->\n")
+ .append(" <deviceTypeModifier>0x")
+ .append(Integer.toString(this.deviceTypeModifier, 16))
+ .append("</deviceTypeModifier>\n")
+
+ .append("\n\n")
+ .append(" <!-- ********************************************************\n")
+ .append(" SD card offset, as a sector number (always 512 bytes).\n")
+ .append(" ********************************************************* -->\n")
+ .append(" <sdSectorStart>").append(this.sdSectorStart).append("</sdSectorStart>\n")
+ .append("\n\n")
+ .append(" <!-- ********************************************************\n")
+ .append(" Drive geometry settings.\n")
+ .append(" ********************************************************* -->\n")
+ .append("\n")
+ .append(" <scsiSectors>").append(this.scsiSectors).append("</scsiSectors>\n")
+ .append(" <bytesPerSector>").append(this.bytesPerSector).append("</bytesPerSector>\n")
+ .append(" <sectorsPerTrack>").append(this.sectorsPerTrack).append("</sectorsPerTrack>\n")
+ .append(" <headsPerCylinder>").append(this.headsPerCylinder).append("</headsPerCylinder>\n")
+ .append("\n\n")
+ .append(" <!-- ********************************************************\n")
+ .append(" Drive identification information. The SCSI2SD doesn't\n")
+ .append(" care what these are set to. Use these strings to trick a OS\n")
+ .append(" thinking a specific hard drive model is attached.\n")
+ .append(" ********************************************************* -->\n")
+ .append("\n")
+ .append(" <!-- 8 character vendor string -->\n")
+ .append(" <!-- For Apple HD SC Setup/Drive Setup, use ' SEAGATE' -->\n")
+ .append(" <vendor>").append(this.vendor).append("</vendor>\n")
+ .append("\n")
+ .append(" <!-- 16 character produce identifier -->\n")
+ .append(" <!-- For Apple HD SC Setup/Drive Setup, use ' ST225N' -->\n")
+ .append(" <prodId>").append(this.prodId).append("</prodId>\n")
+ .append("\n")
+ .append(" <!-- 4 character product revision number -->\n")
+ .append(" <!-- For Apple HD SC Setup/Drive Setup, use '1.0 ' -->\n")
+ .append(" <revision>").append(this.revision).append("</revision>\n")
+ .append("\n")
+ .append(" <!-- 16 character serial number -->\n")
+ .append(" <serial>").append(this.serial).append("</serial>\n")
+ .append("\n")
+ .append("</SCSITarget>\n");
+
+ return out.toString();
+ }
+}
--- /dev/null
+// Copyright (C) 2019 Michael McMaster <michael@codesrc.com>
+//
+// This file is part of scsi2sd-util.
+//
+// scsi2sd-util is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// scsi2sd-util is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with scsi2sd-util. If not, see <https://www.gnu.org/licenses/>.
+
+package com.codesrc.scsi2sd.model;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+// List of disk configurations sorted by SD Starting Sector.
+public class DiskList {
+
+ public static final long reservedSize = 1024*1024 / 512; // oneMb
+
+ private long sdCardSize;
+ private LinkedList<DiskConfig> disks;
+
+ // Deep copy ctor
+ public DiskList(DiskList other) {
+ this.sdCardSize = other.sdCardSize;
+ this.disks = new LinkedList<>();
+ for (var disk : other.disks) {
+ this.disks.add(new DiskConfig(disk));
+ }
+ }
+
+ public DiskList(long sdCardSize) {
+ this.sdCardSize = sdCardSize;
+ disks = new LinkedList<>();
+
+ // Always reserve the first 1Mb for partitioning info
+ disks.add(new DiskConfig(DiskConfig.Type.RESERVED, 0, reservedSize));
+ disks.add(new DiskConfig(DiskConfig.Type.EMPTY, reservedSize, sdCardSize - reservedSize - reservedSize));
+
+ // Also reserve 1Mb at the end for config info
+ disks.add(new DiskConfig(DiskConfig.Type.RESERVED, sdCardSize - reservedSize, reservedSize));
+ }
+
+ public List<DiskConfig> getDisks() {
+ return new ArrayList<>(this.disks);
+ }
+
+ public String getSdCardSizeGb() {
+ return String.format("%.2f", (this.sdCardSize * 512.0) / (1024l*1024*1024));
+ }
+
+ public long getSdCardSize() {
+ return this.sdCardSize;
+ }
+
+
+ public void resetSizeGb(double gb) {
+ var newSize = (long) (gb * (1024l * 1024 * 1024 / 512));
+
+ if (newSize > sdCardSize) {
+ var diffSectors = newSize - sdCardSize;
+ if (disks.getLast().getType() == DiskConfig.Type.RESERVED) {
+ var reserved = disks.getLast();
+ var oldStart = reserved.getSdSectorStart();
+ reserved.setSdSectorStart(oldStart + diffSectors);
+ disks.add(disks.size() - 1, new DiskConfig(DiskConfig.Type.EMPTY, oldStart, diffSectors));
+ }
+ else
+ {
+ disks.add(new DiskConfig(DiskConfig.Type.EMPTY, sdCardSize, diffSectors));
+ }
+
+
+ } else if (newSize < sdCardSize){
+ var lastNonReserved = newSize - reservedSize;
+ while (!disks.isEmpty() && disks.getLast().getSdSectorEnd() > lastNonReserved) {
+ disks.removeLast();
+ }
+
+ if (!disks.isEmpty()) {
+ var lastNotRemoved = disks.getLast().getSdSectorEnd();
+ if (lastNotRemoved < lastNonReserved) {
+ disks.add(new DiskConfig(DiskConfig.Type.EMPTY, lastNotRemoved, lastNonReserved - lastNotRemoved));
+ }
+ }
+
+ disks.add(new DiskConfig(DiskConfig.Type.RESERVED, lastNonReserved, reservedSize));
+ }
+ this.mergeEmptySections();
+
+ sdCardSize = newSize;
+ }
+
+ public boolean add(DiskConfig config) {
+ var found = false;
+
+ this.removeReservedSections(config);
+ this.mergeEmptySections();
+
+ var it = disks.listIterator();
+ while (it.hasNext())
+ {
+ var entry = it.next();
+ if (entry.getType() == DiskConfig.Type.EMPTY &&
+ entry.getSdSectors() >= config.getSdSectors()) {
+ if (config.getSdSectorStart() < 0 ||
+ config.getSdSectorStart() == entry.getSdSectorStart())
+ {
+ config.setSdSectorStart(entry.getSdSectorStart());
+ entry.setSdSectorStart(entry.getSdSectorStart() + config.getSdSectors());
+ entry.setScsiSectors(entry.getSdSectors() - config.getSdSectors());
+
+ if (entry.getSdSectors() == 0)
+ {
+ it.remove();
+ }
+ else
+ {
+ it.previous();
+ }
+
+ it.add(config);
+
+ found = true;
+ break;
+ }
+ else if (config.getSdSectorStart() > entry.getSdSectorStart() &&
+ config.getSdSectorEnd() <= entry.getSdSectorEnd())
+ {
+ var remaining = new DiskConfig(
+ DiskConfig.Type.EMPTY,
+ config.getSdSectorEnd(),
+ entry.getSdSectorEnd() - config.getSdSectorEnd());
+
+ entry.setScsiSectors(config.getSdSectorStart() - entry.getSdSectorStart());
+
+ it.add(entry);
+
+ if (remaining.getSdSectors() > 0) {
+ it.add(remaining);
+ }
+
+ found = true;
+ break;
+ }
+ }
+ }
+
+ return found;
+ }
+
+ public void remove(DiskConfig config) {
+ if (config.getType() != DiskConfig.Type.DISK) {
+ // Don't delete reserved or empty space.
+ return;
+ }
+
+ for (var i = 0; i < disks.size(); ++i) {
+ var entry = disks.get(i);
+
+ if (entry == config)
+ {
+ var startSector = config.getSdSectorStart();
+ var endSector = config.getSdSectorEnd();
+ disks.remove(i);
+
+ var empty = new DiskConfig(DiskConfig.Type.EMPTY, startSector, endSector - startSector);
+ if (empty.getSdSectors() > 0)
+ {
+ disks.add(i, empty);
+ }
+
+ break;
+ }
+ }
+
+ this.mergeEmptySections();
+ }
+
+ // Convert RESERVED into EMPTY if needed.
+ // Can't do this with the UI but can edit XML file or load an old config.
+ private void removeReservedSections(DiskConfig config)
+ {
+ for (var i = 0; i < disks.size(); ++i)
+ {
+ var entry = disks.get(i);
+
+ if (entry.getType() == DiskConfig.Type.RESERVED &&
+ config.getSdSectorStart() < entry.getSdSectorEnd() &&
+ config.getSdSectorEnd() > entry.getSdSectorStart())
+ {
+ var reservedStartSector = entry.getSdSectorStart();
+ var reservedEndSector = entry.getSdSectorEnd();
+ disks.remove(i);
+
+ var stillReservedAtStartSize = config.getSdSectorStart() - reservedStartSector;
+ if (stillReservedAtStartSize > 0)
+ {
+ disks.add(i, new DiskConfig(DiskConfig.Type.RESERVED, reservedStartSector, stillReservedAtStartSize));
+ ++i;
+ }
+
+ var emptyStart = reservedStartSector > config.getSdSectorStart() ? reservedStartSector : config.getSdSectorStart();
+ var emptyEnd = reservedEndSector > config.getSdSectorEnd() ? config.getSdSectorEnd() : reservedEndSector;
+ disks.add(i, new DiskConfig(DiskConfig.Type.EMPTY, emptyStart, emptyEnd - emptyStart));
+ ++i;
+
+ var stillReservedAtEndSize = reservedEndSector - config.getSdSectorEnd();
+ if (stillReservedAtEndSize > 0)
+ {
+ disks.add(i, new DiskConfig(DiskConfig.Type.RESERVED, config.getSdSectorEnd(), stillReservedAtEndSize));
+ ++i;
+ }
+ }
+ }
+ }
+
+ private void mergeEmptySections()
+ {
+ var i = 0;
+ while (i < disks.size() - 1)
+ {
+ var entry = disks.get(i);
+ if (entry.getType() != DiskConfig.Type.EMPTY)
+ {
+ ++i;
+ continue;
+ }
+
+ var next = disks.get(i + 1);
+ if (next.getType() != DiskConfig.Type.EMPTY)
+ {
+ ++i;
+ continue;
+ }
+
+ var endSector = next.getSdSectorEnd();
+ disks.remove(i + 1);
+ disks.remove(i);
+ disks.add(i, new DiskConfig(DiskConfig.Type.EMPTY, entry.getSdSectorStart(), endSector- entry.getSdSectorStart()));
+ }
+ }
+}
--- /dev/null
+// Copyright (C) 2019 Michael McMaster <michael@codesrc.com>
+//
+// This file is part of scsi2sd-util.
+//
+// scsi2sd-util is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// scsi2sd-util is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with scsi2sd-util. If not, see <https://www.gnu.org/licenses/>.
+
+package com.codesrc.scsi2sd.model;
+
+public enum DiskUnit {
+ MB, GB, SECTOR
+}
-// Copyright (C) 2017 Michael McMaster <michael@codesrc.com>
+// Copyright (C) 2019 Michael McMaster <michael@codesrc.com>
//
-// This file is part of SCSI2SD.
+// This file is part of scsi2sd-util.
//
-// SCSI2SD is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
+// scsi2sd-util is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
//
-// SCSI2SD is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
+// scsi2sd-util is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
//
-// You should have received a copy of the GNU General Public License
-// along with SCSI2SD. If not, see <http://www.gnu.org/licenses/>.
+// You should have received a copy of the GNU General Public License
+// along with scsi2sd-util. If not, see <https://www.gnu.org/licenses/>.
package com.codesrc.scsi2sd.model;
--- /dev/null
+// Copyright (C) 2019 Michael McMaster <michael@codesrc.com>
+//
+// This file is part of scsi2sd-util.
+//
+// scsi2sd-util is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// scsi2sd-util is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with scsi2sd-util. If not, see <https://www.gnu.org/licenses/>.
+
+package com.codesrc.scsi2sd.model;
+
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.Set;
+
+public enum Flag6 implements BitEnum {
+ S2S_CFG_ENABLE_TERMINATOR(1);
+
+ static Set<Flag6> fromBitmask(byte bitmask) {
+ Set<Flag6> result = new HashSet<>();
+ for (Flag6 flag : EnumSet.allOf(Flag6.class)) {
+ if ((((int) bitmask & 0xFF) & flag.getBit()) != 0) {
+ result.add(flag);
+ }
+ }
+ return result;
+ }
+
+ private int bit;
+ Flag6(int bit) {
+ this.bit = bit;
+ }
+
+ @Override
+ public int getBit() { return bit; }
+}
--- /dev/null
+// Copyright (C) 2019 Michael McMaster <michael@codesrc.com>
+//
+// This file is part of scsi2sd-util.
+//
+// scsi2sd-util is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// scsi2sd-util is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with scsi2sd-util. If not, see <https://www.gnu.org/licenses/>.
+
+package com.codesrc.scsi2sd.model;
+
+import java.util.*;
+
+public enum Quirks implements BitEnum {
+ S2S_CFG_QUIRKS_NONE(0, "None"),
+ S2S_CFG_QUIRKS_APPLE(1, "Apple"),
+ S2S_CFG_QUIRKS_OMTI(2, "OMTI"),
+ S2S_CFG_QUIRKS_XEBEC(4, "XEBEC"),
+ S2S_CFG_QUIRKS_VMS(8, "VMS");
+
+ static Set<Quirks> fromBitmask(int bitmask) {
+ Set<Quirks> result = new HashSet<>();
+ for (Quirks flag : EnumSet.allOf(Quirks.class)) {
+ if ((bitmask & flag.getBit()) != 0) {
+ result.add(flag);
+ }
+ }
+ return result;
+ }
+
+
+ private int bit;
+ private String desc;
+
+ Quirks(int bit, String desc) {
+ this.bit = bit;
+ this.desc = desc;
+ }
+
+ @Override
+ public int getBit() { return bit; }
+
+ @Override
+ public String toString()
+ {
+ return this.desc;
+ }
+
+}
--- /dev/null
+// Copyright (C) 2019 Michael McMaster <michael@codesrc.com>
+//
+// This file is part of scsi2sd-util.
+//
+// scsi2sd-util is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// scsi2sd-util is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with scsi2sd-util. If not, see <https://www.gnu.org/licenses/>.
+
+package com.codesrc.scsi2sd.model;
+
+import java.util.EnumSet;
+
+public enum Speed {
+ S2S_CFG_SPEED_NoLimit(0, "No limit"),
+ S2S_CFG_SPEED_ASYNC_15(1, "Async, 1.5MB/s"),
+ S2S_CFG_SPEED_ASYNC_33(2, "Async, 3.3MB/s"),
+ S2S_CFG_SPEED_ASYNC_50(3, "Async, 5.0MB/s"),
+ S2S_CFG_SPEED_SYNC_5(4, "Sync, 5.0MB/s"),
+ S2S_CFG_SPEED_SYNC_10(5, "Sync, 10MB/s"),
+ S2S_CFG_SPEED_TURBO(6, "Turbo");
+
+ static Speed fromBits(byte bits) {
+
+ for (Speed speed : EnumSet.allOf(Speed.class)) {
+ if (speed.getValue() == ((int) bits & 0xFF)) {
+ return speed;
+ }
+ }
+ return S2S_CFG_SPEED_NoLimit;
+ }
+
+
+ private int value;
+ private String desc;
+
+ Speed(int value, String desc) {
+ this.value = value;
+ this.desc = desc;
+ }
+
+ public int getValue() {
+ return value;
+ }
+
+ @Override
+ public String toString() {
+ return this.desc;
+ }
+}
+
+
--- /dev/null
+// Copyright (C) 2019 Michael McMaster <michael@codesrc.com>
+//
+// This file is part of scsi2sd-util.
+//
+// scsi2sd-util is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// scsi2sd-util is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with scsi2sd-util. If not, see <https://www.gnu.org/licenses/>.
+
+package com.codesrc.scsi2sd.presentation;
+
+import com.codesrc.scsi2sd.ScreensConfiguration;
+import javafx.fxml.FXML;
+import javafx.scene.control.*;
+import javafx.scene.Scene;
+import javafx.scene.image.Image;
+import org.slf4j.LoggerFactory;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.util.Properties;
+import java.util.ResourceBundle;
+import java.util.stream.Collectors;
+
+/**
+ * Created by michael on 27/05/17.
+ */
+public class AboutController implements FXController {
+ private static org.slf4j.Logger LOGGER = LoggerFactory.getLogger(AboutController.class);
+
+ private ScreensConfiguration screens;
+ private FXWindow window;
+
+ @FXML private TextArea aboutText;
+ @FXML private Label labelVersion;
+ @FXML private Hyperlink licenceLink;
+ @FXML private Button buttonClose;
+
+ private Desktop desktop;
+
+ private String licenseURL;
+
+ private String contactURL;
+
+ private String appVersion;
+
+ public AboutController(
+ ScreensConfiguration screens,
+ Desktop desktop,
+ Properties appProperties) {
+
+ this.screens = screens;
+ this.desktop = desktop;
+ this.licenseURL = appProperties.getProperty("com.codesrc.scsi2sd.app.licence.url");
+ this.appVersion = appProperties.getProperty("com.codesrc.scsi2sd.app.version");
+ }
+
+ @Override
+ public void setWindow(FXWindow window) {
+ this.window = window;
+ }
+
+ @Override
+ public void onSceneCreating(Scene scene)
+ {
+ }
+
+ public void initialize(URL url, ResourceBundle resourceBundle) {
+ String about = new BufferedReader(new InputStreamReader(getClass().getResourceAsStream("/COPYING")))
+ .lines().collect(Collectors.joining("\n"));
+
+ aboutText.setText(about);
+ labelVersion.setText(appVersion);
+
+ licenceLink.setTooltip(new Tooltip(licenseURL));
+ licenceLink.setOnAction(h -> desktop.openBrowser(licenseURL));
+
+ buttonClose.setOnAction(h -> window.close());
+ }
+
+}
--- /dev/null
+// Copyright (C) 2019 Michael McMaster <michael@codesrc.com>
+//
+// This file is part of scsi2sd-util.
+//
+// scsi2sd-util is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// scsi2sd-util is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with scsi2sd-util. If not, see <https://www.gnu.org/licenses/>.
+
+package com.codesrc.scsi2sd.presentation;
+
+import com.codesrc.scsi2sd.ScreensConfiguration;
+import com.codesrc.scsi2sd.document.ActiveDocument;
+import com.codesrc.scsi2sd.document.DocumentObserver;
+import com.codesrc.scsi2sd.model.*;
+import javafx.fxml.FXML;
+import javafx.fxml.Initializable;
+import javafx.scene.control.CheckBox;
+import javafx.scene.control.ChoiceBox;
+import javafx.scene.control.TextField;
+import org.controlsfx.control.ToggleSwitch;
+
+import java.net.URL;
+import java.util.ResourceBundle;
+
+/**
+ * Created by michael on 28/05/17.
+ */
+public class ConfigController implements Initializable, DocumentObserver {
+
+ private ScreensConfiguration screens;
+ private ActiveDocument activeDocument;
+
+ @FXML private TextField cfgSelectionDelay;
+
+ @FXML private TextField cfgStartupDelay;
+
+ @FXML private CheckBox cfgEnableTerminator;
+
+ @FXML private ToggleSwitch cfgCheckParity;
+ @FXML private ToggleSwitch cfgUnitAtt;
+ @FXML private ToggleSwitch cfgScsi2;
+ @FXML private ToggleSwitch cfgSelPulses;
+ @FXML private ToggleSwitch cfgMapLuns;
+
+ @FXML private ChoiceBox speedLimit;
+
+ private BoardConfig boardConfig;
+
+ public ConfigController(ScreensConfiguration screens, ActiveDocument document) {
+ this.screens = screens;
+ this.activeDocument = document;
+ document.addObserver(this);
+ }
+
+ @Override
+ public void initialize(URL url, ResourceBundle resourceBundle) {
+ this.cfgSelectionDelay.setOnAction(e -> this.setSelectionDelay());
+ this.cfgSelectionDelay.focusedProperty().addListener((obs, wasFocussed, isNowFocussed) -> {if (!isNowFocussed) this.setSelectionDelay();});
+
+ this.cfgStartupDelay.setOnAction(e -> this.setStartupDelay());
+ this.cfgStartupDelay.focusedProperty().addListener((obs, wasFocussed, isNowFocussed) -> {if (!isNowFocussed) this.setStartupDelay();});
+
+ this.cfgEnableTerminator.setOnAction(e -> this.setTerminator());
+ this.cfgCheckParity.selectedProperty().addListener(it -> this.setFlag(Flag.S2S_CFG_ENABLE_PARITY, this.cfgCheckParity));
+ this.cfgUnitAtt.selectedProperty().addListener(it -> this.setFlag(Flag.S2S_CFG_ENABLE_UNIT_ATTENTION, this.cfgUnitAtt));
+ this.cfgScsi2.selectedProperty().addListener(it -> this.setFlag(Flag.S2S_CFG_ENABLE_SCSI2, this.cfgScsi2));
+ this.cfgSelPulses.selectedProperty().addListener(it -> this.setFlag(Flag.S2S_CFG_ENABLE_SEL_LATCH, this.cfgSelPulses));
+ this.cfgMapLuns.selectedProperty().addListener(it -> this.setFlag(Flag.S2S_CFG_MAP_LUNS_TO_IDS, this.cfgMapLuns));
+
+ this.speedLimit.getItems().addAll(Speed.values());
+ this.speedLimit.setOnAction(e -> this.setSpeedLimit());
+
+ }
+ public void documentLoaded(ActiveDocument document)
+ {
+ ConfigRoot root = document.getActiveDocument();
+ this.boardConfig = root.getBoardConfig();
+
+ if (this.boardConfig.getSelectionDelay() == 255)
+ {
+ cfgSelectionDelay.setText(null);
+ }
+ else {
+ cfgSelectionDelay.setText(String.valueOf(this.boardConfig.getSelectionDelay()));
+ }
+
+ if (this.boardConfig.getStartupDelay() == 0)
+ {
+ cfgStartupDelay.setText(null);
+ }
+ else {
+ cfgStartupDelay.setText(String.valueOf(this.boardConfig.getStartupDelay()));
+ }
+
+ cfgEnableTerminator.setSelected(this.boardConfig.isEnableTerminator());
+ // TODO check board type. cfgEnableTerminator.setDisable(this.get);
+
+ cfgCheckParity.setSelected(this.boardConfig.getFlags().contains(Flag.S2S_CFG_ENABLE_PARITY));
+ cfgUnitAtt.setSelected(this.boardConfig.getFlags().contains(Flag.S2S_CFG_ENABLE_UNIT_ATTENTION));
+ cfgScsi2.setSelected(this.boardConfig.getFlags().contains(Flag.S2S_CFG_ENABLE_SCSI2));
+ cfgSelPulses.setSelected(this.boardConfig.getFlags().contains(Flag.S2S_CFG_ENABLE_SEL_LATCH));
+ cfgMapLuns.setSelected(this.boardConfig.getFlags().contains(Flag.S2S_CFG_MAP_LUNS_TO_IDS));
+
+ this.speedLimit.setValue(this.boardConfig.getScsiSpeed());
+ }
+
+ public void documentModified(ActiveDocument document, boolean isModified)
+ {
+
+ }
+ public void documentValid(ActiveDocument document, boolean isValid)
+ {
+
+ }
+
+ private void setFlag(Flag flag, ToggleSwitch control)
+ {
+ if (this.boardConfig != null)
+ {
+ this.boardConfig.setFlag(flag, control.isSelected());
+ this.activeDocument.setModified(this.getClass().getName(), true);
+ }
+ }
+
+ private void setTerminator()
+ {
+ if (this.boardConfig != null)
+ {
+ this.boardConfig.setFlag6(Flag6.S2S_CFG_ENABLE_TERMINATOR, this.cfgEnableTerminator.isSelected());
+ this.activeDocument.setModified(this.getClass().getName(), true);
+ }
+ }
+
+ private void setStartupDelay()
+ {
+ if (this.boardConfig != null)
+ {
+ var in = this.cfgStartupDelay.getText();
+ int intValue;
+
+ if (in == null || in.isEmpty())
+ {
+ intValue = 0;
+ }
+ else
+ {
+ var oldValue = this.boardConfig.getStartupDelay();
+
+ try {
+ intValue = Integer.valueOf(in);
+ if (intValue < 0 || intValue > 255)
+ {
+ this.cfgStartupDelay.setText(oldValue == 0 ? "" : String.valueOf(oldValue));
+ return;
+ }
+
+ } catch (NumberFormatException e) {
+ this.cfgStartupDelay.setText(oldValue == 0 ? "" : String.valueOf(oldValue));
+ return;
+ }
+ }
+
+ this.boardConfig.setStartupDelay(intValue);
+ this.cfgStartupDelay.setText(intValue == 0 ? "" : String.valueOf(intValue));
+ this.activeDocument.setModified(DiskConfigController.class.getName(), true);
+ }
+ }
+
+ private void setSelectionDelay()
+ {
+ if (this.boardConfig != null)
+ {
+ var in = this.cfgSelectionDelay.getText();
+ int intValue;
+
+ if (in == null || in.isEmpty())
+ {
+ intValue = 255;
+ }
+ else
+ {
+ var oldValue = this.boardConfig.getSelectionDelay();
+
+ try {
+ intValue = Integer.valueOf(in);
+ if (intValue < 0 || intValue > 255)
+ {
+ this.cfgSelectionDelay.setText(oldValue == 255 ? "" : String.valueOf(oldValue));
+ return;
+ }
+
+ } catch (NumberFormatException e) {
+ this.cfgSelectionDelay.setText(oldValue == 255 ? "" : String.valueOf(oldValue));
+ return;
+ }
+ }
+
+ this.boardConfig.setSelectionDelay(intValue);
+ this.cfgSelectionDelay.setText(intValue == 255 ? "" : String.valueOf(intValue));
+ this.activeDocument.setModified(DiskConfigController.class.getName(), true);
+ }
+ }
+
+ private void setSpeedLimit()
+ {
+ if (this.boardConfig != null)
+ {
+ this.boardConfig.setScsiSpeed((Speed)this.speedLimit.getValue());
+ this.activeDocument.setModified(this.getClass().getName(), true);
+ }
+ }
+}
--- /dev/null
+// Copyright (C) 2019 Michael McMaster <michael@codesrc.com>
+//
+// This file is part of scsi2sd-util.
+//
+// scsi2sd-util is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// scsi2sd-util is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with scsi2sd-util. If not, see <https://www.gnu.org/licenses/>.
+
+package com.codesrc.scsi2sd.presentation;
+
+import com.codesrc.scsi2sd.ScreensConfiguration;
+import com.codesrc.scsi2sd.io.UsbDeviceManager;
+import javafx.fxml.FXML;
+import javafx.scene.Scene;
+import javafx.scene.control.MenuItem;
+import javafx.scene.control.TabPane;
+import javafx.scene.control.TextArea;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.URL;
+import java.util.ResourceBundle;
+import java.util.logging.Level;
+
+
+/**
+ * Created by michael on 21/05/17.
+ */
+public class DebugLogController implements FXController {
+ private static Logger LOGGER = LoggerFactory.getLogger(DebugLogController.class);
+
+ private ScreensConfiguration screens;
+ private FXWindow window;
+
+ private UsbDeviceManager usbDeviceManager;
+ private LogHandler logHandler;
+
+ @FXML private TextArea logTextArea;
+
+ public DebugLogController(ScreensConfiguration screens, UsbDeviceManager usbDeviceManager) {
+ this.screens = screens;
+ this.usbDeviceManager = usbDeviceManager;
+ }
+
+ @Override
+ public void setWindow(FXWindow window) {
+ this.window = window;
+ }
+
+ @Override
+ public void onSceneCreating(Scene scene)
+ {
+ }
+
+ @Override
+ public void initialize(URL url, ResourceBundle resourceBundle) {
+
+ this.logHandler = new LogHandler(this.logTextArea);
+ logHandler.setLevel(Level.INFO);
+ java.util.logging.Logger usbLogger = java.util.logging.Logger.getLogger(UsbDeviceManager.class.getPackageName());
+
+ usbLogger.addHandler(this.logHandler);
+ }
+}
-// Copyright (C) 2017 Michael McMaster <michael@codesrc.com>
+// Copyright (C) 2019 Michael McMaster <michael@codesrc.com>
//
-// This file is part of SCSI2SD.
+// This file is part of scsi2sd-util.
//
-// SCSI2SD is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
+// scsi2sd-util is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
//
-// SCSI2SD is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
+// scsi2sd-util is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
//
-// You should have received a copy of the GNU General Public License
-// along with SCSI2SD. If not, see <http://www.gnu.org/licenses/>.
+// You should have received a copy of the GNU General Public License
+// along with scsi2sd-util. If not, see <https://www.gnu.org/licenses/>.
package com.codesrc.scsi2sd.presentation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.springframework.stereotype.Component;
import java.io.IOException;
/**
* Created by michael on 28/05/17.
*/
-@Component
public class Desktop {
- private static Logger LOGGER = LoggerFactory.getLogger(Desktop.class.getName());
+ private static Logger LOGGER = LoggerFactory.getLogger(Desktop.class);
public enum Environment {
- LINUX,
- MAC,
- WINDOWS,
+ Linux,
+ OSX,
+ Windows,
OTHER
}
public Desktop() {
String os = System.getProperty("os.name").toLowerCase();
if (os.indexOf("windows") != -1 || os.indexOf("nt") != -1) {
- environment = Environment.WINDOWS;
+ environment = Environment.Windows;
} else if (os.indexOf("mac") != -1) {
- environment = Environment.MAC;
+ environment = Environment.OSX;
} else if (os.indexOf("linux") != -1) {
- environment = Environment.LINUX;
+ environment = Environment.Linux;
} else {
environment = Environment.OTHER;
}
LOGGER.info("Launching " + url);
try {
switch (environment) {
- case MAC:
+ case OSX:
Runtime.getRuntime().exec(new String[]{"open", url});
break;
- case WINDOWS:
+ case Windows:
Runtime.getRuntime().exec(new String[]{"cmd", "/c", "start", url});
break;
- case LINUX:
+ case Linux:
case OTHER:
Runtime.getRuntime().exec(new String[]{"xdg-open", url});
break;
--- /dev/null
+// Copyright (C) 2019 Michael McMaster <michael@codesrc.com>
+//
+// This file is part of scsi2sd-util.
+//
+// scsi2sd-util is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// scsi2sd-util is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with scsi2sd-util. If not, see <https://www.gnu.org/licenses/>.
+
+package com.codesrc.scsi2sd.presentation;
+
+import com.codesrc.scsi2sd.ScreensConfiguration;
+import com.codesrc.scsi2sd.document.ActiveDocument;
+import com.codesrc.scsi2sd.document.DocumentObserver;
+import com.codesrc.scsi2sd.io.UsbDeviceConnectedEvent;
+import com.codesrc.scsi2sd.io.UsbDeviceManager;
+import com.codesrc.scsi2sd.model.*;
+import javafx.application.Platform;
+import javafx.collections.ObservableList;
+import javafx.fxml.FXML;
+import javafx.fxml.Initializable;
+import javafx.scene.control.*;
+import javafx.scene.layout.Background;
+import javafx.stage.StageStyle;
+
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Optional;
+import java.util.ResourceBundle;
+
+public class DiskConfigController implements Initializable, DocumentObserver {
+
+ private ScreensConfiguration screens;
+ private ActiveDocument activeDocument;
+ private UsbDeviceManager usbDeviceManager;
+
+ @FXML
+ private TableView diskTableView;
+
+ @FXML
+ private Button newBtn;
+
+ @FXML
+ private Button deleteBtn;
+
+ @FXML private Button setSdCardSizeBtn;
+
+ @FXML private TextField scsiId;
+
+ @FXML private CheckBox enabled;
+
+ @FXML
+ private TextField scsiSizeStr;
+
+ @FXML private ChoiceBox scsiSizeUnit;
+
+ @FXML
+ private TextField scsiBytesPerSector;
+
+ @FXML
+ private TextField sdStartingByte;
+
+ @FXML ComboBox scsiDeviceType;
+
+ @FXML private TextField vendor;
+ @FXML private TextField prodId;
+ @FXML private TextField revision;
+ @FXML private TextField serial;
+
+ @FXML private TextField deviceTypeModifier;
+ @FXML private TextField sectorsPerTrack;
+ @FXML private TextField headsPerCylinder;
+ @FXML private ComboBox quirksMode;
+
+ private DiskList diskList;
+
+ private DiskConfig selectedConfig;
+
+ private int maxSupportedDevices = 4;
+
+ // data bound to the table view.
+ public class DiskListItem
+ {
+ private DiskConfig config;
+
+ public DiskListItem(DiskConfig config) {
+ this.config = config;
+ }
+
+ public long getSdSector() {
+ return config.getSdSectorStart();
+ }
+
+ public DiskConfig getConfig() {
+ return this.config;
+ }
+
+ public DiskConfig.Type getDiskType() {
+ return this.config.getType();
+ }
+
+ public String getSize() {
+ return this.config.getSizeString(this.config.getBestUnit(), true);
+ }
+
+ public String getId() {
+ return this.config.getType() == DiskConfig.Type.DISK ? Integer.toString(this.config.getScsiId()) : "";
+ }
+
+ public DeviceTypeEnum getDeviceType() { return this.config.getType() == DiskConfig.Type.DISK ? this.config.getDeviceType() : null; }
+
+ public boolean isEnabled() {
+ return this.config.isActive();
+ }
+ }
+
+ public DiskConfigController(ScreensConfiguration screens, ActiveDocument document, UsbDeviceManager usbDeviceManager) {
+ this.screens = screens;
+ this.activeDocument = document;
+ this.usbDeviceManager = usbDeviceManager;
+ document.addObserver(this);
+ }
+
+ @Override
+ public void initialize(URL url, ResourceBundle resourceBundle) {
+ this.usbDeviceManager.getDeviceConnectedEvent().subscribe(e -> Platform.runLater(() -> this.handleUsbConnected(e)));
+
+ this.newBtn.setOnAction((e) -> this.addNew());
+ this.deleteBtn.setOnAction((e) -> this.delete());
+ this.setSdCardSizeBtn.setOnAction((e) -> this.setSdCardSize());
+
+ this.scsiId.setOnAction((e) -> this.setScsiId());
+ this.scsiId.setTooltip(new Tooltip("SCSI ID 0 to 7"));
+ this.scsiId.focusedProperty().addListener((obs, wasFocussed, isNowFocussed) -> {if (!isNowFocussed) this.setScsiId();});
+
+ this.enabled.setOnAction((e) -> this.setEnabled());
+
+ this.scsiSizeUnit.setOnAction((e) -> this.setSizeUnits());
+ this.scsiSizeStr.setOnAction((e) -> this.setSize());
+ this.scsiSizeStr.focusedProperty().addListener((obs, wasFocussed, isNowFocussed) -> {if (!isNowFocussed) this.setSize();});
+
+ this.scsiBytesPerSector.setOnAction((e) -> this.setBytesPerSector());
+ this.scsiBytesPerSector.setTooltip(new Tooltip("Normally 512 bytes for hard drives or 2048 bytes for CDROM devices"));
+ this.scsiBytesPerSector.focusedProperty().addListener((obs, wasFocussed, isNowFocussed) -> {if (!isNowFocussed) this.setBytesPerSector();});
+
+ this.scsiDeviceType.setOnAction((e) -> this.setDeviceType());
+
+ this.vendor.setOnAction((e) -> this.setVendor());
+ this.vendor.focusedProperty().addListener((obs, wasFocussed, isNowFocussed) -> {if (!isNowFocussed) this.setVendor();});
+
+ this.prodId.setOnAction((e) -> this.setProdId());
+ this.prodId.focusedProperty().addListener((obs, wasFocussed, isNowFocussed) -> {if (!isNowFocussed) this.setProdId();});
+
+ this.revision.setOnAction((e) -> this.setRevision());
+ this.revision.focusedProperty().addListener((obs, wasFocussed, isNowFocussed) -> {if (!isNowFocussed) this.setRevision();});
+
+ this.serial.setOnAction((e) -> this.setSerial());
+ this.serial.focusedProperty().addListener((obs, wasFocussed, isNowFocussed) -> {if (!isNowFocussed) this.setSerial();});
+
+ this.deviceTypeModifier.setOnAction((e) -> this.setDeviceTypeModifier());
+ this.deviceTypeModifier.setTooltip(new Tooltip("SCSI device type modifier field, usually 0."));
+ this.deviceTypeModifier.focusedProperty().addListener((obs, wasFocussed, isNowFocussed) -> {if (!isNowFocussed) this.setDeviceTypeModifier();});
+
+ this.sectorsPerTrack.setOnAction((e) -> this.setSectorsPerTrack());
+ this.sectorsPerTrack.setTooltip(new Tooltip("Modify emulated disk geometry"));
+ this.sectorsPerTrack.focusedProperty().addListener((obs, wasFocussed, isNowFocussed) -> {if (!isNowFocussed) this.setSectorsPerTrack();});
+
+ this.headsPerCylinder.setOnAction((e) -> this.setHeadsPerCylinder());
+ this.headsPerCylinder.setTooltip(new Tooltip("Modify emulated disk geometry"));
+ this.headsPerCylinder.focusedProperty().addListener((obs, wasFocussed, isNowFocussed) -> {if (!isNowFocussed) this.setHeadsPerCylinder();});
+
+ this.quirksMode.setOnAction((e) -> this.setQuirksMode());
+
+ this.newBtn.setDisable(true);
+ this.deleteBtn.setDisable(true);
+ this.setSdCardSizeBtn.setDisable(true);
+
+ this.scsiSizeUnit.getItems().addAll(DiskUnit.values());
+ this.scsiDeviceType.getItems().addAll(Arrays.stream(DeviceTypeEnum.values()).filter(dt -> dt != DeviceTypeEnum.S2S_CFG_SEQUENTIAL).toArray());
+
+ this.quirksMode.getItems().addAll(Quirks.values());
+
+ this.diskTableView.getSelectionModel().selectedItemProperty().addListener((obs, oldSel, newSel) -> {
+ this.selectRow(newSel);
+ });
+ }
+
+ private void handleUsbConnected(UsbDeviceConnectedEvent usbDeviceConnectedEvent) {
+ this.maxSupportedDevices = usbDeviceConnectedEvent.getUsbDevice().getMaxDisks();
+ }
+
+ public void documentLoaded(ActiveDocument document)
+ {
+ ConfigRoot root = document.getActiveDocument();
+ this.diskList = root.getDiskList();
+
+ ObservableList<DiskListItem> data = diskTableView.getItems();
+ data.clear();
+ for (var config : diskList.getDisks())
+ {
+ data.add(new DiskListItem(config));
+ }
+
+ // this.setSdCardSizeBtn.setDisable(false);
+ }
+
+ public void documentModified(ActiveDocument document, boolean isModified)
+ {
+
+ }
+
+ public void documentValid(ActiveDocument document, boolean isValid)
+ {
+
+ }
+
+ private void selectRow(Object item) {
+ if (item == null)
+ {
+ this.selectedConfig = null;
+ }
+ else
+ {
+ this.selectedConfig = ((DiskListItem) item).getConfig();
+
+ var numDevices = this.diskList.getDisks().stream().filter(c -> c.getType() == DiskConfig.Type.DISK).count();
+ this.newBtn.setDisable(this.selectedConfig.getType() != DiskConfig.Type.EMPTY || numDevices >= this.maxSupportedDevices);
+ this.deleteBtn.setDisable(this.selectedConfig.getType() != DiskConfig.Type.DISK);
+ this.scsiId.setDisable(this.selectedConfig.getType() != DiskConfig.Type.DISK);
+ this.enabled.setDisable(this.selectedConfig.getType() != DiskConfig.Type.DISK);
+ this.scsiSizeStr.setDisable(this.selectedConfig.getType() != DiskConfig.Type.DISK);
+ this.scsiBytesPerSector.setDisable(this.selectedConfig.getType() != DiskConfig.Type.DISK);
+ this.scsiDeviceType.setDisable(this.selectedConfig.getType() != DiskConfig.Type.DISK);
+ this.vendor.setDisable(this.selectedConfig.getType() != DiskConfig.Type.DISK);
+ this.prodId.setDisable(this.selectedConfig.getType() != DiskConfig.Type.DISK);
+ this.revision.setDisable(this.selectedConfig.getType() != DiskConfig.Type.DISK);
+ this.serial.setDisable(this.selectedConfig.getType() != DiskConfig.Type.DISK);
+ this.deviceTypeModifier.setDisable(this.selectedConfig.getType() != DiskConfig.Type.DISK);
+ this.sectorsPerTrack.setDisable(this.selectedConfig.getType() != DiskConfig.Type.DISK);
+ this.headsPerCylinder.setDisable(this.selectedConfig.getType() != DiskConfig.Type.DISK);
+ this.quirksMode.setDisable(this.selectedConfig.getType() != DiskConfig.Type.DISK);
+
+ this.scsiId.setText(this.selectedConfig.getType() == DiskConfig.Type.DISK ? Integer.toString(this.selectedConfig.getScsiId()) : "");
+ this.enabled.setSelected(this.selectedConfig.isActive());
+ var bestUnit = this.selectedConfig.getBestUnit();
+ this.scsiSizeUnit.setValue(bestUnit);
+ this.scsiSizeStr.setText(this.selectedConfig.getSizeString(bestUnit, false));
+ this.scsiBytesPerSector.setText(Integer.toString(this.selectedConfig.getBytesPerSector()));
+ this.sdStartingByte.setText(Long.toString(this.selectedConfig.getSdSectorStart() * DiskConfig.SD_SECTOR_SIZE));
+ this.scsiDeviceType.setValue(this.selectedConfig.getDeviceType());
+ this.deviceTypeModifier.setText(String.valueOf(this.selectedConfig.getDeviceTypeModifier()));
+ this.vendor.setText(this.selectedConfig.getVendor());
+ this.prodId.setText(this.selectedConfig.getProdId());
+ this.revision.setText(this.selectedConfig.getRevision());
+ this.serial.setText(this.selectedConfig.getSerial());
+ this.sectorsPerTrack.setText(String.valueOf(this.selectedConfig.getSectorsPerTrack()));
+ this.headsPerCylinder.setText(String.valueOf(this.selectedConfig.getHeadsPerCylinder()));
+ this.quirksMode.setValue(this.selectedConfig.getQuirksMode());
+
+ }
+ }
+
+ private void addNew()
+ {
+ if (this.selectedConfig != null && this.selectedConfig.getType() == DiskConfig.Type.EMPTY)
+ {
+ var newConfig = new DiskConfig(DiskConfig.Type.DISK, this.selectedConfig.getSdSectorStart(), this.selectedConfig.getSdSectors());
+ this.diskList.add(newConfig);
+ }
+
+ this.activeDocument.setModified(DiskConfigController.class.getName(), true);
+ this.refreshList();
+ }
+
+ private void delete()
+ {
+ if (this.selectedConfig != null && this.selectedConfig.getType() == DiskConfig.Type.DISK)
+ {
+ this.diskList.remove(this.selectedConfig);
+ }
+
+ this.activeDocument.setModified(DiskConfigController.class.getName(), true);
+ this.refreshList();
+ }
+
+ private void refreshList()
+ {
+ var oldSelectedConfig = this.selectedConfig;
+ ObservableList<DiskListItem> data = diskTableView.getItems();
+ data.clear(); // Will call the row selection handler and set this.selectedConfig to null
+
+ for (var config : diskList.getDisks())
+ {
+ var tableItem = new DiskListItem(config);
+ data.add(tableItem);
+
+ if (oldSelectedConfig == config) {
+ diskTableView.getSelectionModel().select(tableItem);
+ }
+ }
+ }
+
+ private void setScsiId()
+ {
+ if (this.selectedConfig != null && this.selectedConfig.getType() == DiskConfig.Type.DISK) {
+ int value;
+ try {
+ value = Integer.parseUnsignedInt(this.scsiId.getText());
+ if (value >= 0 && value <= 7) {
+ this.selectedConfig.setScsiId(value);
+ }
+ } catch (NumberFormatException e) {
+ }
+
+ this.activeDocument.setModified(DiskConfigController.class.getName(), true);
+ this.refreshList();
+ }
+ }
+
+ private void setEnabled()
+ {
+ if (this.selectedConfig != null && this.selectedConfig.getType() == DiskConfig.Type.DISK) {
+ this.selectedConfig.setActive(this.enabled.isSelected());
+ this.activeDocument.setModified(DiskConfigController.class.getName(), true);
+ this.refreshList();
+ }
+ }
+
+
+ private void setSizeUnits()
+ {
+ if (this.selectedConfig != null)
+ {
+ this.scsiSizeStr.setText(this.selectedConfig.getSizeString((DiskUnit)this.scsiSizeUnit.getValue(), false));
+ }
+ }
+
+ private void setSize()
+ {
+ if (this.selectedConfig != null && this.selectedConfig.getType() == DiskConfig.Type.DISK)
+ {
+ double value;
+ try
+ {
+ value = Double.parseDouble(this.scsiSizeStr.getText());
+ if (value <= 0)
+ {
+ this.setSizeUnits();
+ return;
+ }
+ }
+ catch (NumberFormatException e)
+ {
+ this.setSizeUnits();
+ return;
+ }
+
+ var units = (DiskUnit)this.scsiSizeUnit.getValue();
+ var bytes = 0l;
+ switch (units)
+ {
+ case SECTOR: bytes = (long)value * this.selectedConfig.getBytesPerSector(); break;
+ case MB: bytes = (long)(value * 1024 * 1024); break;
+ case GB: bytes = (long)(value * 1024 * 1024 * 1024); break;
+ }
+
+ this.diskList.remove(this.selectedConfig);
+ var origScsiSectors = this.selectedConfig.getScsiSectors();
+ this.selectedConfig.setScsiSectors(bytes / this.selectedConfig.getBytesPerSector());
+ if (!this.diskList.add(this.selectedConfig))
+ {
+ this.selectedConfig.setScsiSectors(origScsiSectors);
+ this.diskList.add(this.selectedConfig);
+ }
+
+ this.activeDocument.setModified(DiskConfigController.class.getName(), true);
+ this.refreshList();
+ }
+ }
+
+ private void setBytesPerSector()
+ {
+ if (this.selectedConfig != null && this.selectedConfig.getType() == DiskConfig.Type.DISK)
+ {
+ int value;
+ try
+ {
+ value = Integer.parseUnsignedInt(this.scsiBytesPerSector.getText());
+
+ if (value <= 0)
+ {
+ this.scsiBytesPerSector.setText(Integer.toString(this.selectedConfig.getBytesPerSector()));
+ return;
+ }
+ }
+ catch (NumberFormatException e)
+ {
+ this.scsiBytesPerSector.setText(Integer.toString(this.selectedConfig.getBytesPerSector()));
+ return;
+ }
+
+ this.diskList.remove(this.selectedConfig);
+
+ var origBytesPerSector = this.selectedConfig.getBytesPerSector();
+ var origScsiSectors = this.selectedConfig.getScsiSectors();
+ var bytes = origBytesPerSector * origScsiSectors;
+
+ this.selectedConfig.setScsiSectors(bytes / value);
+ this.selectedConfig.setBytesPerSector(value);
+
+ if (!this.diskList.add(this.selectedConfig))
+ {
+ this.selectedConfig.setScsiSectors(origScsiSectors);
+ this.selectedConfig.setBytesPerSector(origBytesPerSector);
+
+ this.diskList.add(this.selectedConfig);
+ }
+
+ this.activeDocument.setModified(DiskConfigController.class.getName(), true);
+ this.refreshList();
+ }
+ }
+
+ private void setDeviceType()
+ {
+ if (this.selectedConfig != null)
+ {
+ this.selectedConfig.setDeviceType((DeviceTypeEnum)this.scsiDeviceType.getValue());
+
+ this.activeDocument.setModified(DiskConfigController.class.getName(), true);
+ this.refreshList();
+ }
+ }
+
+ private void setVendor()
+ {
+ if (this.selectedConfig != null)
+ {
+ this.selectedConfig.setVendor(this.vendor.getText());
+ this.vendor.setText(this.selectedConfig.getVendor()); // Fix padding
+ this.activeDocument.setModified(DiskConfigController.class.getName(), true);
+ }
+ }
+
+ private void setProdId()
+ {
+ if (this.selectedConfig != null)
+ {
+ this.selectedConfig.setProdId(this.prodId.getText());
+ this.prodId.setText(this.selectedConfig.getProdId()); // Fix padding
+ this.activeDocument.setModified(DiskConfigController.class.getName(), true);
+ }
+ }
+
+ private void setRevision()
+ {
+ if (this.selectedConfig != null)
+ {
+ this.selectedConfig.setRevision(this.revision.getText());
+ this.revision.setText(this.selectedConfig.getRevision()); // Fix padding
+ this.activeDocument.setModified(DiskConfigController.class.getName(), true);
+ }
+ }
+
+ private void setSerial()
+ {
+ if (this.selectedConfig != null)
+ {
+ this.selectedConfig.setSerial(this.serial.getText());
+ this.serial.setText(this.selectedConfig.getSerial()); // Fix padding
+ this.activeDocument.setModified(DiskConfigController.class.getName(), true);
+ }
+ }
+
+ private void setSdCardSize() {
+ if (this.diskList != null) {
+ TextInputDialog dialog = new TextInputDialog(String.valueOf(this.diskList.getSdCardSizeGb()));
+ dialog.setTitle("SD Card Size");
+ dialog.setHeaderText(null);
+ dialog.setContentText("Set SD card Size (GB):");
+ dialog.initStyle(StageStyle.UTILITY); // remove icons
+
+ Optional<String> result = dialog.showAndWait();
+ if (result.isPresent()) {
+ double value;
+ try
+ {
+ value = Double.parseDouble(result.get());
+
+ if (value <= 0 || value > 1999)
+ {
+ return;
+ }
+ }
+ catch (NumberFormatException e)
+ {
+ return;
+ }
+
+ this.diskList.resetSizeGb(value);
+ this.activeDocument.setModified(DiskConfigController.class.getName(), true);
+ this.refreshList();
+ }
+ }
+ }
+
+ private void setDeviceTypeModifier()
+ {
+ if (this.selectedConfig != null)
+ {
+ var in = this.deviceTypeModifier.getText();
+ int intValue;
+
+ if (in == null || in.isEmpty())
+ {
+ intValue = 0;
+ }
+ else
+ {
+ var oldValue = this.selectedConfig.getDeviceTypeModifier();
+
+ try {
+ intValue = Integer.valueOf(in);
+ if (intValue < 0 || intValue > 255)
+ {
+ this.deviceTypeModifier.setText(String.valueOf(oldValue));
+ return;
+ }
+
+ } catch (NumberFormatException e) {
+ this.deviceTypeModifier.setText(String.valueOf(oldValue));
+ return;
+ }
+ }
+
+ this.selectedConfig.setDeviceTypeModifier(intValue);
+ this.deviceTypeModifier.setText(String.valueOf(intValue));
+ this.activeDocument.setModified(DiskConfigController.class.getName(), true);
+ }
+ }
+
+ private void setSectorsPerTrack()
+ {
+ if (this.selectedConfig != null)
+ {
+ var in = this.sectorsPerTrack.getText();
+ int intValue;
+
+ var oldValue = this.selectedConfig.getSectorsPerTrack();
+
+ try {
+ intValue = Integer.valueOf(in);
+ if (intValue < 1 || intValue > 65535)
+ {
+ this.sectorsPerTrack.setText(String.valueOf(oldValue));
+ return;
+ }
+
+ } catch (NumberFormatException e) {
+ this.sectorsPerTrack.setText(String.valueOf(oldValue));
+ return;
+ }
+
+ this.selectedConfig.setSectorsPerTrack(intValue);
+ this.sectorsPerTrack.setText(String.valueOf(intValue));
+ this.activeDocument.setModified(DiskConfigController.class.getName(), true);
+ }
+ }
+
+ private void setHeadsPerCylinder()
+ {
+ if (this.selectedConfig != null)
+ {
+ var in = this.headsPerCylinder.getText();
+ int intValue;
+
+ var oldValue = this.selectedConfig.getHeadsPerCylinder();
+
+ try {
+ intValue = Integer.valueOf(in);
+ if (intValue < 1 || intValue > 65535)
+ {
+ this.headsPerCylinder.setText(String.valueOf(oldValue));
+ return;
+ }
+
+ } catch (NumberFormatException e) {
+ this.headsPerCylinder.setText(String.valueOf(oldValue));
+ return;
+ }
+
+ this.selectedConfig.setHeadsPerCylinder(intValue);
+ this.headsPerCylinder.setText(String.valueOf(intValue));
+ this.activeDocument.setModified(DiskConfigController.class.getName(), true);
+ }
+ }
+
+
+ private void setQuirksMode()
+ {
+ if (this.selectedConfig != null)
+ {
+ this.selectedConfig.setQuirksMode((Quirks)this.quirksMode.getValue());
+ this.activeDocument.setModified(DiskConfigController.class.getName(), true);
+ }
+ }
+
+}
--- /dev/null
+// Copyright (C) 2019 Michael McMaster <michael@codesrc.com>
+//
+// This file is part of scsi2sd-util.
+//
+// scsi2sd-util is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// scsi2sd-util is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with scsi2sd-util. If not, see <https://www.gnu.org/licenses/>.
+
+package com.codesrc.scsi2sd.presentation;
+
+import javafx.fxml.Initializable;
+import javafx.scene.Scene;
+
+/**
+ * Created by michael on 27/05/17.
+ */
+public interface FXController extends Initializable {
+ void setWindow(FXWindow window);
+ void onSceneCreating(Scene scene);
+}
--- /dev/null
+// Copyright (C) 2019 Michael McMaster <michael@codesrc.com>
+//
+// This file is part of scsi2sd-util.
+//
+// scsi2sd-util is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// scsi2sd-util is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with scsi2sd-util. If not, see <https://www.gnu.org/licenses/>.
+
+package com.codesrc.scsi2sd.presentation;
+
+import com.codesrc.scsi2sd.App;
+import javafx.fxml.FXMLLoader;
+import javafx.scene.Parent;
+import javafx.scene.Scene;
+import javafx.scene.image.Image;
+import javafx.stage.Modality;
+import javafx.stage.Stage;
+import javafx.stage.StageStyle;
+import javafx.stage.Window;
+import javafx.util.Callback;
+
+import java.io.IOException;
+import java.net.URL;
+
+/**
+ * Created by michael on 27/05/17.
+ */
+public class FXWindow extends Stage {
+
+ public FXWindow(Callback<Class<?>,Object> controllerFactory, URL fxml, String title, Window owner, StageStyle style) {
+ super(style);
+ initOwner(owner);
+ initModality(Modality.WINDOW_MODAL);
+ getIcons().add(new Image(App.class.getResourceAsStream("/icons/icon-16.png")));
+ getIcons().add(new Image(App.class.getResourceAsStream("/icons/icon-32.png")));
+ getIcons().add(new Image(App.class.getResourceAsStream("/icons/icon-256.png")));
+ setTitle(title);
+
+
+ FXMLLoader loader = new FXMLLoader(fxml);
+ try {
+ loader.setControllerFactory(controllerFactory);
+ Parent root = loader.load();
+ Object controller = loader.getController();
+ if (controller instanceof FXController)
+ {
+ ((FXController)controller).setWindow(this);
+ }
+
+ Scene scene = new Scene(root);
+
+ if (controller instanceof FXController)
+ {
+ ((FXController)controller).onSceneCreating(scene);
+ }
+
+ setScene(scene);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
--- /dev/null
+// Copyright (C) 2019 Michael McMaster <michael@codesrc.com>
+//
+// This file is part of scsi2sd-util.
+//
+// scsi2sd-util is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// scsi2sd-util is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with scsi2sd-util. If not, see <https://www.gnu.org/licenses/>.
+
+package com.codesrc.scsi2sd.presentation;
+
+import javafx.application.Platform;
+import javafx.scene.control.TextArea;
+
+import java.time.format.DateTimeFormatter;
+import java.util.logging.Handler;
+import java.util.logging.LogRecord;
+
+public class LogHandler extends Handler {
+ private TextArea logTextArea;
+
+ public LogHandler(TextArea logTextArea) {
+ this.logTextArea = logTextArea;
+ }
+
+ @Override
+ public void publish(LogRecord logRecord) {
+ Platform.runLater(() -> {
+ logTextArea.appendText(DateTimeFormatter.ISO_INSTANT.format(logRecord.getInstant()) + " " + logRecord.getMessage() + "\n");
+ });
+ }
+
+ @Override
+ public void flush() {
+
+ }
+
+ @Override
+ public void close() throws SecurityException {
+
+ }
+}
--- /dev/null
+// Copyright (C) 2019 Michael McMaster <michael@codesrc.com>
+//
+// This file is part of scsi2sd-util.
+//
+// scsi2sd-util is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// scsi2sd-util is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with scsi2sd-util. If not, see <https://www.gnu.org/licenses/>.
+
+package com.codesrc.scsi2sd.presentation;
+
+import com.codesrc.scsi2sd.ScreensConfiguration;
+import com.codesrc.scsi2sd.document.ActiveDocument;
+import com.codesrc.scsi2sd.document.DocumentObserver;
+import com.codesrc.scsi2sd.io.UsbDevice;
+import com.codesrc.scsi2sd.io.UsbDeviceManager;
+import com.codesrc.scsi2sd.model.BoardConfig;
+import com.codesrc.scsi2sd.model.ConfigRoot;
+import com.codesrc.scsi2sd.model.DiskConfig;
+import com.codesrc.scsi2sd.model.DiskList;
+import javafx.application.Platform;
+import javafx.fxml.FXML;
+import javafx.scene.control.*;
+import javafx.scene.Scene;
+import javafx.scene.layout.AnchorPane;
+import javafx.stage.FileChooser;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+import java.io.File;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.*;
+import java.util.logging.Level;
+import java.util.prefs.Preferences;
+import java.util.stream.Collectors;
+
+
+/**
+ * Created by michael on 21/05/17.
+ */
+public class MainController implements FXController, DocumentObserver {
+ public static final String Title = "codesrc SCSI2SD";
+ private static Logger LOGGER = LoggerFactory.getLogger(MainController.class);
+ private final String RECENT = "recent_items";
+ private final int RECENT_MAX = 10;
+
+ private ScreensConfiguration screens;
+ private FXWindow window;
+ private ActiveDocument activeDocument;
+
+ private UsbDeviceManager usbDeviceManager;
+
+ private Preferences prefs;
+ private Deque<String> recent;
+
+ @FXML private Menu menuRecent;
+
+ @FXML private MenuItem menuAbout;
+ @FXML private MenuItem menuQuit;
+
+ @FXML private MenuItem menuOpenDevice;
+ @FXML private MenuItem menuSaveDevice;
+ @FXML private MenuItem menuOpenFile;
+ @FXML private MenuItem toolbarOpenFile;
+ @FXML private MenuItem menuSaveFile;
+ @FXML private MenuItem toolbarSaveFile;
+ @FXML private MenuItem menuRevert;
+ @FXML private Button buttonRevert;
+
+ @FXML private TabPane mainTabPane;
+
+ @FXML private AnchorPane debugLog;
+ @FXML private DebugLogController debugLogController;
+
+ public MainController(
+ ScreensConfiguration screens,
+ UsbDeviceManager usbDeviceManager,
+ ActiveDocument activeDocument) {
+ this.screens = screens;
+ this.usbDeviceManager = usbDeviceManager;
+ this.activeDocument = activeDocument;
+ this.activeDocument.addObserver(this);
+
+ this.recent = new ArrayDeque<>();
+ }
+
+ @Override
+ public void setWindow(FXWindow window) {
+ this.window = window;
+ this.window.setOnCloseRequest(e -> this.exit());
+ }
+
+ @Override
+ public void onSceneCreating(Scene scene)
+ {
+ URL stylesheet = MainController.class.getResource("/css/main.css");
+ scene.getStylesheets().add(stylesheet.toString());
+ }
+
+ @Override
+ public void initialize(URL url, ResourceBundle resourceBundle) {
+ menuQuit.setOnAction(h -> this.exit());
+ menuAbout.setOnAction(h -> screens.aboutWindow(window).showAndWait());
+ menuOpenDevice.setOnAction(h -> loadConfigFromDevice());
+ menuSaveDevice.setOnAction(h -> saveConfigToDevice());
+ menuOpenFile.setOnAction(h -> loadConfigFromFile());
+ toolbarOpenFile.setOnAction(h -> loadConfigFromFile());
+ menuSaveFile.setOnAction(h -> saveConfigToFile());
+ toolbarSaveFile.setOnAction(h -> saveConfigToFile());
+ menuRevert.setOnAction(h -> revert());
+ buttonRevert.setOnAction(h -> revert());
+
+ menuOpenDevice.setDisable(true);
+ menuSaveDevice.setDisable(true);
+
+ this.prefs = Preferences.userNodeForPackage(MainController.class);
+ this.populateRecentFromPrefs();
+
+ this.loadDefault();
+
+ this.usbDeviceManager.getDeviceConnectedEvent().subscribe(e -> Platform.runLater(() -> this.handleDeviceConnectedEvent(e.getUsbDevice())));
+ this.usbDeviceManager.getDeviceDisconnectedEvent().subscribe(e -> Platform.runLater(() -> this.handleDeviceDisconnectedEvent(e.getUsbDevice())));
+
+ List<UsbDevice> deviceList = usbDeviceManager.getDevices();
+ if (!deviceList.isEmpty()) {
+ handleDeviceConnectedEvent(deviceList.get(0));
+ }
+ }
+
+ private void exit()
+ {
+ usbDeviceManager.shutdown();
+ System.exit(0);
+ }
+
+ private void loadConfigFromDevice() {
+ List<UsbDevice> deviceList = this.usbDeviceManager.getDevices();
+ if (!deviceList.isEmpty())
+ {
+ this.loadConfigFromDevice(deviceList.get(0));
+ }
+ }
+
+ private void handleDeviceDisconnectedEvent(UsbDevice device)
+ {
+ this.menuOpenDevice.setDisable(true);
+ this.menuSaveDevice.setDisable(true);
+ }
+
+ private void handleDeviceConnectedEvent(UsbDevice device)
+ {
+ this.menuOpenDevice.setDisable(false);
+ this.loadConfigFromDevice(device);
+ this.menuSaveDevice.setDisable(false);
+ }
+
+ private void loadConfigFromDevice(UsbDevice device) {
+ BoardConfig boardConfig = new BoardConfig(device.readBoardConfig());
+ ConfigRoot root = new ConfigRoot();
+ root.setBoardConfig(boardConfig);
+
+ var lastSectorUsed = 0l;
+ var configs = new ArrayList<DiskConfig>();
+ for (var i = 0; i < device.getMaxDisks(); ++i) {
+ var disk = new DiskConfig(device.readDiskConfig(i));
+ if (!disk.isActive() && disk.getSdSectorStart() == 0 && disk.getScsiSectors() == 0)
+ {
+ continue; // dummy entry.
+ }
+
+ lastSectorUsed = Math.max(lastSectorUsed, disk.getSdSectorEnd());
+ configs.add(disk);
+ }
+
+ var sdCapacity = device.getSdCapacity();
+ var fallbackSize = Math.max(2l*1024*1024*1024/512, lastSectorUsed + DiskList.reservedSize);
+ var diskList = new DiskList(sdCapacity > 0 ? sdCapacity : fallbackSize);
+ configs.forEach(c -> diskList.add(c));
+
+ root.setDiskList(diskList);
+
+ activeDocument.loadDocument(root, null);
+ }
+
+ private void saveConfigToDevice()
+ {
+ var device = this.getDevice();
+ if (device == null)
+ {
+ return;
+ }
+
+ var root = this.activeDocument.getActiveDocument();
+ device.saveBoardConfig(root.getBoardConfig().asBytes());
+
+ var configs = root.getDiskList().getDisks().stream()
+ .filter(d -> d.getType() == DiskConfig.Type.DISK)
+ .collect(Collectors.toList());
+
+ for (var i = 0; i < device.getMaxDisks(); ++i)
+ {
+ if (i < configs.size())
+ {
+ device.saveDiskConfig(i, configs.get(i).asBytes());
+ }
+ else
+ {
+ // Save a 0 byte dummy
+ var dummy = new DiskConfig(DiskConfig.Type.DISK, 0, 0);
+ dummy.setActive(false);
+ device.saveDiskConfig(i, dummy.asBytes());
+ }
+ }
+ device.saveCommit();
+ this.window.setTitle(Title);
+ }
+
+ @Override
+ public void documentLoaded(ActiveDocument document)
+ {
+ if (this.window != null) {
+ this.window.setTitle(Title);
+ }
+ this.enableDisableSave();
+ }
+
+ @Override
+ public void documentModified(ActiveDocument document, boolean isModified)
+ {
+ this.window.setTitle("*" + Title);
+ this.enableDisableSave();
+ }
+
+ @Override
+ public void documentValid(ActiveDocument document, boolean isValid)
+ {
+ this.enableDisableSave();
+ }
+
+ private void enableDisableSave()
+ {
+ var device = this.getDevice();
+ this.menuSaveDevice.setDisable(!this.activeDocument.isValid() || device == null || !this.activeDocument.isModified());
+ }
+
+ private UsbDevice getDevice()
+ {
+ List<UsbDevice> deviceList = usbDeviceManager.getDevices();
+ if (deviceList.isEmpty())
+ {
+ return null;
+ }
+ return deviceList.get(0);
+ }
+
+ private void loadConfigFromFile() {
+ FileChooser fileChooser = new FileChooser();
+ fileChooser.setTitle("Open Config File");
+ fileChooser.getExtensionFilters().addAll(
+ new FileChooser.ExtensionFilter("XML", "*.xml"),
+ new FileChooser.ExtensionFilter("All Files", "*.*")
+ );
+
+ File theFile = fileChooser.showOpenDialog(this.window);
+ if (theFile == null) {
+ return; // User canceled.
+ }
+ this.loadConfigFromFile(theFile);
+ }
+
+ private void loadConfigFromFile(File theFile)
+ {
+ try {
+ var builder = DocumentBuilderFactory.newDefaultInstance().newDocumentBuilder();
+ var doc = builder.parse(theFile);
+ BoardConfig boardConfig;
+
+ if (doc.hasChildNodes()
+ && doc.getFirstChild().getNodeName() == "SCSI2SD")
+ {
+ var boardConfigNode = doc.getElementsByTagName("S2S_BoardCfg");
+ if (boardConfigNode != null && boardConfigNode.getLength() > 0)
+ {
+ // do stuff
+ boardConfig = new BoardConfig(boardConfigNode.item(0));
+ }
+ else
+ {
+ throw new IllegalArgumentException("Missing S2S_BoardCfg node");
+ }
+
+ ConfigRoot root = new ConfigRoot();
+ root.setBoardConfig(boardConfig);
+
+ int maxDisks = 7;
+ var sdCapacity = 0;
+ List<UsbDevice> deviceList = this.usbDeviceManager.getDevices();
+ if (!deviceList.isEmpty())
+ {
+ maxDisks = deviceList.get(0).getMaxDisks();
+ sdCapacity = deviceList.get(0).getSdCapacity();
+ }
+
+ var lastSectorUsed = 0l;
+ var configs = new ArrayList<DiskConfig>();
+ var diskNodeList = doc.getElementsByTagName("SCSITarget");
+ for (var i = 0; i < maxDisks && i < diskNodeList.getLength(); ++i) {
+ var disk = new DiskConfig(diskNodeList.item(i));
+ lastSectorUsed = Math.max(lastSectorUsed, disk.getSdSectorEnd());
+ configs.add(disk);
+ }
+
+ var fallbackSize = Math.max(2l*1024*1024*1024/512, lastSectorUsed + DiskList.reservedSize);
+ var diskList = new DiskList(sdCapacity > 0 ? sdCapacity : fallbackSize);
+ configs.forEach(c -> diskList.add(c));
+
+ root.setDiskList(diskList);
+
+ activeDocument.loadDocument(root, theFile.getCanonicalPath());
+ this.saveRecent(theFile.getCanonicalPath());
+ }
+ else {
+ throw new IllegalArgumentException("Missing SCSI2SD node");
+ }
+
+ } catch (Exception e) {
+ Alert alert = new Alert(Alert.AlertType.ERROR);
+ alert.setTitle("Load failed");
+ alert.setContentText(e.getLocalizedMessage());
+ alert.show();
+ }
+ }
+
+ private void saveConfigToFile()
+ {
+ var root = this.activeDocument.getActiveDocument();
+
+ var builder = new StringBuilder();
+ builder.append("<SCSI2SD>\n");
+ builder.append(root.getBoardConfig().toXML());
+
+ root.getDiskList().getDisks().stream()
+ .filter(c -> c.getType() == DiskConfig.Type.DISK)
+ .forEach(c -> builder.append(c.toXML()));
+
+ builder.append("</SCSI2SD>\n");
+
+
+ FileChooser fileChooser = new FileChooser();
+ fileChooser.setTitle("Save Config File");
+ fileChooser.getExtensionFilters().addAll(
+ new FileChooser.ExtensionFilter("XML", "*.xml"),
+ new FileChooser.ExtensionFilter("All Files", "*.*")
+ );
+
+ var filename = this.activeDocument.getOriginalDocumentName();
+ if (filename != null) {
+ Path path = Path.of(filename);
+ fileChooser.setInitialDirectory(path.getParent().toFile());
+ fileChooser.setInitialFileName(path.getFileName().toFile().toString());
+ }
+
+ File theFile = fileChooser.showSaveDialog(this.window);
+ if (theFile == null)
+ {
+ return; // User cancelled.
+ }
+
+ try {
+ var path = theFile.toPath();
+ if (fileChooser.getSelectedExtensionFilter().getExtensions().contains("*.xml") &&
+ !path.getFileName().toString().toLowerCase().endsWith(".xml"))
+ {
+ path = Path.of(path.toString() + ".xml");
+ }
+
+ Files.write(path, builder.toString().getBytes(StandardCharsets.US_ASCII));
+
+ this.window.setTitle(Title);
+ this.saveRecent(path.toString());
+
+ } catch (Exception e) {
+ Alert alert = new Alert(Alert.AlertType.ERROR);
+ alert.setTitle("Save failed");
+ alert.setContentText(e.getLocalizedMessage());
+ alert.show();
+ }
+ }
+
+ private void revert() {
+ var orig = this.activeDocument.getOriginalDocument();
+ if (orig != null) {
+ var revertedDocument = new ConfigRoot(orig);
+ this.activeDocument.loadDocument(revertedDocument, this.activeDocument.getOriginalDocumentName());
+ }
+ }
+
+ private void loadDefault()
+ {
+ var root = new ConfigRoot();
+ root.setBoardConfig(new BoardConfig());
+ root.setDiskList(new DiskList(2l*1024*1024*1024/512));
+ this.activeDocument.loadDocument(root, null);
+ }
+
+ private void populateRecentFromPrefs() {
+ this.recent.clear();
+ for (int i = 0; i < RECENT_MAX; ++i) {
+ var prop = prefs.get(RECENT + i, null);
+ if (prop != null) {
+ this.recent.addLast(prop);
+ }
+ }
+
+ this.setRecentMenuItems();
+ }
+
+ private void saveRecent(String newFile) {
+ this.recent.remove(newFile);
+ this.recent.addFirst(newFile);
+
+ while (recent.size() > RECENT_MAX) {
+ this.recent.removeLast();
+ }
+
+ var i = 0;
+ for (var file : this.recent) {
+ prefs.put(RECENT + i, file);
+ ++i;
+ }
+
+ this.setRecentMenuItems();
+ }
+
+ private void setRecentMenuItems() {
+ this.menuRecent.getItems().clear();
+ for (var file : this.recent) {
+ var menuItem = new MenuItem(file);
+ menuItem.setOnAction(h -> this.loadConfigFromFile(new File(file)));
+ this.menuRecent.getItems().add(menuItem);
+ }
+ }
+}
--- /dev/null
+// Copyright (C) 2019 Michael McMaster <michael@codesrc.com>
+//
+// This file is part of scsi2sd-util.
+//
+// scsi2sd-util is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// scsi2sd-util is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with scsi2sd-util. If not, see <https://www.gnu.org/licenses/>.
+
+package com.codesrc.scsi2sd.presentation;
+
+import com.codesrc.scsi2sd.ScreensConfiguration;
+import com.codesrc.scsi2sd.io.*;
+import javafx.application.Platform;
+import javafx.fxml.FXML;
+import javafx.scene.control.Label;
+import javafx.scene.Scene;
+import org.slf4j.LoggerFactory;
+
+import java.net.URL;
+import java.util.List;
+import java.util.ResourceBundle;
+
+public class StatusTabController implements FXController {
+ private static org.slf4j.Logger LOGGER = LoggerFactory.getLogger(StatusTabController.class);
+
+ private ScreensConfiguration screens;
+ private FXWindow window;
+
+ private UsbDeviceManager usbDeviceManager;
+
+ @FXML private Label status;
+ @FXML private Label hwVersion;
+ @FXML private Label fwVersion;
+ @FXML private Label sdCapacity;
+
+ public StatusTabController(ScreensConfiguration screens, UsbDeviceManager usbDeviceManager) {
+ this.screens = screens;
+ this.usbDeviceManager = usbDeviceManager;
+ }
+
+ @Override
+ public void setWindow(FXWindow window) {
+ this.window = window;
+ }
+
+ @Override
+ public void onSceneCreating(Scene scene)
+ {
+ }
+
+ @Override
+ public void initialize(URL url, ResourceBundle resourceBundle) {
+ status.setText("No device");
+
+ usbDeviceManager.getDeviceConnectedEvent().subscribe(e -> Platform.runLater(() -> this.handleUsbConnected(e)));
+ usbDeviceManager.getDeviceDisconnectedEvent().subscribe(e -> Platform.runLater(() -> this.handleUsbDisconnected(e)));
+ usbDeviceManager.getDeviceFailedEvent().subscribe(e -> Platform.runLater(() -> this.handleUsbFailedEvent(e)));
+
+ List<UsbDevice> deviceList = usbDeviceManager.getDevices();
+ if (!deviceList.isEmpty()) {
+ updateStatus(deviceList.get(0));
+ }
+ }
+
+ public void handleUsbConnected(UsbDeviceConnectedEvent usbDeviceConnectedEvent) {
+ updateStatus(usbDeviceConnectedEvent.getUsbDevice());
+ }
+
+ private void updateStatus(UsbDevice device) {
+
+ status.setText("Connected");
+
+ hwVersion.setText(device.getHardwareDescription());
+ fwVersion.setText(device.getFirmwareDescription());
+
+ StringBuilder sdSizeStr = new StringBuilder();
+ long sectors = device.getSdCapacity();
+ float gbSize = sectors * 512.0f / 1024 / 1024 / 1024;
+ sdSizeStr.append(String.format("%.1f", gbSize)).append("GiB")
+ .append(" (").append(sectors).append(" sectors)");
+ if (sectors < (2 * 1024 * 1024 *1024 / 512)) {
+ sdSizeStr.append(" ! Obsolete Card");
+ }
+ sdCapacity.setText(sdSizeStr.toString());
+ }
+
+ public void handleUsbDisconnected(UsbDeviceDisconnectedEvent usbDeviceDisconnectedEvent) {
+ status.setText("Disconnected");
+ }
+
+ private void handleUsbFailedEvent(UsbDeviceFailedEvent usbDeviceFailedEvent) {
+ status.setText("Failed: " + usbDeviceFailedEvent.getUsbDevicePath() + ". Error: " + usbDeviceFailedEvent.getMessage());
+ }
+}
--- /dev/null
+// Copyright (C) 2019 Michael McMaster <michael@codesrc.com>
+//
+// This file is part of scsi2sd-util.
+//
+// scsi2sd-util is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// scsi2sd-util is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with scsi2sd-util. If not, see <https://www.gnu.org/licenses/>.
+
+module com.codesrc.scsi2sd.ui {
+ exports com.codesrc.scsi2sd;
+
+ opens com.codesrc.scsi2sd.presentation to javafx.fxml, javafx.base;
+
+ requires java.logging;
+ requires org.controlsfx.controls;
+ requires javafx.controls;
+ requires joptsimple;
+ requires org.slf4j;
+ requires org.slf4j.jul;
+ requires java.xml;
+ requires java.prefs;
+
+ requires transitive com.codesrc.scsi2sd.io;
+ requires transitive javafx.base;
+ requires transitive javafx.fxml;
+ requires transitive javafx.graphics;
+}
--- /dev/null
+
+com.codesrc.scsi2sd.app.version = 1.0-BETA
+
+com.codesrc.scsi2sd.app.licence.type = GPLv3
+com.codesrc.scsi2sd.app.licence.url = https://www.gnu.org/licenses/gpl-3.0.html
--- /dev/null
+.root {
+ -fx-background-color: #FFFFFF;
+ }
\ No newline at end of file
--- /dev/null
+
+.root {
+ -fx-border-style: solid;
+ -fx-border-color: #AAAAAA;
+ -fx-border-width: 1;
+ }
\ No newline at end of file
<?import javafx.scene.layout.*?>
-<?import org.controlsfx.control.HyperlinkLabel?>
-
<AnchorPane prefHeight="400.0" prefWidth="600.0"
xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="com.codesrc.scsi2sd.presentation.AboutController">
<ImageView fitHeight="135.0" fitWidth="135.0" AnchorPane.leftAnchor="10.0" AnchorPane.topAnchor="10.0" pickOnBounds="true" preserveRatio="true" >
<image>
- <Image url="@/img/codesrc-square-135.png"/>
+ <Image url="jrt:/com.codesrc.scsi2sd.ui/icons/icon-256.png"/>
</image>
</ImageView>
</font>
</Label>
- <Label text="Copyright 2017 Michael McMaster <michael@codesrc.com>" />
+ <Label>Copyright 2019 Michael McMaster [michael@codesrc.com]</Label>
<Label text="Version: " fx:id="labelVersion"/>
- <HyperlinkLabel fx:id="licenceLink"><text>Licence: [GPLv3+]</text></HyperlinkLabel>
+ <Hyperlink fx:id="licenceLink"><text>Licence: GPLv3</text></Hyperlink>
</children>
</VBox>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+
+<?import javafx.geometry.*?>
+<?import javafx.scene.text.*?>
+<?import java.lang.*?>
+<?import javafx.scene.control.*?>
+<?import javafx.scene.layout.*?>
+
+<?import org.controlsfx.control.ToggleSwitch?>
+<ScrollPane
+ fitToWidth="true"
+ hbarPolicy="AS_NEEDED"
+ vbarPolicy="AS_NEEDED"
+ xmlns="http://javafx.com/javafx/8"
+ xmlns:fx="http://javafx.com/fxml/1"
+ fx:controller="com.codesrc.scsi2sd.presentation.ConfigController">
+
+ <content>
+ <VBox>
+ <children>
+ <GridPane hgap="15.0" vgap="5.0" VBox.vgrow="ALWAYS">
+ <columnConstraints>
+ <ColumnConstraints halignment="RIGHT" hgrow="SOMETIMES" maxWidth="380.0" minWidth="10.0" prefWidth="162.0" />
+ <ColumnConstraints hgrow="SOMETIMES" maxWidth="450.0" minWidth="200.0" prefWidth="329.0" />
+ <ColumnConstraints hgrow="SOMETIMES" maxWidth="315.0" minWidth="0.0" prefWidth="215.0" />
+ </columnConstraints>
+ <rowConstraints>
+ <RowConstraints maxHeight="60.0" minHeight="15.0" prefHeight="30.0" vgrow="SOMETIMES" />
+ <RowConstraints maxHeight="60.0" minHeight="15.0" prefHeight="30.0" vgrow="SOMETIMES" />
+ <RowConstraints maxHeight="60.0" minHeight="15.0" prefHeight="30.0" vgrow="SOMETIMES" />
+ <RowConstraints maxHeight="60.0" minHeight="15.0" prefHeight="30.0" vgrow="SOMETIMES" />
+ <RowConstraints maxHeight="60.0" minHeight="15.0" prefHeight="30.0" vgrow="SOMETIMES" />
+ <RowConstraints maxHeight="60.0" minHeight="15.0" prefHeight="30.0" vgrow="SOMETIMES" />
+ <RowConstraints maxHeight="60.0" minHeight="15.0" prefHeight="30.0" vgrow="SOMETIMES" />
+ <RowConstraints maxHeight="60.0" minHeight="15.0" prefHeight="30.0" vgrow="SOMETIMES" />
+ <RowConstraints maxHeight="60.0" minHeight="15.0" prefHeight="30.0" vgrow="SOMETIMES" />
+ <RowConstraints maxHeight="60.0" minHeight="15.0" prefHeight="30.0" vgrow="SOMETIMES" />
+ <RowConstraints maxHeight="60.0" minHeight="15.0" prefHeight="30.0" vgrow="SOMETIMES" />
+ </rowConstraints>
+ <children>
+ <Label text="Enable Active Terminator" GridPane.columnIndex="1" GridPane.rowIndex="1" />
+ <CheckBox fx:id="cfgEnableTerminator" mnemonicParsing="false" GridPane.rowIndex="1" />
+ <Label text="SCSI Speed Limit" GridPane.columnIndex="1" GridPane.rowIndex="3" />
+ <ChoiceBox fx:id="speedLimit" prefWidth="150.0" GridPane.rowIndex="3" />
+ <Label text="Startup Delay. 0 to 255 seconds." wrapText="true" GridPane.columnIndex="1" GridPane.rowIndex="4" />
+ <TextField fx:id="cfgStartupDelay" alignment="CENTER_RIGHT" maxWidth="150.0" promptText="0" GridPane.rowIndex="4" />
+
+ <Label text="Selection Delay. 0 to 255 milliseconds." GridPane.columnIndex="1" GridPane.rowIndex="5" />
+ <TextField fx:id="cfgSelectionDelay" alignment="CENTER_RIGHT" maxWidth="150.0" promptText="auto" GridPane.rowIndex="5">
+ </TextField>
+
+ <Label text="Check parity" GridPane.columnIndex="1" GridPane.rowIndex="6" />
+ <ToggleSwitch fx:id="cfgCheckParity" mnemonicParsing="false" GridPane.rowIndex="6" />
+
+ <Label text="Unit Attention" GridPane.columnIndex="1" GridPane.rowIndex="7" />
+ <ToggleSwitch fx:id="cfgUnitAtt" mnemonicParsing="false" GridPane.rowIndex="7" />
+
+ <Label text="SCSI2 Mode" GridPane.columnIndex="1" GridPane.rowIndex="2" />
+ <ToggleSwitch fx:id="cfgScsi2" mnemonicParsing="false" GridPane.rowIndex="2" />
+
+ <Label text="Respond to short selection pulses" GridPane.columnIndex="1" GridPane.rowIndex="10" />
+ <ToggleSwitch fx:id="cfgSelPulses" mnemonicParsing="false" GridPane.rowIndex="10" />
+
+ <Label text="Map LUNS to IDs" GridPane.columnIndex="1" GridPane.rowIndex="11" />
+ <ToggleSwitch fx:id="cfgMapLuns" mnemonicParsing="false" GridPane.rowIndex="11" />
+
+ <Label text="Default" GridPane.columnIndex="2">
+ <font>
+ <Font name="System Bold" size="13.0" />
+ </font>
+ </Label>
+ <Label text="Enabled" GridPane.columnIndex="2" GridPane.rowIndex="1" />
+ <Label text="No Limit" GridPane.columnIndex="2" GridPane.rowIndex="3" />
+ <Label text="0" GridPane.columnIndex="2" GridPane.rowIndex="4" />
+ <Label text="Auto (blank)" GridPane.columnIndex="2" GridPane.rowIndex="5" />
+ <Label text="Enabled" GridPane.columnIndex="2" GridPane.rowIndex="6" />
+ <Label text="Disabled" GridPane.columnIndex="2" GridPane.rowIndex="7" />
+ <Label text="Disabled" GridPane.columnIndex="2" GridPane.rowIndex="2" />
+ <Label text="Disabled" GridPane.columnIndex="2" GridPane.rowIndex="10" />
+ <Label text="Disabled" GridPane.columnIndex="2" GridPane.rowIndex="11" />
+ <Label text="Advanced" GridPane.columnIndex="1" GridPane.rowIndex="9">
+ <font>
+ <Font name="System Bold" size="13.0" />
+ </font>
+ </Label>
+ </children>
+ </GridPane>
+ </children>
+ </VBox>
+ </content>
+</ScrollPane>
\ No newline at end of file
<?import javafx.scene.paint.*?>
<?import javafx.scene.text.*?>
-<AnchorPane VBox.vgrow="ALWAYS">
+<AnchorPane VBox.vgrow="ALWAYS"
+ xmlns="http://javafx.com/javafx/8"
+ xmlns:fx="http://javafx.com/fxml/1"
+ fx:controller="com.codesrc.scsi2sd.presentation.DebugLogController">
<children>
- <TextArea AnchorPane.leftAnchor="15" AnchorPane.rightAnchor="15" AnchorPane.topAnchor="15" AnchorPane.bottomAnchor="50" editable="false" />
+ <TextArea fx:id="logTextArea" AnchorPane.leftAnchor="15" AnchorPane.rightAnchor="15" AnchorPane.topAnchor="15" AnchorPane.bottomAnchor="50" editable="false" />
<FlowPane AnchorPane.leftAnchor="15" AnchorPane.bottomAnchor="10" hgap="10">
<Button mnemonicParsing="false" text="Save Log As ..." />
<Button mnemonicParsing="false" text="Clear Log" />
--- /dev/null
+<?import javafx.scene.layout.AnchorPane?>
+<?import javafx.scene.control.Button?>
+<?import javafx.scene.control.TableView?>
+<?import javafx.scene.control.TableColumn?>
+
+<?import javafx.scene.layout.VBox?>
+<?import javafx.scene.control.Accordion?>
+<?import javafx.scene.control.TitledPane?>
+<?import javafx.scene.layout.GridPane?>
+<?import javafx.scene.layout.ColumnConstraints?>
+<?import javafx.scene.layout.RowConstraints?>
+<?import javafx.scene.control.Label?>
+<?import javafx.scene.control.TextField?>
+<?import javafx.scene.control.ComboBox?>
+<?import javafx.scene.control.ChoiceBox?>
+<?import javafx.scene.control.ScrollPane?>
+
+
+<?import javafx.scene.control.cell.PropertyValueFactory?>
+<?import javafx.scene.control.CheckBox?>
+<ScrollPane
+ fitToWidth="true"
+ hbarPolicy="AS_NEEDED"
+ vbarPolicy="AS_NEEDED"
+ xmlns="http://javafx.com/javafx/8"
+ xmlns:fx="http://javafx.com/fxml/1"
+ fx:controller="com.codesrc.scsi2sd.presentation.DiskConfigController">
+ <content>
+
+ <VBox>
+ <children>
+ <AnchorPane xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" minHeight="350" prefHeight="350.0" maxHeight="350">
+ <children>
+ <Button fx:id="newBtn" AnchorPane.bottomAnchor="10.0" AnchorPane.leftAnchor="14.0" mnemonicParsing="false" prefWidth="100.0" text="New" />
+ <Button fx:id="deleteBtn" AnchorPane.bottomAnchor="10.0" AnchorPane.leftAnchor="164.0" mnemonicParsing="false" prefWidth="100.0" text="Delete" />
+ <Button fx:id="setSdCardSizeBtn" AnchorPane.bottomAnchor="10.0" AnchorPane.leftAnchor="314.0" mnemonicParsing="false" prefWidth="150.0" text="SD card Size ..." />
+
+ <TableView fx:id="diskTableView"
+ AnchorPane.bottomAnchor="50.0" AnchorPane.leftAnchor="15.0" AnchorPane.rightAnchor="15.0" AnchorPane.topAnchor="10.0"
+ >
+ <columnResizePolicy>
+ <TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
+ </columnResizePolicy>
+ <columns>
+ <TableColumn editable="false" minWidth="50" prefWidth="100.0" text="SD Sector">
+ <cellValueFactory><PropertyValueFactory property="sdSector" /></cellValueFactory>
+ </TableColumn>
+ <TableColumn editable="false" minWidth="75" prefWidth="178.0" text="Type">
+ <cellValueFactory><PropertyValueFactory property="diskType" /></cellValueFactory>
+ </TableColumn>
+ <TableColumn editable="false" minWidth="75" prefWidth="178.0" text="Size">
+ <cellValueFactory><PropertyValueFactory property="size" /></cellValueFactory>
+ </TableColumn>
+ <TableColumn editable="false" minWidth="50" prefWidth="100.0" text="SCSI ID">
+ <cellValueFactory><PropertyValueFactory property="id" /></cellValueFactory>
+ </TableColumn>
+ <TableColumn editable="false" minWidth="50" prefWidth="100.0" text="Device Type">
+ <cellValueFactory><PropertyValueFactory property="deviceType" /></cellValueFactory>
+ </TableColumn>
+ <TableColumn minWidth="50" prefWidth="100.0" text="Enabled">
+ <cellValueFactory><PropertyValueFactory property="enabled" /></cellValueFactory>
+ </TableColumn>
+ </columns>
+ </TableView>
+ </children>
+ </AnchorPane>
+
+ <Accordion>
+ <panes>
+ <TitledPane animated="false" text="Basic">
+ <content>
+ <AnchorPane>
+ <children>
+ <GridPane layoutX="14.0" layoutY="14.0" prefHeight="105.0" prefWidth="500.0">
+ <columnConstraints>
+ <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
+ <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
+ </columnConstraints>
+ <rowConstraints>
+ <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
+ <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
+ <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
+ </rowConstraints>
+ <children>
+ <Label text="SCSI ID" />
+ <TextField fx:id="scsiId" promptText="0" GridPane.columnIndex="1" />
+
+ <Label text="Type" GridPane.rowIndex="1" />
+ <ComboBox fx:id="scsiDeviceType" prefHeight="25.0" prefWidth="270.0" GridPane.columnIndex="1" GridPane.rowIndex="1" />
+
+ <Label text="Enabled" GridPane.rowIndex="2" />
+ <CheckBox fx:id="enabled" prefHeight="25.0" prefWidth="270.0" GridPane.columnIndex="1" GridPane.rowIndex="2" />
+
+ </children>
+ </GridPane>
+ </children>
+ </AnchorPane>
+ </content>
+ </TitledPane>
+ <TitledPane animated="false" text="Size">
+ <content>
+ <AnchorPane>
+ <children>
+ <Label layoutX="14.0" layoutY="14.0" text="Size" />
+ <TextField fx:id="scsiSizeStr" alignment="CENTER_RIGHT" layoutX="142.0" layoutY="8.0" prefHeight="25.0" prefWidth="200.0" />
+ <ChoiceBox fx:id="scsiSizeUnit" layoutX="375.0" layoutY="8.0" prefWidth="150.0" />
+
+ <Label layoutX="12.0" layoutY="44.0" text="SCSI Sector Size" />
+ <TextField fx:id="scsiBytesPerSector" alignment="CENTER_RIGHT" layoutX="142.0" layoutY="38.0" prefHeight="25.0" prefWidth="200.0" promptText="512 bytes" />
+
+ <Label layoutX="14.0" layoutY="74.0" text="SD Starting Byte" />
+ <TextField fx:id="sdStartingByte" disable="true" alignment="CENTER_RIGHT" layoutX="142.0" layoutY="68.0" prefHeight="25.0" prefWidth="200.0" />
+
+ </children>
+ </AnchorPane>
+ </content>
+ </TitledPane>
+ <TitledPane animated="false" text="Identification">
+ <content>
+ <AnchorPane>
+ <children>
+ <GridPane layoutX="14.0" layoutY="14.0" prefHeight="136.0" prefWidth="524.0">
+ <columnConstraints>
+ <ColumnConstraints hgrow="SOMETIMES" maxWidth="255.0" minWidth="10.0" prefWidth="151.0" />
+ <ColumnConstraints hgrow="SOMETIMES" maxWidth="373.0" minWidth="10.0" prefWidth="373.0" />
+ </columnConstraints>
+ <rowConstraints>
+ <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
+ <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
+ <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
+ <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
+ </rowConstraints>
+ <children>
+ <Label text="Vendor" />
+ <Label text="Product ID" GridPane.rowIndex="1" />
+ <Label text="Revision" GridPane.rowIndex="2" />
+ <Label text="Serial Number" GridPane.rowIndex="3" />
+ <TextField fx:id="vendor" GridPane.columnIndex="1" />
+ <TextField fx:id="prodId" GridPane.columnIndex="1" GridPane.rowIndex="1" />
+ <TextField fx:id="revision" GridPane.columnIndex="1" GridPane.rowIndex="2" />
+ <TextField fx:id="serial" GridPane.columnIndex="1" GridPane.rowIndex="3" />
+ </children>
+ </GridPane>
+ </children>
+ </AnchorPane>
+ </content>
+ </TitledPane>
+
+ <TitledPane animated="false" text="Advanced">
+ <content>
+ <AnchorPane>
+ <children>
+ <GridPane layoutX="14.0" layoutY="14.0" prefHeight="105.0" prefWidth="500.0">
+ <columnConstraints>
+ <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
+ <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
+ </columnConstraints>
+ <rowConstraints>
+ <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
+ <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
+ <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
+ <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
+ </rowConstraints>
+ <children>
+ <Label text="Device Type Modifier" />
+ <TextField fx:id="deviceTypeModifier" promptText="0" GridPane.columnIndex="1" />
+
+ <Label text="Sectors per Track" GridPane.rowIndex="1" />
+ <TextField fx:id="sectorsPerTrack" GridPane.rowIndex="1" GridPane.columnIndex="1" />
+
+ <Label text="Heads per Cylinder" GridPane.rowIndex="2" />
+ <TextField fx:id="headsPerCylinder" GridPane.rowIndex="2" GridPane.columnIndex="1" />
+
+ <Label text="Quirks mode" GridPane.rowIndex="3" />
+ <ComboBox fx:id="quirksMode" GridPane.rowIndex="3" GridPane.columnIndex="1" />
+ </children>
+ </GridPane>
+ </children>
+ </AnchorPane>
+ </content>
+ </TitledPane>
+ </panes>
+ </Accordion>
+ </children>
+ </VBox>
+ </content>
+</ScrollPane>
<?xml version="1.0" encoding="UTF-8"?>
-<?import javafx.geometry.*?>
-<?import java.lang.*?>
-<?import java.util.*?>
+
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
-<?import javafx.scene.paint.*?>
-<?import javafx.scene.text.*?>
-
<?import org.controlsfx.glyphfont.Glyph?>
-
-
-<VBox xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.codesrc.scsi2sd.presentation.MainController">
-
+<?import java.net.URL?>
+<VBox
+ xmlns="http://javafx.com/javafx/8"
+ xmlns:fx="http://javafx.com/fxml/1"
+ fx:controller="com.codesrc.scsi2sd.presentation.MainController"
+ fx:id="mainVbox">
<children>
<MenuBar VBox.vgrow="NEVER">
<menus>
<Menu mnemonicParsing="false" text="File">
<items>
- <MenuItem mnemonicParsing="false" text="Open…">
+ <MenuItem fx:id="menuOpenFile" mnemonicParsing="false" text="Open…">
<graphic>
<Glyph fontFamily="FontAwesome" icon="FOLDER_OPEN"/>
</graphic>
</MenuItem>
- <Menu mnemonicParsing="false" text="Open Recent" />
+ <Menu fx:id="menuRecent" mnemonicParsing="false" text="Open Recent" />
<SeparatorMenuItem mnemonicParsing="false" />
- <MenuItem mnemonicParsing="false" text="Close" />
- <MenuItem mnemonicParsing="false" text="Save" />
- <MenuItem mnemonicParsing="false" text="Save As…" />
- <MenuItem mnemonicParsing="false" text="Revert" />
+ <MenuItem fx:id="menuSaveFile" mnemonicParsing="false" text="Save As…" />
+ <MenuItem fx:id="menuRevert" mnemonicParsing="false" text="Revert" />
<SeparatorMenuItem mnemonicParsing="false" />
<MenuItem fx:id="menuQuit" mnemonicParsing="false" text="Quit" />
</items>
<Glyph fontFamily="FontAwesome" icon="SAVE"/>
</graphic>
<items>
- <MenuItem mnemonicParsing="false" text="Save to device" />
- <MenuItem mnemonicParsing="false" text="Save to SD card" />
- <MenuItem mnemonicParsing="false" text="Save to file ..." />
+ <MenuItem fx:id="menuSaveDevice" mnemonicParsing="false" text="Save to device" />
+ <!--<MenuItem mnemonicParsing="false" text="Save to SD card" />-->
+ <MenuItem fx:id="toolbarSaveFile" mnemonicParsing="false" text="Save to file ..." />
</items>
</MenuButton>
<MenuButton mnemonicParsing="false" text="Open">
<Glyph fontFamily="FontAwesome" icon="FOLDER_OPEN"/>
</graphic>
<items>
- <MenuItem mnemonicParsing="false" text="Open device" />
- <MenuItem mnemonicParsing="false" text="Open SD card" />
- <MenuItem mnemonicParsing="false" text="Open file ..." />
+ <MenuItem fx:id="menuOpenDevice" mnemonicParsing="false" text="Open device" />
+ <!--<MenuItem mnemonicParsing="false" text="Open SD card" />-->
+ <MenuItem fx:id="toolbarOpenFile" mnemonicParsing="false" text="Open file ..." />
</items>
</MenuButton>
- <Button mnemonicParsing="false" text="Revert" />
+ <Button fx:id="buttonRevert" mnemonicParsing="false" text="Revert" />
<Separator></Separator>
<Button>Update Firmware...</Button>
</items>
</Tab>
<Tab closable="false" text="Log">
<content>
- <fx:include source="debugLog.fxml"/>
+ <fx:include fx:id="debugLog" source="debugLog.fxml"/>
</content>
</Tab>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
-<AnchorPane>
+<AnchorPane
+ xmlns="http://javafx.com/javafx/8"
+ xmlns:fx="http://javafx.com/fxml/1"
+ fx:controller="com.codesrc.scsi2sd.presentation.StatusTabController">
<children>
<GridPane AnchorPane.topAnchor="15" AnchorPane.leftAnchor="15" AnchorPane.rightAnchor="15">
<columnConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
- <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Label text="Status" />
<Label alignment="TOP_LEFT" text="Hardware Version" GridPane.rowIndex="1" />
<Label text="Firmware Version" GridPane.rowIndex="2" />
<Label text="SD Capacity" GridPane.rowIndex="3" />
- <Label text="Label" GridPane.columnIndex="1" GridPane.rowIndex="2" />
- <Label text="Label" GridPane.columnIndex="1" GridPane.rowIndex="1" />
- <Label text="Label" GridPane.columnIndex="1" />
- <Label text="Label" GridPane.columnIndex="1" GridPane.rowIndex="3" />
- <Label text="SCSI Disks" GridPane.rowIndex="4" />
- <Label text="Label" GridPane.columnIndex="1" GridPane.rowIndex="4" />
+
+ <Label text="-" fx:id="status" GridPane.columnIndex="1" />
+
+
+ <Label text="-" fx:id="fwVersion" GridPane.columnIndex="1" GridPane.rowIndex="2" />
+ <Label text="-" fx:id="hwVersion" GridPane.columnIndex="1" GridPane.rowIndex="1" />
+
+ <Label text="-" fx:id="sdCapacity" GridPane.columnIndex="1" GridPane.rowIndex="3" />
</children>
</GridPane>
</children>
--- /dev/null
+<!--?xml version="1.0" encoding="UTF-8" standalone="no"?-->
+<svg viewBox="0 0 17 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="si-glyph si-glyph-floppy-disk">
+ <!-- Generator: Sketch 3.0.3 (7891) - http://www.bohemiancoding.com/sketch -->
+ <title>832</title>
+
+ <defs></defs>
+ <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+ <g transform="translate(0.968151, 0.000000)" fill="#434343">
+ <path d="M11.993,0.031 L4.035,0.031 L4.035,5.983 L11.993,5.983 L11.993,0.031 L11.993,0.031 Z M11.0318493,5 L9.03184926,5 L9.03184926,1 L11.0318493,1 L11.0318493,5 L11.0318493,5 Z" class="si-glyph-fill"></path>
+ <path d="M14.0196178,0.031 L13.1109039,0.031 L13.1109039,7.10112134 L2.97331513,7.10112134 L2.97331513,0.031 L2.02037174,0.031 C0.91564095,0.031 0.0209999999,0.950085607 0.0209999999,2.08335637 L0.0209999999,12.9776381 C0.0209999999,14.1109088 0.916646164,15.031 2.02037174,15.031 L14.020623,15.031 C15.1263591,15.031 16.021,14.1109088 16.021,12.9776381 L16.021,2.08335637 L14.0196178,0.031 L14.0196178,0.031 Z M12,13 L4,13 L4,12 L12,12 L12,13 L12,13 Z M12,11 L4,11 L4,10 L12,10 L12,11 L12,11 Z" class="si-glyph-fill"></path>
+ </g>
+ </g>
+</svg>
\ No newline at end of file
--- /dev/null
+<!--?xml version="1.0" encoding="UTF-8" standalone="no"?-->
+<svg viewBox="0 0 17 17" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="si-glyph si-glyph-folder-open">
+ <!-- Generator: Sketch 3.0.3 (7891) - http://www.bohemiancoding.com/sketch -->
+ <title>82</title>
+
+ <defs></defs>
+ <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+ <path d="M8.03,4.042 L7.228,3.042 L1.015,3.042 L1.015,4.042 L0.00899999996,4.042 L0.00899999996,13 L1.026,13 L1.031,13.984 L14.65,13.963 L15.953,4.041 L8.03,4.041 L8.03,4.042 Z M13.82,13.041 L1.711,13.041 L3.1,4.953 L15.032,4.953 L13.82,13.041 L13.82,13.041 Z" fill="#434343" class="si-glyph-fill"></path>
+ </g>
+</svg>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="256"
+ height="256"
+ viewBox="0 0 67.733333 67.733335"
+ version="1.1"
+ id="svg5138"
+ sodipodi:docname="icon.svg"
+ inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
+ inkscape:export-filename="/home/michael/projects/scsi2sd-util/scsi2sd.ui/src/main/resources/icons/icon-16.png"
+ inkscape:export-xdpi="6"
+ inkscape:export-ydpi="6">
+ <defs
+ id="defs5132" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="2"
+ inkscape:cx="16.463924"
+ inkscape:cy="191.71962"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ units="px"
+ inkscape:pagecheckerboard="true"
+ inkscape:window-width="2560"
+ inkscape:window-height="1376"
+ inkscape:window-x="0"
+ inkscape:window-y="27"
+ inkscape:window-maximized="1" />
+ <metadata
+ id="metadata5135">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(0,-229.26666)">
+ <path
+ style="fill:#4d4d4d;fill-rule:evenodd;stroke:#000000;stroke-width:0.26458335px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 10,230 h 40 l 10,10 v 10 h -3 v 5 h 3 v 42 H 45 v -2 H 25 v 2 H 8 v -37 h 2 V 245 H 7 v -15 z"
+ id="path6066"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccccccc" />
+ <path
+ style="fill:#999999;fill-rule:evenodd;stroke:#000000;stroke-width:0.26458335px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 7,245 h 3 v 7 H 7 Z"
+ id="path6068"
+ inkscape:connector-curvature="0" />
+ <rect
+ style="fill:#4d4d4d;fill-opacity:1;stroke:#fffffd;stroke-width:0.26458335;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
+ id="rect6070"
+ width="44"
+ height="55"
+ x="12"
+ y="237" />
+ <rect
+ style="fill:#4c4c8e;fill-opacity:1;stroke:#fffffd;stroke-width:0.26458335;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
+ id="rect6105"
+ width="40"
+ height="23.479628"
+ x="14"
+ y="267" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:3.17500019px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458335px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="15.5"
+ y="280"
+ id="text6074"><tspan
+ sodipodi:role="line"
+ id="tspan6072"
+ x="15.5"
+ y="280.21353"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46666718px;font-family:Sans;-inkscape-font-specification:'Sans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke-width:0.26458335px">SCSI2SD</tspan></text>
+ </g>
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="600"
+ height="300"
+ viewBox="0 0 158.75 79.375002"
+ version="1.1"
+ id="svg8"
+ inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
+ sodipodi:docname="splash.svg"
+ inkscape:export-filename="/home/michael/projects/scsi2sd-util/scsi2sd.ui/src/main/resources/img/splash.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <defs
+ id="defs2" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#646464"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="1.4"
+ inkscape:cx="224.74084"
+ inkscape:cy="234.28571"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ units="px"
+ inkscape:pagecheckerboard="false"
+ inkscape:window-width="2560"
+ inkscape:window-height="1376"
+ inkscape:window-x="0"
+ inkscape:window-y="27"
+ inkscape:window-maximized="1" />
+ <metadata
+ id="metadata5">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(0,-217.62498)">
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:3.17499995px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#c8c8c8;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="5.2941761"
+ y="234.63391"
+ id="text1368"><tspan
+ sodipodi:role="line"
+ x="5.2941761"
+ y="234.63391"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.28888893px;font-family:Sans;-inkscape-font-specification:'Sans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#c8c8c8;fill-opacity:1;stroke-width:0.26458332px"
+ id="tspan1374">SCSI2SD</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:3.17500019px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#c8c8c8;fill-opacity:1;stroke:none;stroke-width:0.26458335px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="5.943749"
+ y="244.27229"
+ id="text1372"><tspan
+ sodipodi:role="line"
+ id="tspan1370"
+ x="5.943749"
+ y="244.27229"
+ style="fill:#c8c8c8;fill-opacity:1;stroke-width:0.26458335px">Configuration and Firmware Update Utility</tspan><tspan
+ sodipodi:role="line"
+ x="5.943749"
+ y="248.24104"
+ style="fill:#c8c8c8;fill-opacity:1;stroke-width:0.26458335px"
+ id="tspan1408">v1.0-BETA</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:3.17500019px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458335px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="5.291667"
+ y="272.9985"
+ id="text1380"><tspan
+ sodipodi:role="line"
+ id="tspan1378"
+ x="5.291667"
+ y="275.80765"
+ style="stroke-width:0.26458335px" /></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:3.17500019px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#969696;fill-opacity:1;stroke:none;stroke-width:0.26458335px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="6.0476184"
+ y="254.47769"
+ id="text1384"><tspan
+ sodipodi:role="line"
+ x="6.0476184"
+ y="254.47769"
+ style="fill:#969696;fill-opacity:1;stroke-width:0.26458335px"
+ id="tspan1386">scsi2sd-util Copyright © 2019 Michael McMaster</tspan><tspan
+ sodipodi:role="line"
+ x="6.0476184"
+ y="258.44644"
+ style="fill:#969696;fill-opacity:1;stroke-width:0.26458335px"
+ id="tspan1406" /><tspan
+ sodipodi:role="line"
+ x="6.0476184"
+ y="262.41519"
+ style="fill:#969696;fill-opacity:1;stroke-width:0.26458335px"
+ id="tspan1388">This program comes with ABSOLUTELY NO WARRANTY.</tspan><tspan
+ sodipodi:role="line"
+ x="6.0476184"
+ y="266.38394"
+ style="fill:#969696;fill-opacity:1;stroke-width:0.26458335px"
+ id="tspan1392">This program is free software: you can redistribute it and/or modify</tspan><tspan
+ sodipodi:role="line"
+ x="6.0476184"
+ y="270.35269"
+ style="fill:#969696;fill-opacity:1;stroke-width:0.26458335px"
+ id="tspan1398">it under the terms of the GNU General Public License as published by</tspan><tspan
+ sodipodi:role="line"
+ x="6.0476184"
+ y="274.32144"
+ style="fill:#969696;fill-opacity:1;stroke-width:0.26458335px"
+ id="tspan1400">the Free Software Foundation, either version 3 of the License, or</tspan><tspan
+ sodipodi:role="line"
+ x="6.0476184"
+ y="278.29019"
+ style="fill:#969696;fill-opacity:1;stroke-width:0.26458335px"
+ id="tspan1402">(at your option) any later version.</tspan><tspan
+ sodipodi:role="line"
+ x="6.0476184"
+ y="282.25894"
+ style="fill:#969696;fill-opacity:1;stroke-width:0.26458335px"
+ id="tspan1404" /></text>
+ </g>
+</svg>
+++ /dev/null
-// Copyright (C) 2017 Michael McMaster <michael@codesrc.com>
-//
-// This file is part of SCSI2SD.
-//
-// SCSI2SD is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// SCSI2SD is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with SCSI2SD. If not, see <http://www.gnu.org/licenses/>.
-
-package com.codesrc.scsi2sd;
-
-import javafx.application.Application;
-import javafx.stage.Stage;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Properties;
-
-public class App extends Application {
-
-
- @Override
- public void start(Stage stage) throws Exception {
- AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfiguration.class);
- ScreensConfiguration screens = context.getBean(ScreensConfiguration.class);
- screens.setPrimaryStage(stage);
- screens.mainWindow().show();
- }
-
-
- public static void main(String[] args) {
-
- Properties appProperties = new Properties();
- try (InputStream is = App.class.getResourceAsStream("/app.properties")) {
- appProperties.load(is);
- } catch (IOException e)
- {
- System.err.println("Could not load resources");
- System.exit(1);
- }
-
-
- System.out.println(
- " SCSI2SD Utility v" + appProperties.getProperty("com.codesrc.scsi2sd.app.version") + "\n" +
- " Copyright (C) 2017 Michael McMaster <michael@codesrc.com>\n" +
- "\n" +
- " This program is free software: you can redistribute it and/or modify\n" +
- " it under the terms of the GNU General Public License as published by\n" +
- " the Free Software Foundation, either version 3 of the License, or\n" +
- " (at your option) any later version.\n" +
- "\n" +
- " This program is distributed in the hope that it will be useful,\n" +
- " but WITHOUT ANY WARRANTY; without even the implied warranty of\n" +
- " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" +
- " GNU General Public License for more details.\n" +
- "\n" +
- " You should have received a copy of the GNU General Public License\n" +
- " along with this program. If not, see <http://www.gnu.org/licenses/>.\n");
-
-
- launch(args);
- }
-}
\ No newline at end of file
+++ /dev/null
-// Copyright (C) 2017 Michael McMaster <michael@codesrc.com>
-//
-// This file is part of SCSI2SD.
-//
-// SCSI2SD is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// SCSI2SD is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with SCSI2SD. If not, see <http://www.gnu.org/licenses/>.
-
-package com.codesrc.scsi2sd;
-
-import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.ImportResource;
-
-/**
- * Created by michael on 27/05/17.
- */
-@Configuration
-@ImportResource("/context/applicationContext.xml")
-public class AppConfiguration {
-
-
-}
+++ /dev/null
-// Copyright (C) 2017 Michael McMaster <michael@codesrc.com>
-//
-// This file is part of SCSI2SD.
-//
-// SCSI2SD is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// SCSI2SD is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with SCSI2SD. If not, see <http://www.gnu.org/licenses/>.
-
-package com.codesrc.scsi2sd;
-
-import com.codesrc.scsi2sd.presentation.AboutController;
-import com.codesrc.scsi2sd.presentation.FXWindow;
-import com.codesrc.scsi2sd.presentation.MainController;
-import javafx.scene.Parent;
-import javafx.scene.Scene;
-import javafx.stage.Stage;
-import javafx.stage.StageStyle;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.Lazy;
-import org.springframework.context.annotation.Scope;
-
-/**
- * Created by michael on 27/05/17.
- */
-@Configuration
-@Lazy
-public class ScreensConfiguration {
- private Stage primaryStage;
-
- public void setPrimaryStage(Stage primaryStage) {
- this.primaryStage = primaryStage;
- }
-
- public void showScreen(Parent screen) {
- primaryStage.setScene(new Scene(screen));
- primaryStage.show();
- }
-
- @Bean
- @Scope("prototype")
- public FXWindow mainWindow() {
- return new FXWindow(mainController(), getClass().getResource("/fx/main.fxml"), "codesrc SCSI2SD", primaryStage, StageStyle.DECORATED);
- }
-
- @Bean
- @Scope("prototype")
- public FXWindow aboutWindow(FXWindow parentWindow) {
- return new FXWindow(aboutController(), getClass().getResource("/fx/about.fxml"), "About SCSI2SD", parentWindow, StageStyle.DECORATED);
- }
-
- @Bean
- @Scope("prototype")
- public MainController mainController() {
- return new MainController(this);
- }
-
-
- @Bean
- @Scope("prototype")
- public AboutController aboutController() {
- return new AboutController(this);
- }
-}
+++ /dev/null
-// Copyright (C) 2017 Michael McMaster <michael@codesrc.com>
-//
-// This file is part of SCSI2SD.
-//
-// SCSI2SD is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// SCSI2SD is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with SCSI2SD. If not, see <http://www.gnu.org/licenses/>.
-
-package com.codesrc.scsi2sd.model;
-
-public interface BitEnum {
- int getBit();
-}
+++ /dev/null
-// Copyright (C) 2017 Michael McMaster <michael@codesrc.com>
-//
-// This file is part of SCSI2SD.
-//
-// SCSI2SD is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// SCSI2SD is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with SCSI2SD. If not, see <http://www.gnu.org/licenses/>.
-
-package com.codesrc.scsi2sd.model;
-
-import javax.xml.bind.annotation.XmlAccessType;
-import javax.xml.bind.annotation.XmlAccessorType;
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlType;
-import java.util.HashSet;
-import java.util.Set;
-
-@XmlType(name = "S2S_BoardCfg")
-@XmlAccessorType(XmlAccessType.NONE)
-public class BoardConfig {
- public static final int LENGTH = 128;
-
- private Set<Flag> flags;
-
- private int startupDelay; // Seconds
-
- private int selectionDelay; // milliseconds
-
- private Set<Flag6> flags6;
-
- private Speed scsiSpeed;
-
- public BoardConfig() {
- this.flags = new HashSet<>();
- this.flags6 = new HashSet<>();
- this.flags6.add(Flag6.S2S_CFG_ENABLE_TERMINATOR);
-
- this.selectionDelay = 255; // "Auto".
- this.scsiSpeed = Speed.S2S_CFG_SPEED_NoLimit;
- }
-
-
- public BoardConfig(byte[] in) {
- if (in.length != LENGTH) {
- throw new IllegalArgumentException("BoardConfig size incorrect");
- }
-
- flags = Flag.fromBitmask(in[4]);
- startupDelay = (int)in[5] & 0xFF;
- selectionDelay = (int)in[6] & 0xFF;
- flags6 = Flag6.fromBitmask(in[7]);
- scsiSpeed = Speed.fromBits(in[8]);
- }
-
- public byte[] asBytes() {
- byte[] out = new byte[LENGTH];
-
- out[0] = 'B'; out[1] = 'C'; out[2] = 'F'; out[3] = 'G';
-
- out[4] = getMask(flags);
- out[5] = (byte) startupDelay;
- out[6] = (byte) selectionDelay;
- out[7] = getMask(flags6);
- out[8] = (byte) scsiSpeed.getValue();
- return out;
- }
-
- private <T extends BitEnum> byte getMask(Set<T> flags) {
- int result = 0;
- for (T item : flags) {
- result |= item.getBit();
- }
- return (byte) result;
- }
-
- public Set<Flag> getFlags() {
- return flags;
- }
-
- public void setFlags(Set<Flag> flags) {
- this.flags = flags;
- }
-
- @XmlElement(name = "startupDelay")
- public int getStartupDelay() {
- return startupDelay;
- }
-
- public void setStartupDelay(int startupDelay) {
- this.startupDelay = startupDelay;
- }
-
- @XmlElement(name = "selectionDelay")
- public int getSelectionDelay() {
- return selectionDelay;
- }
-
- public void setSelectionDelay(int selectionDelay) {
- this.selectionDelay = selectionDelay;
- }
-
- public Set<Flag6> getFlags6() {
- return flags6;
- }
-
- public void setFlag6(Set<Flag6> flags6) {
- this.flags6 = flags6;
- }
-
- public Speed getScsiSpeed() {
- return scsiSpeed;
- }
-
- public void setScsiSpeed(Speed scsiSpeed) {
- this.scsiSpeed = scsiSpeed;
- }
-
- @XmlElement(name = "enableTerminator")
- public boolean isEnableTerminator() {
- return flags6.contains(Flag6.S2S_CFG_ENABLE_TERMINATOR);
- }
-
- public void setEnableTerminator(boolean enableTerminator) {
- this.flags6.add(Flag6.S2S_CFG_ENABLE_TERMINATOR);
- }
-}
+++ /dev/null
-// Copyright (C) 2017 Michael McMaster <michael@codesrc.com>
-//
-// This file is part of SCSI2SD.
-//
-// SCSI2SD is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// SCSI2SD is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with SCSI2SD. If not, see <http://www.gnu.org/licenses/>.
-
-package com.codesrc.scsi2sd.model;
-
-import javax.xml.bind.annotation.XmlAccessType;
-import javax.xml.bind.annotation.XmlAccessorType;
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlRootElement;
-
-@XmlRootElement(name = "SCSI2SD")
-@XmlAccessorType(XmlAccessType.NONE)
-public class ConfigRoot {
- private BoardConfig boardConfig;
-
- @XmlElement(name = "S2S_BoardCfg")
- public BoardConfig getBoardConfig() {
- return boardConfig;
- }
-
- public void setBoardConfig(BoardConfig boardConfig) {
- this.boardConfig = boardConfig;
- }
-}
+++ /dev/null
-// Copyright (C) 2017 Michael McMaster <michael@codesrc.com>
-//
-// This file is part of SCSI2SD.
-//
-// SCSI2SD is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// SCSI2SD is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with SCSI2SD. If not, see <http://www.gnu.org/licenses/>.
-
-package com.codesrc.scsi2sd.model;
-
-import java.util.EnumSet;
-import java.util.HashSet;
-import java.util.Set;
-
-public enum Flag6 implements BitEnum {
- S2S_CFG_ENABLE_TERMINATOR(1);
-
- static Set<Flag6> fromBitmask(byte bitmask) {
- Set<Flag6> result = new HashSet<>();
- for (Flag6 flag : EnumSet.allOf(Flag6.class)) {
- if ((((int) bitmask & 0xFF) & flag.getBit()) != 0) {
- result.add(flag);
- }
- }
- return result;
- }
-
- private int bit;
- Flag6(int bit) {
- this.bit = bit;
- }
-
- @Override
- public int getBit() { return bit; }
-}
+++ /dev/null
-// Copyright (C) 2017 Michael McMaster <michael@codesrc.com>
-//
-// This file is part of SCSI2SD.
-//
-// SCSI2SD is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// SCSI2SD is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with SCSI2SD. If not, see <http://www.gnu.org/licenses/>.
-
-package com.codesrc.scsi2sd.model;
-
-import java.util.EnumSet;
-
-public enum Speed {
- S2S_CFG_SPEED_NoLimit(0),
- S2S_CFG_SPEED_ASYNC_15(1),
- S2S_CFG_SPEED_ASYNC_33(2),
- S2S_CFG_SPEED_ASYNC_50(3),
- S2S_CFG_SPEED_SYNC_5(4),
- S2S_CFG_SPEED_SYNC_10(5),
- S2S_CFG_SPEED_TURBO(6);
-
- static Speed fromBits(byte bits) {
-
- for (Speed speed : EnumSet.allOf(Speed.class)) {
- if (speed.getValue() == ((int) bits & 0xFF)) {
- return speed;
- }
- }
- return S2S_CFG_SPEED_NoLimit;
- }
-
-
- private int value;
-
- Speed(int value) {
- this.value = value;
- }
-
- int getValue() {
- return value;
- }
-}
-
-
+++ /dev/null
-// Copyright (C) 2017 Michael McMaster <michael@codesrc.com>
-//
-// This file is part of SCSI2SD.
-//
-// SCSI2SD is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// SCSI2SD is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with SCSI2SD. If not, see <http://www.gnu.org/licenses/>.
-
-package com.codesrc.scsi2sd.presentation;
-
-import com.codesrc.scsi2sd.ScreensConfiguration;
-import javafx.fxml.FXML;
-import javafx.scene.control.Button;
-import javafx.scene.control.Label;
-import javafx.scene.control.TextArea;
-import javafx.scene.control.Tooltip;
-import org.controlsfx.control.HyperlinkLabel;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
-
-import java.io.BufferedReader;
-import java.io.InputStreamReader;
-import java.net.URL;
-import java.util.ResourceBundle;
-import java.util.stream.Collectors;
-
-/**
- * Created by michael on 27/05/17.
- */
-public class AboutController implements FXController {
- private static org.slf4j.Logger LOGGER = LoggerFactory.getLogger(AboutController.class.getName());
-
- private ScreensConfiguration screens;
- private FXWindow window;
-
-
- @FXML private TextArea aboutText;
- @FXML private Label labelVersion;
- @FXML private HyperlinkLabel licenceLink;
- @FXML private Button buttonClose;
-
- @Autowired
- private Desktop desktop;
-
- @Value("${com.codesrc.scsi2sd.app.licence.url}")
- private String licenseURL;
-
- @Value("${com.codesrc.scsi2sd.app.version}")
- private String appVersion;
-
- public AboutController(ScreensConfiguration screens) {
- this.screens = screens;
- }
-
- @Override
- public void setWindow(FXWindow window) {
- this.window = window;
- }
-
- public void initialize(URL url, ResourceBundle resourceBundle) {
- String about = new BufferedReader(new InputStreamReader(getClass().getResourceAsStream("/licence.txt")))
- .lines().collect(Collectors.joining("\n"));
-
- aboutText.setText(about);
- labelVersion.setText(labelVersion.getText() + appVersion);
-
- licenceLink.setTooltip(new Tooltip(licenseURL));
- licenceLink.setOnAction(h -> desktop.openBrowser(licenseURL));
-
- buttonClose.setOnAction(h -> window.close());
- }
-
-}
+++ /dev/null
-// Copyright (C) 2017 Michael McMaster <michael@codesrc.com>
-//
-// This file is part of SCSI2SD.
-//
-// SCSI2SD is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// SCSI2SD is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with SCSI2SD. If not, see <http://www.gnu.org/licenses/>.
-
-package com.codesrc.scsi2sd.presentation;
-
-import javafx.fxml.Initializable;
-
-/**
- * Created by michael on 27/05/17.
- */
-public interface FXController extends Initializable {
- void setWindow(FXWindow window);
-}
+++ /dev/null
-// Copyright (C) 2017 Michael McMaster <michael@codesrc.com>
-//
-// This file is part of SCSI2SD.
-//
-// SCSI2SD is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// SCSI2SD is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with SCSI2SD. If not, see <http://www.gnu.org/licenses/>.
-
-package com.codesrc.scsi2sd.presentation;
-
-import com.codesrc.scsi2sd.App;
-import javafx.fxml.FXMLLoader;
-import javafx.scene.Parent;
-import javafx.scene.Scene;
-import javafx.scene.image.Image;
-import javafx.stage.Modality;
-import javafx.stage.Stage;
-import javafx.stage.StageStyle;
-import javafx.stage.Window;
-
-import java.io.IOException;
-import java.net.URL;
-
-/**
- * Created by michael on 27/05/17.
- */
-public class FXWindow extends Stage {
- public FXWindow(FXController controller, URL fxml, String title, Window owner) {
- this(controller, fxml, title, owner, StageStyle.DECORATED);
- }
-
- public FXWindow(final FXController controller, URL fxml, String title, Window owner, StageStyle style) {
- super(style);
- initOwner(owner);
- initModality(Modality.WINDOW_MODAL);
- getIcons().add(new Image(App.class.getResourceAsStream("/icons/codesrc-16x16.png")));
- getIcons().add(new Image(App.class.getResourceAsStream("/icons/codesrc-32x32.png")));
- setTitle(title);
-
-
- FXMLLoader loader = new FXMLLoader(fxml);
- try {
- loader.setControllerFactory(a -> controller);
- controller.setWindow(this);
- setScene(new Scene((Parent) loader.load()));
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-}
\ No newline at end of file
+++ /dev/null
-// Copyright (C) 2017 Michael McMaster <michael@codesrc.com>
-//
-// This file is part of SCSI2SD.
-//
-// SCSI2SD is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// SCSI2SD is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with SCSI2SD. If not, see <http://www.gnu.org/licenses/>.
-
-package com.codesrc.scsi2sd.presentation;
-
-import com.codesrc.scsi2sd.ScreensConfiguration;
-import javafx.fxml.FXML;
-import javafx.scene.control.MenuItem;
-import javafx.scene.control.TabPane;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.net.URL;
-import java.util.ResourceBundle;
-
-
-/**
- * Created by michael on 21/05/17.
- */
-public class MainController implements FXController {
- private static Logger LOGGER = LoggerFactory.getLogger(MainController.class.getName());
-
- private ScreensConfiguration screens;
- private FXWindow window;
-
-
- @FXML private MenuItem menuAbout;
- @FXML private MenuItem menuQuit;
-
- @FXML private TabPane mainTabPane;
-
- // @FXML private TextField cfgSelectionDelay;
- // @FXML private Button cfgSelectionDelayHelp;
-
- public MainController(ScreensConfiguration screens) {
- this.screens = screens;
- }
-
- @Override
- public void setWindow(FXWindow window) {
- this.window = window;
- }
-
- @Override
- public void initialize(URL url, ResourceBundle resourceBundle) {
- menuQuit.setOnAction(h -> System.exit(0));
- menuAbout.setOnAction(h -> screens.aboutWindow(window).showAndWait());
- // testLoad();
- }
-
-/*
- private void testLoad() {
- try {
- File file = new File("/tmp/t.xml");
- JAXBContext jaxbContext = JAXBContext.newInstance(ConfigRoot.class);
-
- Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
- ConfigRoot customer = (ConfigRoot) jaxbUnmarshaller.unmarshal(file);
- System.out.println(customer.getBoardConfig().getStartupDelay());
-
- cfgSelectionDelay.setText(String.valueOf(customer.getBoardConfig().getSelectionDelay()));
-
- Tooltip tip = new Tooltip("Delay before responding to SCSI selection.\nSCSI1 hosts usually require 1ms delay.\n\nDefault: blank for auto selection.");
- cfgSelectionDelay.setTooltip(tip);
- cfgSelectionDelayHelp.setOnAction(h -> {
- Dialog<String> dialog = new Dialog<>();
- dialog.setTitle("Selection Delay");
- dialog.setContentText("Delay before responding to SCSI selection.\nSCSI1 hosts usually require 1ms delay.\n\nDefault: blank for auto selection.");
- dialog.getDialogPane().getButtonTypes().add(ButtonType.CLOSE);
- dialog.showAndWait();
- });
- } catch (Exception e) {
- // don't ever do this
- }
- }
- */
-
-}
+++ /dev/null
-
-com.codesrc.scsi2sd.app.version = 0.1
-
-com.codesrc.scsi2sd.app.licence.type = GPLv3+
-com.codesrc.scsi2sd.app.licence.url = https://www.gnu.org/licenses/gpl-3.0.en.html
-
-
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-
-<beans
- xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:context="http://www.springframework.org/schema/context"
-
- xsi:schemaLocation="
- http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-4.3.xsd">
-
- <context:component-scan base-package="com.codesrc.scsi2sd" />
-
- <bean id="appProperties"
- class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
- <property name="location" value="app.properties" />
- </bean>
-</beans>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-
-<?import javafx.geometry.*?>
-<?import javafx.scene.text.*?>
-<?import java.lang.*?>
-<?import javafx.scene.control.*?>
-<?import javafx.scene.layout.*?>
-
-<?import javafx.scene.image.ImageView?>
-<?import javafx.scene.image.Image?>
- <ScrollPane fitToWidth="true" hbarPolicy="AS_NEEDED" vbarPolicy="AS_NEEDED" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
- <content>
- <VBox>
- <children>
- <GridPane hgap="15.0" vgap="5.0" VBox.vgrow="ALWAYS">
- <columnConstraints>
- <ColumnConstraints halignment="RIGHT" hgrow="SOMETIMES" maxWidth="380.0" minWidth="10.0" prefWidth="162.0" />
- <ColumnConstraints hgrow="SOMETIMES" maxWidth="450.0" minWidth="200.0" prefWidth="329.0" />
- <ColumnConstraints hgrow="SOMETIMES" maxWidth="315.0" minWidth="0.0" prefWidth="215.0" />
- </columnConstraints>
- <rowConstraints>
- <RowConstraints maxHeight="60.0" minHeight="15.0" prefHeight="30.0" vgrow="SOMETIMES" />
- <RowConstraints maxHeight="60.0" minHeight="15.0" prefHeight="30.0" vgrow="SOMETIMES" />
- <RowConstraints maxHeight="60.0" minHeight="15.0" prefHeight="30.0" vgrow="SOMETIMES" />
- <RowConstraints maxHeight="60.0" minHeight="15.0" prefHeight="30.0" vgrow="SOMETIMES" />
- <RowConstraints maxHeight="60.0" minHeight="15.0" prefHeight="30.0" vgrow="SOMETIMES" />
- <RowConstraints maxHeight="60.0" minHeight="15.0" prefHeight="30.0" vgrow="SOMETIMES" />
- <RowConstraints maxHeight="60.0" minHeight="15.0" prefHeight="30.0" vgrow="SOMETIMES" />
- <RowConstraints maxHeight="60.0" minHeight="15.0" prefHeight="30.0" vgrow="SOMETIMES" />
- <RowConstraints maxHeight="60.0" minHeight="15.0" prefHeight="30.0" vgrow="SOMETIMES" />
- <RowConstraints maxHeight="60.0" minHeight="15.0" prefHeight="30.0" vgrow="SOMETIMES" />
- <RowConstraints maxHeight="60.0" minHeight="15.0" prefHeight="30.0" vgrow="SOMETIMES" />
- </rowConstraints>
- <children>
- <Label text="Enable Active Terminator" GridPane.columnIndex="1" GridPane.rowIndex="1" />
- <CheckBox mnemonicParsing="false" GridPane.rowIndex="1" />
- <Label text="SCSI Speed Limit" GridPane.columnIndex="1" GridPane.rowIndex="3" />
- <ChoiceBox prefWidth="150.0" GridPane.rowIndex="3" />
- <Label text="Startup Delay. 0 to 255 seconds." wrapText="true" GridPane.columnIndex="1" GridPane.rowIndex="4" />
- <TextField alignment="CENTER_RIGHT" maxWidth="150.0" promptText="0" GridPane.rowIndex="4" />
-
- <Label text="Selection Delay. 0 to 255 milliseconds." GridPane.columnIndex="1" GridPane.rowIndex="5" />
- <TextField fx:id="cfgSelectionDelay" alignment="CENTER_RIGHT" maxWidth="150.0" promptText="auto" GridPane.rowIndex="5">
- </TextField>
-
- <Label text="Check parity" GridPane.columnIndex="1" GridPane.rowIndex="6" />
- <Label text="Unit Attention" GridPane.columnIndex="1" GridPane.rowIndex="7" />
- <Label text="SCSI2 Mode" GridPane.columnIndex="1" GridPane.rowIndex="2" />
- <Label text="Respond to short selection pulses" GridPane.columnIndex="1" GridPane.rowIndex="10" />
- <Label text="Map LUNS to IDs" GridPane.columnIndex="1" GridPane.rowIndex="11" />
- <CheckBox mnemonicParsing="false" GridPane.rowIndex="6" />
- <CheckBox mnemonicParsing="false" GridPane.rowIndex="7" />
- <CheckBox mnemonicParsing="false" GridPane.rowIndex="2" />
- <CheckBox mnemonicParsing="false" GridPane.rowIndex="10" />
- <CheckBox mnemonicParsing="false" GridPane.rowIndex="11" />
- <Label text="Default" GridPane.columnIndex="2">
- <font>
- <Font name="System Bold" size="13.0" />
- </font>
- </Label>
- <Label text="Enabled" GridPane.columnIndex="2" GridPane.rowIndex="1" />
- <Label text="No Limit" GridPane.columnIndex="2" GridPane.rowIndex="3" />
- <Label text="0" GridPane.columnIndex="2" GridPane.rowIndex="4" />
- <Label text="Auto (blank)" GridPane.columnIndex="2" GridPane.rowIndex="5" />
- <Label text="Enabled" GridPane.columnIndex="2" GridPane.rowIndex="6" />
- <Label text="Disabled" GridPane.columnIndex="2" GridPane.rowIndex="7" />
- <Label text="Disabled" GridPane.columnIndex="2" GridPane.rowIndex="2" />
- <Label text="Disabled" GridPane.columnIndex="2" GridPane.rowIndex="10" />
- <Label text="Disabled" GridPane.columnIndex="2" GridPane.rowIndex="11" />
- <Label text="Advanced" GridPane.columnIndex="1" GridPane.rowIndex="9">
- <font>
- <Font name="System Bold" size="13.0" />
- </font>
- </Label>
- </children>
- </GridPane>
- </children>
- </VBox>
- </content>
- </ScrollPane>
\ No newline at end of file
+++ /dev/null
-<?import javafx.scene.layout.AnchorPane?>
-<?import javafx.scene.control.Button?>
-<?import javafx.scene.control.TableView?>
-<?import javafx.scene.control.TableColumn?>
-
-<?import javafx.scene.layout.VBox?>
-<?import javafx.scene.control.Accordion?>
-<?import javafx.scene.control.TitledPane?>
-<?import javafx.scene.layout.GridPane?>
-<?import javafx.scene.layout.ColumnConstraints?>
-<?import javafx.scene.layout.RowConstraints?>
-<?import javafx.scene.control.Label?>
-<?import javafx.scene.control.TextField?>
-<?import javafx.scene.control.ComboBox?>
-<?import javafx.scene.control.ChoiceBox?>
-<?import javafx.scene.control.ScrollPane?>
-
-
-<ScrollPane fitToWidth="true" hbarPolicy="AS_NEEDED" vbarPolicy="AS_NEEDED" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
- <content>
-
- <VBox>
- <children>
- <AnchorPane xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" minHeight="350" prefHeight="350.0" maxHeight="350">
- <children>
- <Button AnchorPane.bottomAnchor="10.0" AnchorPane.leftAnchor="14.0" mnemonicParsing="false" prefWidth="100.0" text="New ..." />
- <Button AnchorPane.bottomAnchor="10.0" AnchorPane.leftAnchor="114.0" mnemonicParsing="false" prefWidth="100.0" text="Configure ..." />
- <Button AnchorPane.bottomAnchor="10.0" AnchorPane.leftAnchor="214.0" mnemonicParsing="false" prefWidth="100.0" text="Delete" />
- <TableView AnchorPane.bottomAnchor="50.0" AnchorPane.leftAnchor="15.0" AnchorPane.rightAnchor="15.0" AnchorPane.topAnchor="10.0">
- <columnResizePolicy>
- <TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
- </columnResizePolicy>
- <columns>
- <TableColumn editable="false" minWidth="50" prefWidth="75.0" text="Item" />
- <TableColumn editable="false" minWidth="75" prefWidth="261.0" text="Type" />
- <TableColumn editable="false" minWidth="75" prefWidth="178.0" text="Size" />
- <TableColumn editable="false" minWidth="50" prefWidth="100.0" text="SCSI ID" />
- <TableColumn minWidth="50" prefWidth="115.0" text="Enabled" />
- </columns>
- </TableView>
- </children>
- </AnchorPane>
-
- <Accordion>
- <panes>
- <TitledPane animated="false" text="Basic">
- <content>
- <AnchorPane>
- <children>
- <GridPane layoutX="14.0" layoutY="14.0" prefHeight="105.0" prefWidth="500.0">
- <columnConstraints>
- <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
- <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
- </columnConstraints>
- <rowConstraints>
- <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
- <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
- <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
- </rowConstraints>
- <children>
- <Label text="SCSI ID" />
- <Label text="Type" GridPane.rowIndex="1" />
- <TextField promptText="0" GridPane.columnIndex="1" />
- <ComboBox prefHeight="25.0" prefWidth="270.0" GridPane.columnIndex="1" GridPane.rowIndex="1" />
- </children>
- </GridPane>
- </children>
- </AnchorPane>
- </content>
- </TitledPane>
- <TitledPane animated="false" text="Size">
- <content>
- <AnchorPane>
- <children>
- <ChoiceBox layoutX="375.0" layoutY="215.0" prefWidth="150.0" />
- <Label layoutX="14.0" layoutY="14.0" text="SD Sector" />
- <TextField alignment="CENTER_RIGHT" layoutX="142.0" layoutY="8.0" prefHeight="25.0" prefWidth="200.0" />
- <Label layoutX="142.0" layoutY="41.0" text="Min:" />
- <Label layoutX="142.0" layoutY="68.0" text="Max:" />
- <Label layoutX="16.0" layoutY="221.0" text="Size" />
- <TextField alignment="CENTER_RIGHT" layoutX="144.0" layoutY="215.0" prefHeight="25.0" prefWidth="200.0" />
- <TextField alignment="CENTER_RIGHT" editable="false" layoutX="187.0" layoutY="36.0" prefHeight="25.0" prefWidth="155.0" />
- <TextField alignment="CENTER_RIGHT" editable="false" layoutX="187.0" layoutY="63.0" prefHeight="25.0" prefWidth="155.0" />
- <TextField alignment="CENTER_RIGHT" editable="false" layoutX="189.0" layoutY="274.0" prefHeight="25.0" prefWidth="155.0" />
- <TextField alignment="CENTER_RIGHT" editable="false" layoutX="189.0" layoutY="247.0" prefHeight="25.0" prefWidth="155.0" />
- <Label layoutX="144.0" layoutY="279.0" text="Max:" />
- <Label layoutX="144.0" layoutY="252.0" text="Min:" />
- <Label layoutX="12.0" layoutY="124.0" text="SCSI Sector Size" />
- <TextField alignment="CENTER_RIGHT" layoutX="142.0" layoutY="118.0" prefHeight="25.0" prefWidth="200.0" promptText="512 bytes" />
- </children>
- </AnchorPane>
- </content>
- </TitledPane>
- <TitledPane animated="false" text="Identification">
- <content>
- <AnchorPane>
- <children>
- <GridPane layoutX="14.0" layoutY="14.0" prefHeight="136.0" prefWidth="524.0">
- <columnConstraints>
- <ColumnConstraints hgrow="SOMETIMES" maxWidth="255.0" minWidth="10.0" prefWidth="151.0" />
- <ColumnConstraints hgrow="SOMETIMES" maxWidth="373.0" minWidth="10.0" prefWidth="373.0" />
- </columnConstraints>
- <rowConstraints>
- <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
- <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
- <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
- <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
- </rowConstraints>
- <children>
- <Label text="Vendor" />
- <Label text="Product ID" GridPane.rowIndex="1" />
- <Label text="Revision" GridPane.rowIndex="2" />
- <Label text="Serial Number" GridPane.rowIndex="3" />
- <TextField promptText="codesrc" GridPane.columnIndex="1" />
- <TextField promptText="SCSI2SD" GridPane.columnIndex="1" GridPane.rowIndex="1" />
- <TextField promptText="1.0" GridPane.columnIndex="1" GridPane.rowIndex="2" />
- <TextField promptText="12345678" GridPane.columnIndex="1" GridPane.rowIndex="3" />
- </children>
- </GridPane>
- </children>
- </AnchorPane>
- </content>
- </TitledPane>
- </panes>
- </Accordion>
- </children>
- </VBox>
- </content>
-</ScrollPane>
+++ /dev/null
- GNU GENERAL PUBLIC LICENSE
- Version 3, 29 June 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The GNU General Public License is a free, copyleft license for
-software and other kinds of works.
-
- The licenses for most software and other practical works are designed
-to take away your freedom to share and change the works. By contrast,
-the GNU General Public License is intended to guarantee your freedom to
-share and change all versions of a program--to make sure it remains free
-software for all its users. We, the Free Software Foundation, use the
-GNU General Public License for most of our software; it applies also to
-any other work released this way by its authors. You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-them if you wish), that you receive source code or can get it if you
-want it, that you can change the software or use pieces of it in new
-free programs, and that you know you can do these things.
-
- To protect your rights, we need to prevent others from denying you
-these rights or asking you to surrender the rights. Therefore, you have
-certain responsibilities if you distribute copies of the software, or if
-you modify it: responsibilities to respect the freedom of others.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must pass on to the recipients the same
-freedoms that you received. You must make sure that they, too, receive
-or can get the source code. And you must show them these terms so they
-know their rights.
-
- Developers that use the GNU GPL protect your rights with two steps:
-(1) assert copyright on the software, and (2) offer you this License
-giving you legal permission to copy, distribute and/or modify it.
-
- For the developers' and authors' protection, the GPL clearly explains
-that there is no warranty for this free software. For both users' and
-authors' sake, the GPL requires that modified versions be marked as
-changed, so that their problems will not be attributed erroneously to
-authors of previous versions.
-
- Some devices are designed to deny users access to install or run
-modified versions of the software inside them, although the manufacturer
-can do so. This is fundamentally incompatible with the aim of
-protecting users' freedom to change the software. The systematic
-pattern of such abuse occurs in the area of products for individuals to
-use, which is precisely where it is most unacceptable. Therefore, we
-have designed this version of the GPL to prohibit the practice for those
-products. If such problems arise substantially in other domains, we
-stand ready to extend this provision to those domains in future versions
-of the GPL, as needed to protect the freedom of users.
-
- Finally, every program is threatened constantly by software patents.
-States should not allow patents to restrict development and use of
-software on general-purpose computers, but in those that do, we wish to
-avoid the special danger that patents applied to a free program could
-make it effectively proprietary. To prevent this, the GPL assures that
-patents cannot be used to render the program non-free.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- TERMS AND CONDITIONS
-
- 0. Definitions.
-
- "This License" refers to version 3 of the GNU General Public License.
-
- "Copyright" also means copyright-like laws that apply to other kinds of
-works, such as semiconductor masks.
-
- "The Program" refers to any copyrightable work licensed under this
-License. Each licensee is addressed as "you". "Licensees" and
-"recipients" may be individuals or organizations.
-
- To "modify" a work means to copy from or adapt all or part of the work
-in a fashion requiring copyright permission, other than the making of an
-exact copy. The resulting work is called a "modified version" of the
-earlier work or a work "based on" the earlier work.
-
- A "covered work" means either the unmodified Program or a work based
-on the Program.
-
- To "propagate" a work means to do anything with it that, without
-permission, would make you directly or secondarily liable for
-infringement under applicable copyright law, except executing it on a
-computer or modifying a private copy. Propagation includes copying,
-distribution (with or without modification), making available to the
-public, and in some countries other activities as well.
-
- To "convey" a work means any kind of propagation that enables other
-parties to make or receive copies. Mere interaction with a user through
-a computer network, with no transfer of a copy, is not conveying.
-
- An interactive user interface displays "Appropriate Legal Notices"
-to the extent that it includes a convenient and prominently visible
-feature that (1) displays an appropriate copyright notice, and (2)
-tells the user that there is no warranty for the work (except to the
-extent that warranties are provided), that licensees may convey the
-work under this License, and how to view a copy of this License. If
-the interface presents a list of user commands or options, such as a
-menu, a prominent item in the list meets this criterion.
-
- 1. Source Code.
-
- The "source code" for a work means the preferred form of the work
-for making modifications to it. "Object code" means any non-source
-form of a work.
-
- A "Standard Interface" means an interface that either is an official
-standard defined by a recognized standards body, or, in the case of
-interfaces specified for a particular programming language, one that
-is widely used among developers working in that language.
-
- The "System Libraries" of an executable work include anything, other
-than the work as a whole, that (a) is included in the normal form of
-packaging a Major Component, but which is not part of that Major
-Component, and (b) serves only to enable use of the work with that
-Major Component, or to implement a Standard Interface for which an
-implementation is available to the public in source code form. A
-"Major Component", in this context, means a major essential component
-(kernel, window system, and so on) of the specific operating system
-(if any) on which the executable work runs, or a compiler used to
-produce the work, or an object code interpreter used to run it.
-
- The "Corresponding Source" for a work in object code form means all
-the source code needed to generate, install, and (for an executable
-work) run the object code and to modify the work, including scripts to
-control those activities. However, it does not include the work's
-System Libraries, or general-purpose tools or generally available free
-programs which are used unmodified in performing those activities but
-which are not part of the work. For example, Corresponding Source
-includes interface definition files associated with source files for
-the work, and the source code for shared libraries and dynamically
-linked subprograms that the work is specifically designed to require,
-such as by intimate data communication or control flow between those
-subprograms and other parts of the work.
-
- The Corresponding Source need not include anything that users
-can regenerate automatically from other parts of the Corresponding
-Source.
-
- The Corresponding Source for a work in source code form is that
-same work.
-
- 2. Basic Permissions.
-
- All rights granted under this License are granted for the term of
-copyright on the Program, and are irrevocable provided the stated
-conditions are met. This License explicitly affirms your unlimited
-permission to run the unmodified Program. The output from running a
-covered work is covered by this License only if the output, given its
-content, constitutes a covered work. This License acknowledges your
-rights of fair use or other equivalent, as provided by copyright law.
-
- You may make, run and propagate covered works that you do not
-convey, without conditions so long as your license otherwise remains
-in force. You may convey covered works to others for the sole purpose
-of having them make modifications exclusively for you, or provide you
-with facilities for running those works, provided that you comply with
-the terms of this License in conveying all material for which you do
-not control copyright. Those thus making or running the covered works
-for you must do so exclusively on your behalf, under your direction
-and control, on terms that prohibit them from making any copies of
-your copyrighted material outside their relationship with you.
-
- Conveying under any other circumstances is permitted solely under
-the conditions stated below. Sublicensing is not allowed; section 10
-makes it unnecessary.
-
- 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
-
- No covered work shall be deemed part of an effective technological
-measure under any applicable law fulfilling obligations under article
-11 of the WIPO copyright treaty adopted on 20 December 1996, or
-similar laws prohibiting or restricting circumvention of such
-measures.
-
- When you convey a covered work, you waive any legal power to forbid
-circumvention of technological measures to the extent such circumvention
-is effected by exercising rights under this License with respect to
-the covered work, and you disclaim any intention to limit operation or
-modification of the work as a means of enforcing, against the work's
-users, your or third parties' legal rights to forbid circumvention of
-technological measures.
-
- 4. Conveying Verbatim Copies.
-
- You may convey verbatim copies of the Program's source code as you
-receive it, in any medium, provided that you conspicuously and
-appropriately publish on each copy an appropriate copyright notice;
-keep intact all notices stating that this License and any
-non-permissive terms added in accord with section 7 apply to the code;
-keep intact all notices of the absence of any warranty; and give all
-recipients a copy of this License along with the Program.
-
- You may charge any price or no price for each copy that you convey,
-and you may offer support or warranty protection for a fee.
-
- 5. Conveying Modified Source Versions.
-
- You may convey a work based on the Program, or the modifications to
-produce it from the Program, in the form of source code under the
-terms of section 4, provided that you also meet all of these conditions:
-
- a) The work must carry prominent notices stating that you modified
- it, and giving a relevant date.
-
- b) The work must carry prominent notices stating that it is
- released under this License and any conditions added under section
- 7. This requirement modifies the requirement in section 4 to
- "keep intact all notices".
-
- c) You must license the entire work, as a whole, under this
- License to anyone who comes into possession of a copy. This
- License will therefore apply, along with any applicable section 7
- additional terms, to the whole of the work, and all its parts,
- regardless of how they are packaged. This License gives no
- permission to license the work in any other way, but it does not
- invalidate such permission if you have separately received it.
-
- d) If the work has interactive user interfaces, each must display
- Appropriate Legal Notices; however, if the Program has interactive
- interfaces that do not display Appropriate Legal Notices, your
- work need not make them do so.
-
- A compilation of a covered work with other separate and independent
-works, which are not by their nature extensions of the covered work,
-and which are not combined with it such as to form a larger program,
-in or on a volume of a storage or distribution medium, is called an
-"aggregate" if the compilation and its resulting copyright are not
-used to limit the access or legal rights of the compilation's users
-beyond what the individual works permit. Inclusion of a covered work
-in an aggregate does not cause this License to apply to the other
-parts of the aggregate.
-
- 6. Conveying Non-Source Forms.
-
- You may convey a covered work in object code form under the terms
-of sections 4 and 5, provided that you also convey the
-machine-readable Corresponding Source under the terms of this License,
-in one of these ways:
-
- a) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by the
- Corresponding Source fixed on a durable physical medium
- customarily used for software interchange.
-
- b) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by a
- written offer, valid for at least three years and valid for as
- long as you offer spare parts or customer support for that product
- model, to give anyone who possesses the object code either (1) a
- copy of the Corresponding Source for all the software in the
- product that is covered by this License, on a durable physical
- medium customarily used for software interchange, for a price no
- more than your reasonable cost of physically performing this
- conveying of source, or (2) access to copy the
- Corresponding Source from a network server at no charge.
-
- c) Convey individual copies of the object code with a copy of the
- written offer to provide the Corresponding Source. This
- alternative is allowed only occasionally and noncommercially, and
- only if you received the object code with such an offer, in accord
- with subsection 6b.
-
- d) Convey the object code by offering access from a designated
- place (gratis or for a charge), and offer equivalent access to the
- Corresponding Source in the same way through the same place at no
- further charge. You need not require recipients to copy the
- Corresponding Source along with the object code. If the place to
- copy the object code is a network server, the Corresponding Source
- may be on a different server (operated by you or a third party)
- that supports equivalent copying facilities, provided you maintain
- clear directions next to the object code saying where to find the
- Corresponding Source. Regardless of what server hosts the
- Corresponding Source, you remain obligated to ensure that it is
- available for as long as needed to satisfy these requirements.
-
- e) Convey the object code using peer-to-peer transmission, provided
- you inform other peers where the object code and Corresponding
- Source of the work are being offered to the general public at no
- charge under subsection 6d.
-
- A separable portion of the object code, whose source code is excluded
-from the Corresponding Source as a System Library, need not be
-included in conveying the object code work.
-
- A "User Product" is either (1) a "consumer product", which means any
-tangible personal property which is normally used for personal, family,
-or household purposes, or (2) anything designed or sold for incorporation
-into a dwelling. In determining whether a product is a consumer product,
-doubtful cases shall be resolved in favor of coverage. For a particular
-product received by a particular user, "normally used" refers to a
-typical or common use of that class of product, regardless of the status
-of the particular user or of the way in which the particular user
-actually uses, or expects or is expected to use, the product. A product
-is a consumer product regardless of whether the product has substantial
-commercial, industrial or non-consumer uses, unless such uses represent
-the only significant mode of use of the product.
-
- "Installation Information" for a User Product means any methods,
-procedures, authorization keys, or other information required to install
-and execute modified versions of a covered work in that User Product from
-a modified version of its Corresponding Source. The information must
-suffice to ensure that the continued functioning of the modified object
-code is in no case prevented or interfered with solely because
-modification has been made.
-
- If you convey an object code work under this section in, or with, or
-specifically for use in, a User Product, and the conveying occurs as
-part of a transaction in which the right of possession and use of the
-User Product is transferred to the recipient in perpetuity or for a
-fixed term (regardless of how the transaction is characterized), the
-Corresponding Source conveyed under this section must be accompanied
-by the Installation Information. But this requirement does not apply
-if neither you nor any third party retains the ability to install
-modified object code on the User Product (for example, the work has
-been installed in ROM).
-
- The requirement to provide Installation Information does not include a
-requirement to continue to provide support service, warranty, or updates
-for a work that has been modified or installed by the recipient, or for
-the User Product in which it has been modified or installed. Access to a
-network may be denied when the modification itself materially and
-adversely affects the operation of the network or violates the rules and
-protocols for communication across the network.
-
- Corresponding Source conveyed, and Installation Information provided,
-in accord with this section must be in a format that is publicly
-documented (and with an implementation available to the public in
-source code form), and must require no special password or key for
-unpacking, reading or copying.
-
- 7. Additional Terms.
-
- "Additional permissions" are terms that supplement the terms of this
-License by making exceptions from one or more of its conditions.
-Additional permissions that are applicable to the entire Program shall
-be treated as though they were included in this License, to the extent
-that they are valid under applicable law. If additional permissions
-apply only to part of the Program, that part may be used separately
-under those permissions, but the entire Program remains governed by
-this License without regard to the additional permissions.
-
- When you convey a copy of a covered work, you may at your option
-remove any additional permissions from that copy, or from any part of
-it. (Additional permissions may be written to require their own
-removal in certain cases when you modify the work.) You may place
-additional permissions on material, added by you to a covered work,
-for which you have or can give appropriate copyright permission.
-
- Notwithstanding any other provision of this License, for material you
-add to a covered work, you may (if authorized by the copyright holders of
-that material) supplement the terms of this License with terms:
-
- a) Disclaiming warranty or limiting liability differently from the
- terms of sections 15 and 16 of this License; or
-
- b) Requiring preservation of specified reasonable legal notices or
- author attributions in that material or in the Appropriate Legal
- Notices displayed by works containing it; or
-
- c) Prohibiting misrepresentation of the origin of that material, or
- requiring that modified versions of such material be marked in
- reasonable ways as different from the original version; or
-
- d) Limiting the use for publicity purposes of names of licensors or
- authors of the material; or
-
- e) Declining to grant rights under trademark law for use of some
- trade names, trademarks, or service marks; or
-
- f) Requiring indemnification of licensors and authors of that
- material by anyone who conveys the material (or modified versions of
- it) with contractual assumptions of liability to the recipient, for
- any liability that these contractual assumptions directly impose on
- those licensors and authors.
-
- All other non-permissive additional terms are considered "further
-restrictions" within the meaning of section 10. If the Program as you
-received it, or any part of it, contains a notice stating that it is
-governed by this License along with a term that is a further
-restriction, you may remove that term. If a license document contains
-a further restriction but permits relicensing or conveying under this
-License, you may add to a covered work material governed by the terms
-of that license document, provided that the further restriction does
-not survive such relicensing or conveying.
-
- If you add terms to a covered work in accord with this section, you
-must place, in the relevant source files, a statement of the
-additional terms that apply to those files, or a notice indicating
-where to find the applicable terms.
-
- Additional terms, permissive or non-permissive, may be stated in the
-form of a separately written license, or stated as exceptions;
-the above requirements apply either way.
-
- 8. Termination.
-
- You may not propagate or modify a covered work except as expressly
-provided under this License. Any attempt otherwise to propagate or
-modify it is void, and will automatically terminate your rights under
-this License (including any patent licenses granted under the third
-paragraph of section 11).
-
- However, if you cease all violation of this License, then your
-license from a particular copyright holder is reinstated (a)
-provisionally, unless and until the copyright holder explicitly and
-finally terminates your license, and (b) permanently, if the copyright
-holder fails to notify you of the violation by some reasonable means
-prior to 60 days after the cessation.
-
- Moreover, your license from a particular copyright holder is
-reinstated permanently if the copyright holder notifies you of the
-violation by some reasonable means, this is the first time you have
-received notice of violation of this License (for any work) from that
-copyright holder, and you cure the violation prior to 30 days after
-your receipt of the notice.
-
- Termination of your rights under this section does not terminate the
-licenses of parties who have received copies or rights from you under
-this License. If your rights have been terminated and not permanently
-reinstated, you do not qualify to receive new licenses for the same
-material under section 10.
-
- 9. Acceptance Not Required for Having Copies.
-
- You are not required to accept this License in order to receive or
-run a copy of the Program. Ancillary propagation of a covered work
-occurring solely as a consequence of using peer-to-peer transmission
-to receive a copy likewise does not require acceptance. However,
-nothing other than this License grants you permission to propagate or
-modify any covered work. These actions infringe copyright if you do
-not accept this License. Therefore, by modifying or propagating a
-covered work, you indicate your acceptance of this License to do so.
-
- 10. Automatic Licensing of Downstream Recipients.
-
- Each time you convey a covered work, the recipient automatically
-receives a license from the original licensors, to run, modify and
-propagate that work, subject to this License. You are not responsible
-for enforcing compliance by third parties with this License.
-
- An "entity transaction" is a transaction transferring control of an
-organization, or substantially all assets of one, or subdividing an
-organization, or merging organizations. If propagation of a covered
-work results from an entity transaction, each party to that
-transaction who receives a copy of the work also receives whatever
-licenses to the work the party's predecessor in interest had or could
-give under the previous paragraph, plus a right to possession of the
-Corresponding Source of the work from the predecessor in interest, if
-the predecessor has it or can get it with reasonable efforts.
-
- You may not impose any further restrictions on the exercise of the
-rights granted or affirmed under this License. For example, you may
-not impose a license fee, royalty, or other charge for exercise of
-rights granted under this License, and you may not initiate litigation
-(including a cross-claim or counterclaim in a lawsuit) alleging that
-any patent claim is infringed by making, using, selling, offering for
-sale, or importing the Program or any portion of it.
-
- 11. Patents.
-
- A "contributor" is a copyright holder who authorizes use under this
-License of the Program or a work on which the Program is based. The
-work thus licensed is called the contributor's "contributor version".
-
- A contributor's "essential patent claims" are all patent claims
-owned or controlled by the contributor, whether already acquired or
-hereafter acquired, that would be infringed by some manner, permitted
-by this License, of making, using, or selling its contributor version,
-but do not include claims that would be infringed only as a
-consequence of further modification of the contributor version. For
-purposes of this definition, "control" includes the right to grant
-patent sublicenses in a manner consistent with the requirements of
-this License.
-
- Each contributor grants you a non-exclusive, worldwide, royalty-free
-patent license under the contributor's essential patent claims, to
-make, use, sell, offer for sale, import and otherwise run, modify and
-propagate the contents of its contributor version.
-
- In the following three paragraphs, a "patent license" is any express
-agreement or commitment, however denominated, not to enforce a patent
-(such as an express permission to practice a patent or covenant not to
-sue for patent infringement). To "grant" such a patent license to a
-party means to make such an agreement or commitment not to enforce a
-patent against the party.
-
- If you convey a covered work, knowingly relying on a patent license,
-and the Corresponding Source of the work is not available for anyone
-to copy, free of charge and under the terms of this License, through a
-publicly available network server or other readily accessible means,
-then you must either (1) cause the Corresponding Source to be so
-available, or (2) arrange to deprive yourself of the benefit of the
-patent license for this particular work, or (3) arrange, in a manner
-consistent with the requirements of this License, to extend the patent
-license to downstream recipients. "Knowingly relying" means you have
-actual knowledge that, but for the patent license, your conveying the
-covered work in a country, or your recipient's use of the covered work
-in a country, would infringe one or more identifiable patents in that
-country that you have reason to believe are valid.
-
- If, pursuant to or in connection with a single transaction or
-arrangement, you convey, or propagate by procuring conveyance of, a
-covered work, and grant a patent license to some of the parties
-receiving the covered work authorizing them to use, propagate, modify
-or convey a specific copy of the covered work, then the patent license
-you grant is automatically extended to all recipients of the covered
-work and works based on it.
-
- A patent license is "discriminatory" if it does not include within
-the scope of its coverage, prohibits the exercise of, or is
-conditioned on the non-exercise of one or more of the rights that are
-specifically granted under this License. You may not convey a covered
-work if you are a party to an arrangement with a third party that is
-in the business of distributing software, under which you make payment
-to the third party based on the extent of your activity of conveying
-the work, and under which the third party grants, to any of the
-parties who would receive the covered work from you, a discriminatory
-patent license (a) in connection with copies of the covered work
-conveyed by you (or copies made from those copies), or (b) primarily
-for and in connection with specific products or compilations that
-contain the covered work, unless you entered into that arrangement,
-or that patent license was granted, prior to 28 March 2007.
-
- Nothing in this License shall be construed as excluding or limiting
-any implied license or other defenses to infringement that may
-otherwise be available to you under applicable patent law.
-
- 12. No Surrender of Others' Freedom.
-
- If conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot convey a
-covered work so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you may
-not convey it at all. For example, if you agree to terms that obligate you
-to collect a royalty for further conveying from those to whom you convey
-the Program, the only way you could satisfy both those terms and this
-License would be to refrain entirely from conveying the Program.
-
- 13. Use with the GNU Affero General Public License.
-
- Notwithstanding any other provision of this License, you have
-permission to link or combine any covered work with a work licensed
-under version 3 of the GNU Affero General Public License into a single
-combined work, and to convey the resulting work. The terms of this
-License will continue to apply to the part which is the covered work,
-but the special requirements of the GNU Affero General Public License,
-section 13, concerning interaction through a network will apply to the
-combination as such.
-
- 14. Revised Versions of this License.
-
- The Free Software Foundation may publish revised and/or new versions of
-the GNU General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
- Each version is given a distinguishing version number. If the
-Program specifies that a certain numbered version of the GNU General
-Public License "or any later version" applies to it, you have the
-option of following the terms and conditions either of that numbered
-version or of any later version published by the Free Software
-Foundation. If the Program does not specify a version number of the
-GNU General Public License, you may choose any version ever published
-by the Free Software Foundation.
-
- If the Program specifies that a proxy can decide which future
-versions of the GNU General Public License can be used, that proxy's
-public statement of acceptance of a version permanently authorizes you
-to choose that version for the Program.
-
- Later license versions may give you additional or different
-permissions. However, no additional obligations are imposed on any
-author or copyright holder as a result of your choosing to follow a
-later version.
-
- 15. Disclaimer of Warranty.
-
- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
-APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
-HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
-OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
-THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
-IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
-ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
- 16. Limitation of Liability.
-
- IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
-THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
-GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
-USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
-DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
-PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
-EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGES.
-
- 17. Interpretation of Sections 15 and 16.
-
- If the disclaimer of warranty and limitation of liability provided
-above cannot be given local legal effect according to their terms,
-reviewing courts shall apply local law that most closely approximates
-an absolute waiver of all civil liability in connection with the
-Program, unless a warranty or assumption of liability accompanies a
-copy of the Program in return for a fee.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-state the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-Also add information on how to contact you by electronic and paper mail.
-
- If the program does terminal interaction, make it output a short
-notice like this when it starts in an interactive mode:
-
- <program> Copyright (C) <year> <name of author>
- This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, your program's commands
-might be different; for a GUI interface, you would use an "about box".
-
- You should also get your employer (if you work as a programmer) or school,
-if any, to sign a "copyright disclaimer" for the program, if necessary.
-For more information on this, and how to apply and follow the GNU GPL, see
-<http://www.gnu.org/licenses/>.
-
- The GNU General Public License does not permit incorporating your program
-into proprietary programs. If your program is a subroutine library, you
-may consider it more useful to permit linking proprietary applications with
-the library. If this is what you want to do, use the GNU Lesser General
-Public License instead of this License. But first, please read
-<http://www.gnu.org/philosophy/why-not-lgpl.html>.
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<configuration>
- <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
- <encoder>
- <Pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg %n
- </Pattern>
- </encoder>
- <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
- <level>TRACE</level>
- </filter>
- </appender>
-
- <logger name="com.codesrc.scsi2sd" additivity="false">
- <level value="DEBUG" />
- <appender-ref ref="consoleAppender" />
- </logger>
-
- <root>
- <level value="INFO" />
- <appender-ref ref="consoleAppender" />
- </root>
-</configuration>