From ef741d8f41f5281644d066d7448def53b3e6474a Mon Sep 17 00:00:00 2001 From: Dejan Pekter Date: Sat, 20 Aug 2016 13:52:59 +0200 Subject: [PATCH 01/75] Initial commit --- README.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..66568c5 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# raspberrypi-thermocycler +After working for couple of months on arduino-thermocycler, we turned to Raspberry Pi to have more powerful machine and easier development in Java. From 6a2958ed289d2776071b96a927cc51c1288316e6 Mon Sep 17 00:00:00 2001 From: Dejan Pekter Date: Sat, 20 Aug 2016 14:26:46 +0200 Subject: [PATCH 02/75] Draft rewrite of Arduino-thermocycler. --- .project | 23 +++ .settings/org.eclipse.core.resources.prefs | 2 + .settings/org.eclipse.jdt.core.prefs | 2 + .settings/org.eclipse.jdt.ui.prefs | 59 +++++++ .settings/org.eclipse.m2e.core.prefs | 4 + pom.xml | 58 +++++++ .../thermocycler/logic/RaspiPinsExtened.java | 8 + .../codlex/thermocycler/logic/Settings.java | 57 +++++++ src/com/codlex/thermocycler/logic/State.java | 5 + .../codlex/thermocycler/logic/StateLogic.java | 134 +++++++++++++++ src/com/codlex/thermocycler/logic/Switch.java | 65 ++++++++ .../thermocycler/logic/Thermocycler.java | 139 ++++++++++++++++ .../logic/ThermocyclerWorker.java | 43 +++++ .../codlex/thermocycler/logic/Translator.java | 79 +++++++++ .../codlex/thermocycler/logic/bath/Bath.java | 84 ++++++++++ .../thermocycler/logic/bath/BathFactory.java | 15 ++ .../thermocycler/logic/bath/WaterPump.java | 24 +++ .../logic/bath/cold/ColdBath.java | 65 ++++++++ .../thermocycler/logic/bath/cold/Cooler.java | 25 +++ .../thermocycler/logic/bath/hot/Heater.java | 25 +++ .../thermocycler/logic/bath/hot/HotBath.java | 46 ++++++ .../logic/bath/sensors/LevelSensor.java | 32 ++++ .../logic/bath/sensors/TemperatureSensor.java | 26 +++ .../thermocycler/view/TestController.java | 32 ++++ .../codlex/thermocycler/view/TestScene.fxml | 95 +++++++++++ .../thermocycler/view/ThermocyclerGUI.java | 88 ++++++++++ src/to_rewrite/DallasSensorDS18B20.java | 108 +++++++++++++ src/to_rewrite/DistanceMonitor.java | 153 ++++++++++++++++++ src/to_rewrite/PhysicalQuantity.java | 36 +++++ src/to_rewrite/Sensor.java | 78 +++++++++ src/to_rewrite/Sensors.java | 114 +++++++++++++ .../thermocycler/logic/RaspiPinsExtened.class | Bin 0 -> 547 bytes .../codlex/thermocycler/logic/Settings.class | Bin 0 -> 2110 bytes .../com/codlex/thermocycler/logic/State.class | Bin 0 -> 1154 bytes .../thermocycler/logic/StateLogic.class | Bin 0 -> 4277 bytes .../logic/Switch$SwitchState.class | Bin 0 -> 1208 bytes .../codlex/thermocycler/logic/Switch.class | Bin 0 -> 2210 bytes .../thermocycler/logic/Thermocycler.class | Bin 0 -> 4172 bytes .../logic/ThermocyclerWorker.class | Bin 0 -> 1887 bytes .../thermocycler/logic/Translator.class | Bin 0 -> 2500 bytes .../codlex/thermocycler/logic/bath/Bath.class | Bin 0 -> 3080 bytes .../thermocycler/logic/bath/BathFactory.class | Bin 0 -> 685 bytes .../thermocycler/logic/bath/WaterPump.class | Bin 0 -> 872 bytes .../logic/bath/cold/ColdBath.class | Bin 0 -> 2747 bytes .../thermocycler/logic/bath/cold/Cooler.class | Bin 0 -> 877 bytes .../thermocycler/logic/bath/hot/Heater.class | Bin 0 -> 875 bytes .../thermocycler/logic/bath/hot/HotBath.class | Bin 0 -> 2599 bytes .../logic/bath/sensors/LevelSensor.class | Bin 0 -> 1456 bytes .../bath/sensors/TemperatureSensor.class | Bin 0 -> 1303 bytes .../thermocycler/view/TestController.class | Bin 0 -> 1563 bytes .../codlex/thermocycler/view/TestScene.fxml | 95 +++++++++++ .../thermocycler/view/ThermocyclerGUI.class | Bin 0 -> 2156 bytes .../to_rewrite/DallasSensorDS18B20.class | Bin 0 -> 2711 bytes .../DistanceMonitor$TimeoutException.class | Bin 0 -> 601 bytes .../classes/to_rewrite/DistanceMonitor.class | Bin 0 -> 3819 bytes .../classes/to_rewrite/PhysicalQuantity.class | Bin 0 -> 1019 bytes target/classes/to_rewrite/Sensor.class | Bin 0 -> 345 bytes target/classes/to_rewrite/Sensors.class | Bin 0 -> 4866 bytes 58 files changed, 1819 insertions(+) create mode 100644 .project create mode 100644 .settings/org.eclipse.core.resources.prefs create mode 100644 .settings/org.eclipse.jdt.core.prefs create mode 100644 .settings/org.eclipse.jdt.ui.prefs create mode 100644 .settings/org.eclipse.m2e.core.prefs create mode 100644 pom.xml create mode 100644 src/com/codlex/thermocycler/logic/RaspiPinsExtened.java create mode 100644 src/com/codlex/thermocycler/logic/Settings.java create mode 100644 src/com/codlex/thermocycler/logic/State.java create mode 100644 src/com/codlex/thermocycler/logic/StateLogic.java create mode 100644 src/com/codlex/thermocycler/logic/Switch.java create mode 100644 src/com/codlex/thermocycler/logic/Thermocycler.java create mode 100644 src/com/codlex/thermocycler/logic/ThermocyclerWorker.java create mode 100644 src/com/codlex/thermocycler/logic/Translator.java create mode 100644 src/com/codlex/thermocycler/logic/bath/Bath.java create mode 100644 src/com/codlex/thermocycler/logic/bath/BathFactory.java create mode 100644 src/com/codlex/thermocycler/logic/bath/WaterPump.java create mode 100644 src/com/codlex/thermocycler/logic/bath/cold/ColdBath.java create mode 100644 src/com/codlex/thermocycler/logic/bath/cold/Cooler.java create mode 100644 src/com/codlex/thermocycler/logic/bath/hot/Heater.java create mode 100644 src/com/codlex/thermocycler/logic/bath/hot/HotBath.java create mode 100644 src/com/codlex/thermocycler/logic/bath/sensors/LevelSensor.java create mode 100644 src/com/codlex/thermocycler/logic/bath/sensors/TemperatureSensor.java create mode 100644 src/com/codlex/thermocycler/view/TestController.java create mode 100644 src/com/codlex/thermocycler/view/TestScene.fxml create mode 100644 src/com/codlex/thermocycler/view/ThermocyclerGUI.java create mode 100644 src/to_rewrite/DallasSensorDS18B20.java create mode 100644 src/to_rewrite/DistanceMonitor.java create mode 100644 src/to_rewrite/PhysicalQuantity.java create mode 100644 src/to_rewrite/Sensor.java create mode 100644 src/to_rewrite/Sensors.java create mode 100644 target/classes/com/codlex/thermocycler/logic/RaspiPinsExtened.class create mode 100644 target/classes/com/codlex/thermocycler/logic/Settings.class create mode 100644 target/classes/com/codlex/thermocycler/logic/State.class create mode 100644 target/classes/com/codlex/thermocycler/logic/StateLogic.class create mode 100644 target/classes/com/codlex/thermocycler/logic/Switch$SwitchState.class create mode 100644 target/classes/com/codlex/thermocycler/logic/Switch.class create mode 100644 target/classes/com/codlex/thermocycler/logic/Thermocycler.class create mode 100644 target/classes/com/codlex/thermocycler/logic/ThermocyclerWorker.class create mode 100644 target/classes/com/codlex/thermocycler/logic/Translator.class create mode 100644 target/classes/com/codlex/thermocycler/logic/bath/Bath.class create mode 100644 target/classes/com/codlex/thermocycler/logic/bath/BathFactory.class create mode 100644 target/classes/com/codlex/thermocycler/logic/bath/WaterPump.class create mode 100644 target/classes/com/codlex/thermocycler/logic/bath/cold/ColdBath.class create mode 100644 target/classes/com/codlex/thermocycler/logic/bath/cold/Cooler.class create mode 100644 target/classes/com/codlex/thermocycler/logic/bath/hot/Heater.class create mode 100644 target/classes/com/codlex/thermocycler/logic/bath/hot/HotBath.class create mode 100644 target/classes/com/codlex/thermocycler/logic/bath/sensors/LevelSensor.class create mode 100644 target/classes/com/codlex/thermocycler/logic/bath/sensors/TemperatureSensor.class create mode 100644 target/classes/com/codlex/thermocycler/view/TestController.class create mode 100644 target/classes/com/codlex/thermocycler/view/TestScene.fxml create mode 100644 target/classes/com/codlex/thermocycler/view/ThermocyclerGUI.class create mode 100644 target/classes/to_rewrite/DallasSensorDS18B20.class create mode 100644 target/classes/to_rewrite/DistanceMonitor$TimeoutException.class create mode 100644 target/classes/to_rewrite/DistanceMonitor.class create mode 100644 target/classes/to_rewrite/PhysicalQuantity.class create mode 100644 target/classes/to_rewrite/Sensor.class create mode 100644 target/classes/to_rewrite/Sensors.class diff --git a/.project b/.project new file mode 100644 index 0000000..b51ffba --- /dev/null +++ b/.project @@ -0,0 +1,23 @@ + + + Thermocycler + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + + diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..99f26c0 --- /dev/null +++ b/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/=UTF-8 diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..4ede96d --- /dev/null +++ b/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning diff --git a/.settings/org.eclipse.jdt.ui.prefs b/.settings/org.eclipse.jdt.ui.prefs new file mode 100644 index 0000000..c29fe85 --- /dev/null +++ b/.settings/org.eclipse.jdt.ui.prefs @@ -0,0 +1,59 @@ +cleanup.add_default_serial_version_id=true +cleanup.add_generated_serial_version_id=false +cleanup.add_missing_annotations=true +cleanup.add_missing_deprecated_annotations=true +cleanup.add_missing_methods=false +cleanup.add_missing_nls_tags=false +cleanup.add_missing_override_annotations=true +cleanup.add_missing_override_annotations_interface_methods=true +cleanup.add_serial_version_id=false +cleanup.always_use_blocks=true +cleanup.always_use_parentheses_in_expressions=false +cleanup.always_use_this_for_non_static_field_access=true +cleanup.always_use_this_for_non_static_method_access=false +cleanup.convert_functional_interfaces=false +cleanup.convert_to_enhanced_for_loop=false +cleanup.correct_indentation=true +cleanup.format_source_code=true +cleanup.format_source_code_changes_only=false +cleanup.insert_inferred_type_arguments=false +cleanup.make_local_variable_final=true +cleanup.make_parameters_final=false +cleanup.make_private_fields_final=true +cleanup.make_type_abstract_if_missing_method=false +cleanup.make_variable_declarations_final=false +cleanup.never_use_blocks=false +cleanup.never_use_parentheses_in_expressions=true +cleanup.organize_imports=true +cleanup.qualify_static_field_accesses_with_declaring_class=false +cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true +cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true +cleanup.qualify_static_member_accesses_with_declaring_class=true +cleanup.qualify_static_method_accesses_with_declaring_class=false +cleanup.remove_private_constructors=true +cleanup.remove_redundant_type_arguments=false +cleanup.remove_trailing_whitespaces=true +cleanup.remove_trailing_whitespaces_all=true +cleanup.remove_trailing_whitespaces_ignore_empty=false +cleanup.remove_unnecessary_casts=true +cleanup.remove_unnecessary_nls_tags=true +cleanup.remove_unused_imports=true +cleanup.remove_unused_local_variables=false +cleanup.remove_unused_private_fields=true +cleanup.remove_unused_private_members=false +cleanup.remove_unused_private_methods=true +cleanup.remove_unused_private_types=true +cleanup.sort_members=true +cleanup.sort_members_all=false +cleanup.use_anonymous_class_creation=false +cleanup.use_blocks=false +cleanup.use_blocks_only_for_return_and_throw=false +cleanup.use_lambda=true +cleanup.use_parentheses_in_expressions=false +cleanup.use_this_for_non_static_field_access=true +cleanup.use_this_for_non_static_field_access_only_if_necessary=false +cleanup.use_this_for_non_static_method_access=false +cleanup.use_this_for_non_static_method_access_only_if_necessary=true +cleanup_profile=_DejanFullCleanup +cleanup_settings_version=2 +eclipse.preferences.version=1 diff --git a/.settings/org.eclipse.m2e.core.prefs b/.settings/org.eclipse.m2e.core.prefs new file mode 100644 index 0000000..f897a7f --- /dev/null +++ b/.settings/org.eclipse.m2e.core.prefs @@ -0,0 +1,4 @@ +activeProfiles= +eclipse.preferences.version=1 +resolveWorkspaceProjects=true +version=1 diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..b4f0eff --- /dev/null +++ b/pom.xml @@ -0,0 +1,58 @@ + + 4.0.0 + + com.codlex + Thermocycler + 0.0.1-SNAPSHOT + jar + + Thermocycler + http://maven.apache.org + + + UTF-8 + + + + + junit + junit + 3.8.1 + test + + + + com.pi4j + pi4j-core + 1.1 + + + + log4j + log4j + 1.2.17 + + + + org.projectlombok + lombok + 0.10.1 + + + + com.google.guava + guava + 19.0 + + + + + + + projectlombok.org + http://projectlombok.org/mavenrepo + + + + diff --git a/src/com/codlex/thermocycler/logic/RaspiPinsExtened.java b/src/com/codlex/thermocycler/logic/RaspiPinsExtened.java new file mode 100644 index 0000000..c07155c --- /dev/null +++ b/src/com/codlex/thermocycler/logic/RaspiPinsExtened.java @@ -0,0 +1,8 @@ +package com.codlex.thermocycler.logic; + +import com.pi4j.io.gpio.Pin; +import com.pi4j.io.gpio.RaspiPin; + +public class RaspiPinsExtened extends RaspiPin { + public static Pin pin = createDigitalPin(40, "GPIO 40"); +} diff --git a/src/com/codlex/thermocycler/logic/Settings.java b/src/com/codlex/thermocycler/logic/Settings.java new file mode 100644 index 0000000..ed83ed1 --- /dev/null +++ b/src/com/codlex/thermocycler/logic/Settings.java @@ -0,0 +1,57 @@ +package com.codlex.thermocycler.logic; + +import com.pi4j.io.gpio.Pin; +import com.pi4j.io.gpio.RaspiPin; + +public class Settings { + + /** + * Bath. + */ + public static int BathMinimumLevel = 50; + public static int BathDepth = 20; + public static int LevelEpsilon = 1; + public static int TemperatureEpsilon = 1; + + /** + * Hot Bath. + */ + public static Pin HotBathLevelEchoPin = RaspiPin.GPIO_01; + public static Pin HotBathLevelTriggerPin = RaspiPin.GPIO_00; + public static Pin HotBathHeaterPin = RaspiPin.GPIO_29; + public static Pin HotBathWaterPump = RaspiPin.GPIO_27; + public static Pin HotBathCirculationWaterPump = RaspiPin.GPIO_25; + + // indices for one wire + + /** + * ColdBath. + */ + public static Pin ColdBathLevelEchoPin = RaspiPin.GPIO_04; + public static Pin ColdBathLevelTriggerPin = RaspiPin.GPIO_03; + public static Pin ColdBathCoolerPin = RaspiPin.GPIO_21; + public static Pin ColdBathWaterPump = RaspiPin.GPIO_23; + + /** + * Translator + */ + public static Pin TranslatorPowerPin = RaspiPin.GPIO_28; + public static Pin TranslatorPulsePin = RaspiPin.GPIO_22; + public static Pin TranslatorToColdDirection = RaspiPin.GPIO_24; + + /** + * Logger. + */ + public static int SDSelectChip = 53; + public static String LogFile = "debug2.log"; + public static boolean LogToFile = true; + public static boolean LogToSerial = true; + + public static String HotBathTemperatureSensor1 = "28-000006cc1f5e"; + public static String HotBathTemperatureSensor2 = "28-0215030e8cff"; + public static String HotBathTemperatureSensor3 = "28-031504074bff"; + public static String ColdBathTemperatureSensor1 = "28-021502e596ff"; + public static String ColdBathTemperatureSensor2 = "28-02150310a9ff"; + public static String ColdBathTemperatureSensorAntifriz = "28-031635f7afff"; + +} diff --git a/src/com/codlex/thermocycler/logic/State.java b/src/com/codlex/thermocycler/logic/State.java new file mode 100644 index 0000000..820c6f3 --- /dev/null +++ b/src/com/codlex/thermocycler/logic/State.java @@ -0,0 +1,5 @@ +package com.codlex.thermocycler.logic; + +public enum State { + NotReady, HotBath, ColdBath, Finished +} diff --git a/src/com/codlex/thermocycler/logic/StateLogic.java b/src/com/codlex/thermocycler/logic/StateLogic.java new file mode 100644 index 0000000..a89b2e6 --- /dev/null +++ b/src/com/codlex/thermocycler/logic/StateLogic.java @@ -0,0 +1,134 @@ +package com.codlex.thermocycler.logic; + +import java.util.concurrent.TimeUnit; + +import lombok.extern.log4j.Log4j; + +@Log4j +public class StateLogic { + + static String StateToString(State state) { + switch (state) { + case NotReady : + return "NotReady"; + case HotBath : + return "HotBath"; + case ColdBath : + return "ColdBath"; + case Finished : + return "Finished"; + default : + return "StateNameNotFound!"; + } + } + Thermocycler thermocycler; + State currentState = State.NotReady; + long time = 0; + + long immersionStart = 0; + + long hotBathImmersionCount = 0; + + long coldBathImmersionCount = 0; + + StateLogic(Thermocycler thermocycler) { + this.thermocycler = thermocycler; + } + + long calculateImmersionTime() { + return this.time - this.immersionStart; + } + + void changeState(State state) { + log.debug("STATE_CHANGE [" + this.currentState.toString() + "] . [" + + state.toString() + "]"); + + this.currentState = state; + switch (state) { + case HotBath : + this.hotBathImmersionCount++; + break; + case ColdBath : + this.coldBathImmersionCount++; + break; + // do nothing for the rest + default : + log.error("EXPECTED HOT OR COLD BATH ONLY"); + } + } + + void doCycle() { + if (this.currentState == State.ColdBath) { + changeState(State.HotBath); + } else { + changeState(State.ColdBath); + } + + // reset start time + this.immersionStart = this.time; + } + + State getCurrentState() { + return this.currentState; + } + long getTargetImmersionTime() { + // ASSERT state in (ColdBath, HotBath) + if (this.currentState == State.ColdBath) { + return TimeUnit.SECONDS.toMillis(this.thermocycler.coldBath.time); + } else { // this.currentState == HotBath + return TimeUnit.SECONDS.toMillis(this.thermocycler.hotBath.time); + } + } + + boolean isLastCycle() { + int targetCycles = this.thermocycler.cycles.get(); + boolean hotFinished = this.hotBathImmersionCount >= targetCycles; + boolean coldFinished = this.coldBathImmersionCount >= targetCycles; + return hotFinished && coldFinished; + } + + void processCycling() { + // ASSERT state in (ColdBath, HotBath) + long currentImmersionTime = calculateImmersionTime(); + if (currentImmersionTime > getTargetImmersionTime()) { + if (!isLastCycle()) { + // reset start time + this.immersionStart = this.time; + + // invert state + doCycle(); + } else { + changeState(State.Finished); + } + } + } + + void processNotReady() { + boolean hotBathReady = this.thermocycler.hotBath.isReady(); + boolean coldBathReady = this.thermocycler.coldBath.isReady(); + if (hotBathReady && coldBathReady) { + this.immersionStart = this.time; + changeState(State.HotBath); + } else { + log.debug("Thermocycler is not ready yet."); + } + } + + void update(long delta) { + this.time += delta; + + switch (this.currentState) { + case NotReady : + processNotReady(); + break; + case HotBath : + processCycling(); + break; + case ColdBath : + processCycling(); + break; + + } + } + +} \ No newline at end of file diff --git a/src/com/codlex/thermocycler/logic/Switch.java b/src/com/codlex/thermocycler/logic/Switch.java new file mode 100644 index 0000000..e1b9264 --- /dev/null +++ b/src/com/codlex/thermocycler/logic/Switch.java @@ -0,0 +1,65 @@ +package com.codlex.thermocycler.logic; + +import com.pi4j.io.gpio.GpioController; +import com.pi4j.io.gpio.GpioFactory; +import com.pi4j.io.gpio.GpioPinDigitalOutput; +import com.pi4j.io.gpio.Pin; +import com.pi4j.io.gpio.PinState; + +public class Switch { + + private enum SwitchState { + On, Off + }; + + static final PinState ON_CURRENT = PinState.HIGH; + static final PinState OFF_CURRENT = PinState.LOW; + + private SwitchState state = SwitchState.Off; + private GpioPinDigitalOutput pin; + private PinState onCurrent; + private PinState offCurrent; + + public Switch(Pin pinNumber) { + this(pinNumber, true); + }; + + public Switch(Pin pinNumber, boolean inverse) { + final GpioController gpio = GpioFactory.getInstance(); + + if (inverse) { + this.onCurrent = OFF_CURRENT; + this.offCurrent = ON_CURRENT; + } else { + this.onCurrent = ON_CURRENT; + this.offCurrent = OFF_CURRENT; + } + + this.pin = gpio.provisionDigitalOutputPin(pinNumber, + getClass().getSimpleName(), this.offCurrent); + }; + + protected void off() { + + } + + protected void on() { + + } + + public void turnOff() { + if (this.state != SwitchState.Off) { + this.state = SwitchState.Off; + this.pin.setState(this.offCurrent); + off(); + } + } + + public void turnOn() { + if (this.state != SwitchState.On) { + this.state = SwitchState.On; + this.pin.setState(this.onCurrent); + on(); + } + } +} diff --git a/src/com/codlex/thermocycler/logic/Thermocycler.java b/src/com/codlex/thermocycler/logic/Thermocycler.java new file mode 100644 index 0000000..0de96f7 --- /dev/null +++ b/src/com/codlex/thermocycler/logic/Thermocycler.java @@ -0,0 +1,139 @@ +package com.codlex.thermocycler.logic; + +import java.util.concurrent.atomic.AtomicBoolean; + +import com.codlex.thermocycler.logic.bath.Bath; + +import javafx.beans.property.IntegerProperty; +import javafx.beans.property.SimpleIntegerProperty; +import lombok.Getter; +import lombok.extern.log4j.Log4j; + +@Log4j +public class Thermocycler { + + static int COLD_TEMPERATURE = 1; + static int COLD_TIME = 2; + + static int HOT_TEMPERATURE = 3; + static int HOT_TIME = 4; + static int CYCLES = 5; + static int START = 6; + static int STARTED = 7; + private StateLogic stateLogic; + private Translator translator; + + Bath coldBath; + Bath hotBath; + + @Getter + final IntegerProperty cycles = new SimpleIntegerProperty(100); + + int start = 0; + + public AtomicBoolean isStarted = new AtomicBoolean(false); + + public Thermocycler() { + // this.stateLogic = new StateLogic(this); + // this.coldBath = BathFactory.createCold(); + // this.hotBath = BathFactory.createHot(); + // this.translator = new Translator(); + } + + void back() { + if (this.isStarted.get()) { + log.error("Thermocycler started, can't go back now."); + return; + } + + // TODO: implement + log.debug("back"); + } + + void confirm() { + if (this.isStarted.get()) { + log.error("Thermocycler started, can't go confirm now."); + return; + } + // TODO: implement + } + + void deleteDigit() { + // TODO: implement + } + + void enterDigit(int digit) { + // TODO: implement + } + + void exit() { + log.debug("exit"); + } + + void init() { + try { + Thread.sleep(1500); + } catch (InterruptedException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + this.translator.goToCold(); + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + this.translator.goToHot(); + try { + Thread.sleep(1500); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + this.translator.erect(); + } + + void logStatus() { + // log.debug("ThermocyclerStatus(state=%s, immersion=%lu ms, + // targetImmersion=%lu ms)", + // StateToString(this.stateLogic.getCurrentState()), + // this.stateLogic.calculateImmersionTime(), + // this.stateLogic.getTargetImmersionTime()); + // this.hotBath.logStatus(); + // this.coldBath.logStatus(); + } + + void reset() { + // TODO: reset everything for next cycling + } + + public void start() { + this.isStarted.set(true); + } + + void update(long deltaT) { + + if (this.isStarted.get()) { + log.debug("############################## CYCLE(hot=" + + this.stateLogic.hotBathImmersionCount + ", cold=" + + this.stateLogic.coldBathImmersionCount + ", total=" + + this.cycles + ") ##############################"); + this.stateLogic.update(deltaT); + this.hotBath.update(deltaT); + this.coldBath.update(deltaT); + this.translator.update(this.stateLogic.getCurrentState()); + logStatus(); + + if (this.stateLogic.getCurrentState() == State.Finished) { + this.isStarted.set(false); + log.debug( + "############################## CYCLING_FINISHED ##############################"); + reset(); + } + } else { + this.hotBath.logStatus(); + this.coldBath.logStatus(); + } + } +} \ No newline at end of file diff --git a/src/com/codlex/thermocycler/logic/ThermocyclerWorker.java b/src/com/codlex/thermocycler/logic/ThermocyclerWorker.java new file mode 100644 index 0000000..f57907a --- /dev/null +++ b/src/com/codlex/thermocycler/logic/ThermocyclerWorker.java @@ -0,0 +1,43 @@ +package com.codlex.thermocycler.logic; + +import lombok.extern.log4j.Log4j; + +@Log4j +public class ThermocyclerWorker implements Runnable { + + public static void start(final Thermocycler thermocycler) { + Thread worker = new Thread(new ThermocyclerWorker(thermocycler)); + worker.start(); + } + + private final Thermocycler thermocycler; + + public ThermocyclerWorker(final Thermocycler thermocycler) { + this.thermocycler = thermocycler; + } + + @Override + public void run() { + log.debug("Thermocycler worker started"); + this.thermocycler.init(); + long lastLoopStart = System.currentTimeMillis(); + while (true) { + long currentMillis = System.currentTimeMillis(); + long deltaT = currentMillis - lastLoopStart; + lastLoopStart = System.currentTimeMillis(); + + this.thermocycler.update(deltaT); + + if (deltaT > 100) { + log.debug("Processing done in " + deltaT + " ms"); + } + + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + log.error(e); + } + } + } + +} diff --git a/src/com/codlex/thermocycler/logic/Translator.java b/src/com/codlex/thermocycler/logic/Translator.java new file mode 100644 index 0000000..5fd2379 --- /dev/null +++ b/src/com/codlex/thermocycler/logic/Translator.java @@ -0,0 +1,79 @@ +package com.codlex.thermocycler.logic; + +public class Translator { + + Switch power = new Switch(Settings.TranslatorPowerPin, false); + Switch toCold = new Switch(Settings.TranslatorToColdDirection); + Switch pulse = new Switch(Settings.TranslatorPulsePin); + + State currentState = State.NotReady; + + public Translator() { + this.power.turnOn(); + } + + void changeState(State state) { + this.currentState = state; + + switch (this.currentState) { + case ColdBath : + goToCold(); + break; + case HotBath : + goToHot(); + break; + } + } + + void erect() { + // assume that state is HotBath + this.power.turnOn(); + this.toCold.turnOn(); + this.pulse.turnOn(); + try { + Thread.sleep(750); + } catch (InterruptedException e) { + e.printStackTrace(); + } + this.pulse.turnOff(); + this.power.turnOff(); + + } + + void goToCold() { + this.power.turnOn(); + this.toCold.turnOn(); + this.pulse.turnOn(); + try { + Thread.sleep(500); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + this.pulse.turnOff(); + } + + void goToHot() { + this.power.turnOn(); + this.toCold.turnOff(); + this.pulse.turnOn(); + try { + Thread.sleep(500); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + this.pulse.turnOff(); + } + + void update(State state) { + + // not_ready . hot_bath + // hot_bath . cold_bath + // cold_bath . hot_bath + // cold_bath . finished + if (state != this.currentState) { + changeState(state); + } + } +} diff --git a/src/com/codlex/thermocycler/logic/bath/Bath.java b/src/com/codlex/thermocycler/logic/bath/Bath.java new file mode 100644 index 0000000..5bacae1 --- /dev/null +++ b/src/com/codlex/thermocycler/logic/bath/Bath.java @@ -0,0 +1,84 @@ +package com.codlex.thermocycler.logic.bath; + +import com.codlex.thermocycler.logic.Settings; +import com.codlex.thermocycler.logic.bath.sensors.LevelSensor; +import com.codlex.thermocycler.logic.bath.sensors.TemperatureSensor; +import com.pi4j.io.gpio.Pin; + +import javafx.beans.property.IntegerProperty; +import javafx.beans.property.SimpleIntegerProperty; +import lombok.extern.log4j.Log4j; + +@Log4j +public abstract class Bath { + + protected TemperatureSensor temperatureSensor1; + + protected TemperatureSensor temperatureSensor2; + + protected IntegerProperty temp = new SimpleIntegerProperty(); + + WaterPump pump; + protected int temperature = 0; + + public long time = 0; + + protected LevelSensor level; + + public Bath(String temperatureSensorIndex1, String temperatureSensorIndex2, + Pin levelEchoPin, Pin levelTriggerPin, Pin waterPumpPin) { + this.temperatureSensor1 = new TemperatureSensor( + temperatureSensorIndex1); // TODO: add addres + this.temperatureSensor2 = new TemperatureSensor( + temperatureSensorIndex2); // TODO: add addres + this.level = new LevelSensor(levelEchoPin, levelTriggerPin, + Settings.BathDepth); + this.pump = new WaterPump(waterPumpPin); + } + + protected float getCurrentTemperature() { + float sum = this.temperatureSensor1.getTemperature(); + sum += this.temperatureSensor2.getTemperature(); + return sum / 2; + } + public boolean isLevelOK() { + int minimumLevel = Settings.BathMinimumLevel - Settings.LevelEpsilon; + return this.level.getPercentageFilled() > minimumLevel; + } + public boolean isReady() { + return isTemperatureOK() && isLevelOK(); + } + + public boolean isTemperatureOK() { + return true; + // float minTemperature = this.temperature - + // Settings.TemperatureEpsilon; + // float maxTemperature = this.temperature + + // Settings.TemperatureEpsilon; + // float currentTemperature = getCurrentTemperature(); + // return minTemperature <= currentTemperature + // && currentTemperature <= maxTemperature; + } + + public void keepLevel() { + int precetage = this.level.getPercentageFilled(); + if (precetage < Settings.BathMinimumLevel) { + log.debug("ukljuceno punjenje! " + precetage); + this.pump.turnOn(); + } else { + log.debug("iskljuceno punjenje!" + precetage); + this.pump.turnOff(); + } + } + + public abstract void keepTemperature(); + + public abstract void logStatus(); + + public void update(long deltaT) { + keepTemperature(); + keepLevel(); + logStatus(); + } + +} diff --git a/src/com/codlex/thermocycler/logic/bath/BathFactory.java b/src/com/codlex/thermocycler/logic/bath/BathFactory.java new file mode 100644 index 0000000..f4e7ea6 --- /dev/null +++ b/src/com/codlex/thermocycler/logic/bath/BathFactory.java @@ -0,0 +1,15 @@ +package com.codlex.thermocycler.logic.bath; + +import com.codlex.thermocycler.logic.bath.cold.ColdBath; +import com.codlex.thermocycler.logic.bath.hot.HotBath; + +public class BathFactory { + public static ColdBath createCold() { + return new ColdBath(); + } + + public static HotBath createHot() { + return new HotBath(); + } + +} diff --git a/src/com/codlex/thermocycler/logic/bath/WaterPump.java b/src/com/codlex/thermocycler/logic/bath/WaterPump.java new file mode 100644 index 0000000..3da296f --- /dev/null +++ b/src/com/codlex/thermocycler/logic/bath/WaterPump.java @@ -0,0 +1,24 @@ +package com.codlex.thermocycler.logic.bath; + +import com.codlex.thermocycler.logic.Switch; +import com.pi4j.io.gpio.Pin; + +import lombok.extern.log4j.Log4j; + +@Log4j +public class WaterPump extends Switch { + + public WaterPump(Pin pin) { + super(pin); + } + + @Override + public void off() { + log.debug("Pump is turned off."); + } + + @Override + public void on() { + log.debug("Pump is turned on."); + } +} \ No newline at end of file diff --git a/src/com/codlex/thermocycler/logic/bath/cold/ColdBath.java b/src/com/codlex/thermocycler/logic/bath/cold/ColdBath.java new file mode 100644 index 0000000..ebd38d9 --- /dev/null +++ b/src/com/codlex/thermocycler/logic/bath/cold/ColdBath.java @@ -0,0 +1,65 @@ +package com.codlex.thermocycler.logic.bath.cold; + +import com.codlex.thermocycler.logic.Settings; +import com.codlex.thermocycler.logic.bath.Bath; +import com.codlex.thermocycler.logic.bath.sensors.TemperatureSensor; + +import lombok.extern.log4j.Log4j; + +@Log4j +public class ColdBath extends Bath { + + Cooler cooler; + TemperatureSensor antifrizTemperature; + + public ColdBath() { + super(Settings.ColdBathTemperatureSensor1, + Settings.ColdBathTemperatureSensor2, + Settings.ColdBathLevelEchoPin, Settings.ColdBathLevelTriggerPin, + Settings.ColdBathWaterPump); + this.cooler = new Cooler(Settings.ColdBathCoolerPin); + this.antifrizTemperature = new TemperatureSensor( + Settings.ColdBathTemperatureSensorAntifriz); + + this.temperature = 30; + this.time = 9; + } + + @Override + public void keepTemperature() { + if (isTemperatureOK()) { + this.cooler.turnOff(); + return; + } + + // cooler turned on when antifriz temperature goes over + // (wanted_temperature - epsOn) + float epsOn = 1; + boolean turnOn = this.antifrizTemperature + .getTemperature() > this.temperature - epsOn; + + if (turnOn) { + this.cooler.turnOn(); + } + + // cooler turned off when temperature in bath reaches wanted temperature + // OR antifriz temperature goes below (wanted_temperature - epsOff) + float epsOff = 4; + boolean turnOff = this.antifrizTemperature + .getTemperature() < this.temperature - epsOff; + + if (turnOff) { + this.cooler.turnOff(); + } + } + + @Override + public void logStatus() { + log.debug("ColdBathStatus(temp1=" + + this.temperatureSensor1.getTemperature() + ", temp2=" + + this.temperatureSensor2.getTemperature() + ", tempA=" + + this.antifrizTemperature.getTemperature() + ", level=" + + this.level.getPercentageFilled() + ")"); + } + +}; diff --git a/src/com/codlex/thermocycler/logic/bath/cold/Cooler.java b/src/com/codlex/thermocycler/logic/bath/cold/Cooler.java new file mode 100644 index 0000000..41bb96b --- /dev/null +++ b/src/com/codlex/thermocycler/logic/bath/cold/Cooler.java @@ -0,0 +1,25 @@ +package com.codlex.thermocycler.logic.bath.cold; + +import com.codlex.thermocycler.logic.Switch; +import com.pi4j.io.gpio.Pin; + +import lombok.extern.log4j.Log4j; + +@Log4j +public class Cooler extends Switch { + + public Cooler(Pin pin) { + super(pin); + } + + @Override + protected void off() { + log.debug("Cooler is turned off."); + } + + @Override + protected void on() { + log.debug("Cooler is turned on."); + } + +} diff --git a/src/com/codlex/thermocycler/logic/bath/hot/Heater.java b/src/com/codlex/thermocycler/logic/bath/hot/Heater.java new file mode 100644 index 0000000..2265513 --- /dev/null +++ b/src/com/codlex/thermocycler/logic/bath/hot/Heater.java @@ -0,0 +1,25 @@ +package com.codlex.thermocycler.logic.bath.hot; + +import com.codlex.thermocycler.logic.Switch; +import com.pi4j.io.gpio.Pin; + +import lombok.extern.log4j.Log4j; + +@Log4j +public class Heater extends Switch { + + public Heater(Pin pin) { + super(pin); + } + + @Override + protected void off() { + log.debug("Heater is turned off!"); + } + + @Override + protected void on() { + log.debug("Heater is turned on!"); + } + +} diff --git a/src/com/codlex/thermocycler/logic/bath/hot/HotBath.java b/src/com/codlex/thermocycler/logic/bath/hot/HotBath.java new file mode 100644 index 0000000..f481aee --- /dev/null +++ b/src/com/codlex/thermocycler/logic/bath/hot/HotBath.java @@ -0,0 +1,46 @@ +package com.codlex.thermocycler.logic.bath.hot; + +import com.codlex.thermocycler.logic.Settings; +import com.codlex.thermocycler.logic.Switch; +import com.codlex.thermocycler.logic.bath.Bath; + +import lombok.extern.log4j.Log4j; + +@Log4j +public class HotBath extends Bath { + + Heater heater; + Switch circulationWaterPump; + + public HotBath() { + super(Settings.HotBathTemperatureSensor1, + Settings.HotBathTemperatureSensor2, + Settings.HotBathLevelEchoPin, Settings.HotBathLevelTriggerPin, + Settings.HotBathWaterPump); + this.heater = new Heater(Settings.HotBathHeaterPin); + + this.temperature = 30; + this.time = 10; + this.circulationWaterPump = new Switch( + Settings.HotBathCirculationWaterPump); + this.circulationWaterPump.turnOn(); + } + + @Override + public void keepTemperature() { + // TOOD: check this + if (getCurrentTemperature() < this.temperature) { + this.heater.turnOn(); + } else { + this.heater.turnOff(); + } + } + + @Override + public void logStatus() { + log.debug("HotBathStatus(temp1=" + + this.temperatureSensor1.getTemperature() + ", temp2=" + + this.temperatureSensor2.getTemperature() + ", level=" + + this.level.getPercentageFilled() + ")"); + } +} \ No newline at end of file diff --git a/src/com/codlex/thermocycler/logic/bath/sensors/LevelSensor.java b/src/com/codlex/thermocycler/logic/bath/sensors/LevelSensor.java new file mode 100644 index 0000000..971f4ad --- /dev/null +++ b/src/com/codlex/thermocycler/logic/bath/sensors/LevelSensor.java @@ -0,0 +1,32 @@ +package com.codlex.thermocycler.logic.bath.sensors; + +import com.pi4j.io.gpio.Pin; + +import lombok.extern.log4j.Log4j; +import to_rewrite.DistanceMonitor; +import to_rewrite.DistanceMonitor.TimeoutException; + +@Log4j +public class LevelSensor { + + private int emptyDistance; + private final DistanceMonitor distanceMonitor; + + public LevelSensor(Pin echoPin, Pin triggerPin, int emptyDistance) { + this.distanceMonitor = new DistanceMonitor(echoPin, triggerPin); + this.emptyDistance = emptyDistance; + } + + public int getPercentageFilled() { + float distanceFromWater = 0; + try { + distanceFromWater = this.distanceMonitor.measureDistance(); + } catch (final TimeoutException e) { + log.error("Couldn't measure level", e); + } + + float filledCM = this.emptyDistance - distanceFromWater; + return (int) ((filledCM / this.emptyDistance) * 100); + } + +} \ No newline at end of file diff --git a/src/com/codlex/thermocycler/logic/bath/sensors/TemperatureSensor.java b/src/com/codlex/thermocycler/logic/bath/sensors/TemperatureSensor.java new file mode 100644 index 0000000..7e98233 --- /dev/null +++ b/src/com/codlex/thermocycler/logic/bath/sensors/TemperatureSensor.java @@ -0,0 +1,26 @@ +package com.codlex.thermocycler.logic.bath.sensors; + +import java.io.IOException; + +import lombok.extern.log4j.Log4j; +import to_rewrite.Sensor; +import to_rewrite.Sensors; + +@Log4j +public class TemperatureSensor { + + private final Sensor sensor; + + public TemperatureSensor(String sensorAddress) { + this.sensor = Sensors.getSensorById(sensorAddress).get(); + } + + public float getTemperature() { + try { + return this.sensor.getValue().floatValue(); + } catch (IOException e) { + log.error("Couldn't read temperature", e); + return -255; + } + } +} diff --git a/src/com/codlex/thermocycler/view/TestController.java b/src/com/codlex/thermocycler/view/TestController.java new file mode 100644 index 0000000..37d7b94 --- /dev/null +++ b/src/com/codlex/thermocycler/view/TestController.java @@ -0,0 +1,32 @@ +package com.codlex.thermocycler.view; + +import com.codlex.thermocycler.logic.Thermocycler; + +import javafx.fxml.FXML; +import javafx.scene.control.TextField; +import javafx.util.converter.NumberStringConverter; +import lombok.extern.log4j.Log4j; + +@Log4j +public class TestController { + + private Thermocycler thermocycler; + + @FXML + private TextField cycles; + + public void bind() { + this.cycles.textProperty().bindBidirectional( + this.thermocycler.getCycles(), new NumberStringConverter()); + } + + public void setModel(Thermocycler thermocycler) { + this.thermocycler = thermocycler; + } + + @FXML + private void start() { + log.debug("start clicked"); + this.thermocycler.start(); + } +} diff --git a/src/com/codlex/thermocycler/view/TestScene.fxml b/src/com/codlex/thermocycler/view/TestScene.fxml new file mode 100644 index 0000000..abc7619 --- /dev/null +++ b/src/com/codlex/thermocycler/view/TestScene.fxml @@ -0,0 +1,95 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/com/codlex/thermocycler/view/scenes/FillInBathsController.java b/src/com/codlex/thermocycler/view/scenes/FillInBathsController.java new file mode 100644 index 0000000..078ca9f --- /dev/null +++ b/src/com/codlex/thermocycler/view/scenes/FillInBathsController.java @@ -0,0 +1,41 @@ +package com.codlex.thermocycler.view.scenes; + +import com.codlex.thermocycler.logic.Thermocycler; +import com.codlex.thermocycler.logic.bath.sensors.LevelSensor; +import com.codlex.thermocycler.view.ThermocyclerController; + +import javafx.beans.property.IntegerProperty; +import javafx.fxml.FXML; +import javafx.scene.control.Label; +import javafx.scene.control.ProgressBar; +import javafx.util.converter.NumberStringConverter; + +public class FillInBathsController implements ThermocyclerController { + + @FXML + private Label hotBathLevelLabel; + + @FXML + private Label coldBathLevelLabel; + + @FXML + private ProgressBar hotBathLevelProgressBar; + + @FXML + private ProgressBar coldBathLevelProgressBar; + + + public void setModel(Thermocycler thermocycler) { + LevelSensor hotBathLevel = thermocycler.getHotBath().getLevelSensor(); + LevelSensor coldBathLevel = thermocycler.getColdBath().getLevelSensor(); + + bind(hotBathLevel, this.hotBathLevelLabel, this.hotBathLevelProgressBar); + bind(coldBathLevel, this.coldBathLevelLabel, this.coldBathLevelProgressBar); + } + + private static void bind(LevelSensor sensor, Label label, ProgressBar progressBar) { + label.textProperty().bindBidirectional(sensor.getProperty(), new NumberStringConverter()); + progressBar.progressProperty().bindBidirectional(sensor.getDoubleProperty()); + } + +} From 25155ee06398c4ef6345f0852fe38ed82ff83bf0 Mon Sep 17 00:00:00 2001 From: Dejan Pekter Date: Sun, 21 Aug 2016 19:57:18 +0200 Subject: [PATCH 06/75] Added level sensor property for testing. --- .../thermocycler/logic/bath/sensors/LevelSensor.java | 7 +++++-- src/com/codlex/thermocycler/view/RootScene.fxml | 3 ++- src/com/codlex/thermocycler/view/TestController.java | 11 ++++++++++- .../codlex/thermocycler/view/scenes/FillInBaths.fxml | 2 +- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/com/codlex/thermocycler/logic/bath/sensors/LevelSensor.java b/src/com/codlex/thermocycler/logic/bath/sensors/LevelSensor.java index 926c909..0336cae 100644 --- a/src/com/codlex/thermocycler/logic/bath/sensors/LevelSensor.java +++ b/src/com/codlex/thermocycler/logic/bath/sensors/LevelSensor.java @@ -6,6 +6,7 @@ import com.codlex.thermocycler.hardware.Sensor; import com.pi4j.io.gpio.Pin; +import javafx.application.Platform; import javafx.beans.property.DoubleProperty; import javafx.beans.property.IntegerProperty; import javafx.beans.property.SimpleDoubleProperty; @@ -38,8 +39,10 @@ public int getPercentageFilled() { float filledCM = this.emptyDistance - distanceFromWater; int integerValue = (int) ((filledCM / this.emptyDistance) * 100); - this.property.set(integerValue); - this.doubleProperty.set(integerValue / 100.0); + Platform.runLater(() -> { + this.property.set(integerValue); + this.doubleProperty.set(integerValue / 100.0); + }); return property.get(); } diff --git a/src/com/codlex/thermocycler/view/RootScene.fxml b/src/com/codlex/thermocycler/view/RootScene.fxml index b7aedda..d510a28 100644 --- a/src/com/codlex/thermocycler/view/RootScene.fxml +++ b/src/com/codlex/thermocycler/view/RootScene.fxml @@ -7,7 +7,6 @@ - @@ -56,6 +55,7 @@ + - + From b79cb0ce4335e8f13db2523e7459811cf42ad5d5 Mon Sep 17 00:00:00 2001 From: Dejan Pekter Date: Mon, 22 Aug 2016 21:55:12 +0200 Subject: [PATCH 07/75] Implemented sceens: - FillInBaths - FillRefillTanks - PutSpecimen - HotBathConfiguration - ColdBathConfiguration - Turned ThermocyclerController into class with default behavior --- .../codlex/thermocycler/logic/StateLogic.java | 4 +- .../codlex/thermocycler/logic/bath/Bath.java | 31 +++-- .../logic/bath/cold/ColdBath.java | 8 +- .../thermocycler/logic/bath/hot/HotBath.java | 6 +- .../view/ThermocyclerController.java | 56 +++++++- .../thermocycler/view/ThermocyclerGUI.java | 16 ++- .../thermocycler/view/ThermocyclerScene.java | 36 +++++- .../view/scenes/AbstractBathController.java | 109 ++++++++++++++++ .../view/scenes/ColdBathConfiguration.fxml | 121 +++++++++++++++++ .../ColdBathConfigurationController.java | 17 +++ .../thermocycler/view/scenes/FillInBaths.fxml | 6 +- .../view/scenes/FillInBathsController.java | 70 +++++++--- .../view/scenes/FillRefillTanks.fxml | 28 ++++ .../view/scenes/FillRefillTanks.java | 7 + .../view/scenes/HotBathConfiguration.fxml | 122 ++++++++++++++++++ .../HotBathConfigurationController.java | 12 ++ .../thermocycler/view/scenes/PutSpecimen.fxml | 28 ++++ .../thermocycler/view/scenes/PutSpecimen.java | 7 + 18 files changed, 633 insertions(+), 51 deletions(-) create mode 100644 src/com/codlex/thermocycler/view/scenes/AbstractBathController.java create mode 100644 src/com/codlex/thermocycler/view/scenes/ColdBathConfiguration.fxml create mode 100644 src/com/codlex/thermocycler/view/scenes/ColdBathConfigurationController.java create mode 100644 src/com/codlex/thermocycler/view/scenes/FillRefillTanks.fxml create mode 100644 src/com/codlex/thermocycler/view/scenes/FillRefillTanks.java create mode 100644 src/com/codlex/thermocycler/view/scenes/HotBathConfiguration.fxml create mode 100644 src/com/codlex/thermocycler/view/scenes/HotBathConfigurationController.java create mode 100644 src/com/codlex/thermocycler/view/scenes/PutSpecimen.fxml create mode 100644 src/com/codlex/thermocycler/view/scenes/PutSpecimen.java diff --git a/src/com/codlex/thermocycler/logic/StateLogic.java b/src/com/codlex/thermocycler/logic/StateLogic.java index a89b2e6..2cd7ad7 100644 --- a/src/com/codlex/thermocycler/logic/StateLogic.java +++ b/src/com/codlex/thermocycler/logic/StateLogic.java @@ -74,9 +74,9 @@ State getCurrentState() { long getTargetImmersionTime() { // ASSERT state in (ColdBath, HotBath) if (this.currentState == State.ColdBath) { - return TimeUnit.SECONDS.toMillis(this.thermocycler.coldBath.time); + return TimeUnit.SECONDS.toMillis(this.thermocycler.coldBath.time.get()); } else { // this.currentState == HotBath - return TimeUnit.SECONDS.toMillis(this.thermocycler.hotBath.time); + return TimeUnit.SECONDS.toMillis(this.thermocycler.hotBath.time.get()); } } diff --git a/src/com/codlex/thermocycler/logic/bath/Bath.java b/src/com/codlex/thermocycler/logic/bath/Bath.java index 89161cd..ff6a69c 100644 --- a/src/com/codlex/thermocycler/logic/bath/Bath.java +++ b/src/com/codlex/thermocycler/logic/bath/Bath.java @@ -6,6 +6,7 @@ import com.pi4j.io.gpio.Pin; import javafx.beans.property.IntegerProperty; +import javafx.beans.property.Property; import javafx.beans.property.SimpleIntegerProperty; import lombok.extern.log4j.Log4j; @@ -16,12 +17,11 @@ public abstract class Bath { protected TemperatureSensor temperatureSensor2; - protected IntegerProperty temp = new SimpleIntegerProperty(); + private WaterPump pump; - WaterPump pump; - protected int temperature = 0; + protected IntegerProperty temperature = new SimpleIntegerProperty(); - public long time = 0; + public IntegerProperty time = new SimpleIntegerProperty(); protected LevelSensor level; @@ -50,14 +50,13 @@ public boolean isReady() { } public boolean isTemperatureOK() { - return true; - // float minTemperature = this.temperature - - // Settings.TemperatureEpsilon; - // float maxTemperature = this.temperature + - // Settings.TemperatureEpsilon; - // float currentTemperature = getCurrentTemperature(); - // return minTemperature <= currentTemperature - // && currentTemperature <= maxTemperature; + float minTemperature = this.temperature.get() + - Settings.TemperatureEpsilon; + float maxTemperature = this.temperature.get() + + Settings.TemperatureEpsilon; + float currentTemperature = getCurrentTemperature(); + return minTemperature <= currentTemperature + && currentTemperature <= maxTemperature; } public void keepLevel() { @@ -85,4 +84,12 @@ public LevelSensor getLevelSensor() { return this.level; } + public IntegerProperty getTemperatureProperty() { + return this.temperature; + } + + public IntegerProperty getTimeProperty() { + return this.time; + } + } diff --git a/src/com/codlex/thermocycler/logic/bath/cold/ColdBath.java b/src/com/codlex/thermocycler/logic/bath/cold/ColdBath.java index ebd38d9..fa1f35b 100644 --- a/src/com/codlex/thermocycler/logic/bath/cold/ColdBath.java +++ b/src/com/codlex/thermocycler/logic/bath/cold/ColdBath.java @@ -21,8 +21,8 @@ public ColdBath() { this.antifrizTemperature = new TemperatureSensor( Settings.ColdBathTemperatureSensorAntifriz); - this.temperature = 30; - this.time = 9; + this.temperature.set(30); + this.time.set(9); } @Override @@ -36,7 +36,7 @@ public void keepTemperature() { // (wanted_temperature - epsOn) float epsOn = 1; boolean turnOn = this.antifrizTemperature - .getTemperature() > this.temperature - epsOn; + .getTemperature() > this.temperature.get() - epsOn; if (turnOn) { this.cooler.turnOn(); @@ -46,7 +46,7 @@ public void keepTemperature() { // OR antifriz temperature goes below (wanted_temperature - epsOff) float epsOff = 4; boolean turnOff = this.antifrizTemperature - .getTemperature() < this.temperature - epsOff; + .getTemperature() < this.temperature.get() - epsOff; if (turnOff) { this.cooler.turnOff(); diff --git a/src/com/codlex/thermocycler/logic/bath/hot/HotBath.java b/src/com/codlex/thermocycler/logic/bath/hot/HotBath.java index 40bcd5b..f20764a 100644 --- a/src/com/codlex/thermocycler/logic/bath/hot/HotBath.java +++ b/src/com/codlex/thermocycler/logic/bath/hot/HotBath.java @@ -21,8 +21,8 @@ public HotBath() { Settings.HotBathWaterPump); this.heater = new Heater(Settings.HotBathHeaterPin); - this.temperature = 30; - this.time = 10; + this.temperature.set(30); + this.time.set(10); this.circulationWaterPump = HardwareProvider.get().getSwitch(Settings.HotBathCirculationWaterPump); this.circulationWaterPump.turnOn(); } @@ -30,7 +30,7 @@ public HotBath() { @Override public void keepTemperature() { // TOOD: check this - if (getCurrentTemperature() < this.temperature) { + if (getCurrentTemperature() < this.temperature.get()) { this.heater.turnOn(); } else { this.heater.turnOff(); diff --git a/src/com/codlex/thermocycler/view/ThermocyclerController.java b/src/com/codlex/thermocycler/view/ThermocyclerController.java index a409c5b..178ba46 100644 --- a/src/com/codlex/thermocycler/view/ThermocyclerController.java +++ b/src/com/codlex/thermocycler/view/ThermocyclerController.java @@ -2,6 +2,58 @@ import com.codlex.thermocycler.logic.Thermocycler; -public interface ThermocyclerController { - void setModel(Thermocycler thermocycler); +import javafx.fxml.FXML; +import javafx.scene.control.Button; + +public abstract class ThermocyclerController { + protected Thermocycler thermocycler; + protected ThermocyclerGUI gui; + + @FXML + private Button nextButton; + + @FXML + private Button backButton; + + public final void setModel(Thermocycler thermocycler) { + this.thermocycler = thermocycler; + onModelInitialized(); + updateUI(); + } + + public final void setGui(ThermocyclerGUI gui) { + this.gui = gui; + } + + @FXML + protected void onNextClick() { + System.out.println("NEXT CLICKED"); + this.gui.nextScene(); + } + + @FXML + protected void onBackClick() { + this.gui.previousScene(); + } + + protected void onModelInitialized() { + + } + + protected final void updateUI() { + final String VALID_BUTTON_STYLE = "-fx-background-color: green"; + final String INVALID_BUTTON_STYLE = "-fx-background-color: gray"; + boolean isValid = validation(); + this.nextButton.setDisable(!isValid); + this.nextButton.setStyle(isValid ? VALID_BUTTON_STYLE : INVALID_BUTTON_STYLE); + onUpdateUI(); + } + + protected void onUpdateUI() { + + } + + protected boolean validation() { + return true; + } } diff --git a/src/com/codlex/thermocycler/view/ThermocyclerGUI.java b/src/com/codlex/thermocycler/view/ThermocyclerGUI.java index 5f7eb91..a112ede 100644 --- a/src/com/codlex/thermocycler/view/ThermocyclerGUI.java +++ b/src/com/codlex/thermocycler/view/ThermocyclerGUI.java @@ -10,8 +10,6 @@ import javafx.application.Application; import javafx.fxml.FXMLLoader; import javafx.scene.Scene; -import javafx.scene.layout.AnchorPane; -import javafx.scene.layout.HBox; import javafx.scene.layout.Pane; import javafx.stage.Stage; @@ -28,6 +26,8 @@ public static void main(String[] args) { private Thermocycler thermocycler; + private ThermocyclerScene currentScene; + /** * Returns the main stage. * @@ -84,7 +84,13 @@ public void initRootLayout() { private void setScene(ThermocyclerScene scene) { - this.rootLayout.getChildren().set(0, scene.load(this.thermocycler)); + this.currentScene = scene; + Pane pane = scene.load(this.thermocycler, this); + this.rootLayout.getChildren().set(0, pane); + } + + public void nextScene() { + setScene(this.currentScene.nextScene()); } @Override @@ -100,4 +106,8 @@ public void start(Stage primaryStage) { // showPersonOverview(); } + public void previousScene() { + setScene(this.currentScene.previousScene()); + } + } diff --git a/src/com/codlex/thermocycler/view/ThermocyclerScene.java b/src/com/codlex/thermocycler/view/ThermocyclerScene.java index ec68a99..c24bfbd 100644 --- a/src/com/codlex/thermocycler/view/ThermocyclerScene.java +++ b/src/com/codlex/thermocycler/view/ThermocyclerScene.java @@ -10,8 +10,14 @@ @Log4j public enum ThermocyclerScene { - FillInBaths; - + FillInBaths, + FillRefillTanks, + PutSpecimen, + HotBathConfiguration, + ColdBathConfiguration, +// CyclesConfiguration, +// CycingInProgress + ; private final FXMLLoader loader; @@ -21,17 +27,41 @@ private ThermocyclerScene() { } + public ThermocyclerScene previousScene() { + if (!hasPreviousScene()) { + throw new RuntimeException(name() + " doesn't have previous scene!"); + } + + return values()[ordinal() - 1]; + } + + private boolean hasPreviousScene() { + return ordinal() != 0; + } + + public ThermocyclerScene nextScene() { + if (!hasNextScene()) { + throw new RuntimeException(name() + " doesn't have next scene!"); + } + return values()[ordinal() + 1]; + } + + public boolean hasNextScene() { + return ordinal() != values().length - 1; + } + @SuppressWarnings("unchecked") public T getController() { return (T) this.loader.getController(); } - public Pane load(Thermocycler thermocycler) { + public Pane load(Thermocycler thermocycler, ThermocyclerGUI gui) { try { Pane pane = this.loader.load(); ThermocyclerController controller = this.loader.getController(); controller.setModel(thermocycler); + controller.setGui(gui); return pane; } catch (IOException e) { log.debug(e); diff --git a/src/com/codlex/thermocycler/view/scenes/AbstractBathController.java b/src/com/codlex/thermocycler/view/scenes/AbstractBathController.java new file mode 100644 index 0000000..a30cf18 --- /dev/null +++ b/src/com/codlex/thermocycler/view/scenes/AbstractBathController.java @@ -0,0 +1,109 @@ +package com.codlex.thermocycler.view.scenes; + +import com.codlex.thermocycler.logic.bath.Bath; +import com.codlex.thermocycler.view.ThermocyclerController; + +import javafx.beans.property.IntegerProperty; +import javafx.fxml.FXML; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.Slider; + +public abstract class AbstractBathController extends ThermocyclerController { + + @FXML + private Slider temperatureSlider; + + @FXML + private Label temperatureLabel; + + @FXML + private Button minusOneCelzius; + + @FXML + private Button plusOneCelzius; + + @FXML + private Label timeLabel; + + @FXML + private Slider timeSlider; + + @FXML + private Button minusOneSecond; + + @FXML + private Button plusOneSecond; + + private Bath bath; + + @Override + protected void onModelInitialized() { + this.bath = getBath(); + this.temperatureSlider.valueProperty().bindBidirectional(bath.getTemperatureProperty()); + this.bath.getTemperatureProperty().addListener((newValue) -> { + IntegerProperty property = (IntegerProperty) newValue; + Integer value = property.get(); + updateTemperature(value); + updateUI(); + }); + updateTemperature(this.bath.getTemperatureProperty().get()); + + this.timeSlider.valueProperty().bindBidirectional(bath.getTimeProperty()); + this.bath.getTimeProperty().addListener((newValue) -> { + IntegerProperty property = (IntegerProperty) newValue; + Integer value = property.get(); + updateTime(value); + updateUI(); + }); + updateTime(this.bath.getTimeProperty().get()); + } + + protected abstract Bath getBath(); + + private void updateTemperature(Integer value) { + this.temperatureLabel.textProperty().set(String.format("%d°C", value)); + } + + private void updateTime(Integer value) { + this.timeLabel.textProperty().set(String.format("%d:%02d", value / 60, value % 60)); + } + + @Override + protected void onUpdateUI() { + this.minusOneCelzius.setDisable(this.bath.getTemperatureProperty().get() < (int) this.temperatureSlider.getMin() + 1); + this.plusOneCelzius.setDisable(this.bath.getTemperatureProperty().get() > (int) this.temperatureSlider.getMax() - 1); + + this.minusOneSecond.setDisable(this.bath.getTimeProperty().get() < (int) this.timeSlider.getMin() + 1); + this.plusOneSecond.setDisable(this.bath.getTimeProperty().get() > (int) this.timeSlider.getMax() - 1); + + } + + @FXML + private void onMinusOneCelziusClick() { + decrement(this.bath.getTemperatureProperty()); + } + + @FXML + private void onPlusOneCelziusClick() { + increment(this.bath.getTemperatureProperty()); + } + + @FXML + private void onMinusOneSecondClick() { + decrement(this.bath.getTimeProperty()); + } + + @FXML + private void onPlusOneSecondClick() { + increment(this.bath.getTimeProperty()); + } + + private static void increment(IntegerProperty property) { + property.set(property.get() + 1); + } + + private static void decrement(IntegerProperty property) { + property.set(property.get() - 1); + } +} diff --git a/src/com/codlex/thermocycler/view/scenes/ColdBathConfiguration.fxml b/src/com/codlex/thermocycler/view/scenes/ColdBathConfiguration.fxml new file mode 100644 index 0000000..33073cd --- /dev/null +++ b/src/com/codlex/thermocycler/view/scenes/ColdBathConfiguration.fxml @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/com/codlex/thermocycler/view/scenes/ColdBathConfigurationController.java b/src/com/codlex/thermocycler/view/scenes/ColdBathConfigurationController.java new file mode 100644 index 0000000..f760987 --- /dev/null +++ b/src/com/codlex/thermocycler/view/scenes/ColdBathConfigurationController.java @@ -0,0 +1,17 @@ +package com.codlex.thermocycler.view.scenes; + +import com.codlex.thermocycler.logic.bath.Bath; + +public class ColdBathConfigurationController extends AbstractBathController { + + @Override + protected Bath getBath() { + return this.thermocycler.getColdBath(); + } + + + @Override + protected void onNextClick() { + this.thermocycler.start(); + } +} diff --git a/src/com/codlex/thermocycler/view/scenes/FillInBaths.fxml b/src/com/codlex/thermocycler/view/scenes/FillInBaths.fxml index e4dfa0a..0f40ba9 100644 --- a/src/com/codlex/thermocycler/view/scenes/FillInBaths.fxml +++ b/src/com/codlex/thermocycler/view/scenes/FillInBaths.fxml @@ -37,7 +37,7 @@ - + @@ -61,7 +61,7 @@ - + @@ -76,7 +76,7 @@ - + + diff --git a/src/com/codlex/thermocycler/view/scenes/FillRefillTanks.java b/src/com/codlex/thermocycler/view/scenes/FillRefillTanks.java new file mode 100644 index 0000000..a8fcdfc --- /dev/null +++ b/src/com/codlex/thermocycler/view/scenes/FillRefillTanks.java @@ -0,0 +1,7 @@ +package com.codlex.thermocycler.view.scenes; + +import com.codlex.thermocycler.view.ThermocyclerController; + +public class FillRefillTanks extends ThermocyclerController { + +} diff --git a/src/com/codlex/thermocycler/view/scenes/HotBathConfiguration.fxml b/src/com/codlex/thermocycler/view/scenes/HotBathConfiguration.fxml new file mode 100644 index 0000000..6456dbd --- /dev/null +++ b/src/com/codlex/thermocycler/view/scenes/HotBathConfiguration.fxml @@ -0,0 +1,122 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/com/codlex/thermocycler/view/scenes/HotBathConfigurationController.java b/src/com/codlex/thermocycler/view/scenes/HotBathConfigurationController.java new file mode 100644 index 0000000..d677545 --- /dev/null +++ b/src/com/codlex/thermocycler/view/scenes/HotBathConfigurationController.java @@ -0,0 +1,12 @@ +package com.codlex.thermocycler.view.scenes; + +import com.codlex.thermocycler.logic.bath.Bath; + +public class HotBathConfigurationController extends AbstractBathController { + + @Override + protected Bath getBath() { + return this.thermocycler.getHotBath(); + } + +} diff --git a/src/com/codlex/thermocycler/view/scenes/PutSpecimen.fxml b/src/com/codlex/thermocycler/view/scenes/PutSpecimen.fxml new file mode 100644 index 0000000..0e39af4 --- /dev/null +++ b/src/com/codlex/thermocycler/view/scenes/PutSpecimen.fxml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + diff --git a/src/com/codlex/thermocycler/view/scenes/PutSpecimen.java b/src/com/codlex/thermocycler/view/scenes/PutSpecimen.java new file mode 100644 index 0000000..bde79f5 --- /dev/null +++ b/src/com/codlex/thermocycler/view/scenes/PutSpecimen.java @@ -0,0 +1,7 @@ +package com.codlex.thermocycler.view.scenes; + +import com.codlex.thermocycler.view.ThermocyclerController; + +public class PutSpecimen extends ThermocyclerController { + +} From 7f31e0bad007a082104181a4736cb5ed46a1e182 Mon Sep 17 00:00:00 2001 From: Dejan Pekter Date: Tue, 23 Aug 2016 23:09:20 +0200 Subject: [PATCH 08/75] Implemented CyclesConfiguration and ThermocyclerOverview screen. --- .../codlex/thermocycler/logic/bath/Bath.java | 21 ++- .../logic/bath/sensors/TemperatureSensor.java | 6 +- .../view/ThermocyclerController.java | 5 +- .../thermocycler/view/ThermocyclerGUI.java | 6 +- .../thermocycler/view/ThermocyclerScene.java | 3 +- .../ColdBathConfigurationController.java | 6 +- .../view/scenes/CyclesConfiguration.fxml | 166 ++++++++++++++++++ .../view/scenes/CyclesConfiguration.java | 150 ++++++++++++++++ .../view/scenes/ThermocyclerOverview.fxml | 110 ++++++++++++ .../ThermocyclerOverviewController.java | 95 ++++++++++ 10 files changed, 555 insertions(+), 13 deletions(-) create mode 100644 src/com/codlex/thermocycler/view/scenes/CyclesConfiguration.fxml create mode 100644 src/com/codlex/thermocycler/view/scenes/CyclesConfiguration.java create mode 100644 src/com/codlex/thermocycler/view/scenes/ThermocyclerOverview.fxml create mode 100644 src/com/codlex/thermocycler/view/scenes/ThermocyclerOverviewController.java diff --git a/src/com/codlex/thermocycler/logic/bath/Bath.java b/src/com/codlex/thermocycler/logic/bath/Bath.java index ff6a69c..90048ac 100644 --- a/src/com/codlex/thermocycler/logic/bath/Bath.java +++ b/src/com/codlex/thermocycler/logic/bath/Bath.java @@ -5,9 +5,13 @@ import com.codlex.thermocycler.logic.bath.sensors.TemperatureSensor; import com.pi4j.io.gpio.Pin; +import javafx.application.Platform; +import javafx.beans.property.FloatProperty; import javafx.beans.property.IntegerProperty; import javafx.beans.property.Property; +import javafx.beans.property.SimpleFloatProperty; import javafx.beans.property.SimpleIntegerProperty; +import lombok.Getter; import lombok.extern.log4j.Log4j; @Log4j @@ -25,6 +29,9 @@ public abstract class Bath { protected LevelSensor level; + @Getter + private FloatProperty currentTemperatureProperty = new SimpleFloatProperty(); + public Bath(String temperatureSensorIndex1, String temperatureSensorIndex2, Pin levelEchoPin, Pin levelTriggerPin, Pin waterPumpPin) { this.temperatureSensor1 = new TemperatureSensor( @@ -36,11 +43,19 @@ public Bath(String temperatureSensorIndex1, String temperatureSensorIndex2, this.pump = new WaterPump(waterPumpPin); } - protected float getCurrentTemperature() { + public synchronized float getCurrentTemperature() { float sum = this.temperatureSensor1.getTemperature(); sum += this.temperatureSensor2.getTemperature(); - return sum / 2; + float averageTemp = sum / 2; + + Platform.runLater(() -> { + System.out.println("UPDATED!" + averageTemp); + this.currentTemperatureProperty.setValue(averageTemp); + }); + + return averageTemp; } + public boolean isLevelOK() { int minimumLevel = Settings.BathMinimumLevel - Settings.LevelEpsilon; return this.level.getPercentageFilled() > minimumLevel; @@ -75,6 +90,8 @@ public void keepLevel() { public abstract void logStatus(); public void update(long deltaT) { + //TODO: fix this, this is to initialize values + getCurrentTemperature(); keepTemperature(); keepLevel(); logStatus(); diff --git a/src/com/codlex/thermocycler/logic/bath/sensors/TemperatureSensor.java b/src/com/codlex/thermocycler/logic/bath/sensors/TemperatureSensor.java index 8fdce79..ba127b8 100644 --- a/src/com/codlex/thermocycler/logic/bath/sensors/TemperatureSensor.java +++ b/src/com/codlex/thermocycler/logic/bath/sensors/TemperatureSensor.java @@ -5,11 +5,14 @@ import com.codlex.thermocycler.hardware.HardwareProvider; import com.codlex.thermocycler.hardware.Sensor; +import javafx.beans.property.FloatProperty; +import javafx.beans.property.SimpleFloatProperty; +import lombok.Getter; import lombok.extern.log4j.Log4j; @Log4j public class TemperatureSensor { - + private final Sensor sensor; public TemperatureSensor(String sensorAddress) { @@ -19,6 +22,7 @@ public TemperatureSensor(String sensorAddress) { public float getTemperature() { try { return this.sensor.getValue().floatValue(); + } catch (IOException e) { log.error("Couldn't read temperature", e); return -255; diff --git a/src/com/codlex/thermocycler/view/ThermocyclerController.java b/src/com/codlex/thermocycler/view/ThermocyclerController.java index 178ba46..5efb91d 100644 --- a/src/com/codlex/thermocycler/view/ThermocyclerController.java +++ b/src/com/codlex/thermocycler/view/ThermocyclerController.java @@ -10,10 +10,10 @@ public abstract class ThermocyclerController { protected ThermocyclerGUI gui; @FXML - private Button nextButton; + protected Button nextButton; @FXML - private Button backButton; + protected Button backButton; public final void setModel(Thermocycler thermocycler) { this.thermocycler = thermocycler; @@ -27,7 +27,6 @@ public final void setGui(ThermocyclerGUI gui) { @FXML protected void onNextClick() { - System.out.println("NEXT CLICKED"); this.gui.nextScene(); } diff --git a/src/com/codlex/thermocycler/view/ThermocyclerGUI.java b/src/com/codlex/thermocycler/view/ThermocyclerGUI.java index a112ede..00648ba 100644 --- a/src/com/codlex/thermocycler/view/ThermocyclerGUI.java +++ b/src/com/codlex/thermocycler/view/ThermocyclerGUI.java @@ -75,7 +75,7 @@ public void initRootLayout() { controller.setModel(this.thermocycler); controller.bind(); - setScene(ThermocyclerScene.FillInBaths); + setScene(ThermocyclerScene.CyclesConfiguration); } catch (IOException e) { e.printStackTrace(); @@ -86,6 +86,10 @@ public void initRootLayout() { private void setScene(ThermocyclerScene scene) { this.currentScene = scene; Pane pane = scene.load(this.thermocycler, this); + if (pane == null) { + throw new RuntimeException(scene.name() + " couldn't be loaded!"); + } + this.rootLayout.getChildren().set(0, pane); } diff --git a/src/com/codlex/thermocycler/view/ThermocyclerScene.java b/src/com/codlex/thermocycler/view/ThermocyclerScene.java index c24bfbd..56609d4 100644 --- a/src/com/codlex/thermocycler/view/ThermocyclerScene.java +++ b/src/com/codlex/thermocycler/view/ThermocyclerScene.java @@ -15,7 +15,8 @@ public enum ThermocyclerScene { PutSpecimen, HotBathConfiguration, ColdBathConfiguration, -// CyclesConfiguration, + CyclesConfiguration, + ThermocyclerOverview, // CycingInProgress ; diff --git a/src/com/codlex/thermocycler/view/scenes/ColdBathConfigurationController.java b/src/com/codlex/thermocycler/view/scenes/ColdBathConfigurationController.java index f760987..32f701c 100644 --- a/src/com/codlex/thermocycler/view/scenes/ColdBathConfigurationController.java +++ b/src/com/codlex/thermocycler/view/scenes/ColdBathConfigurationController.java @@ -9,9 +9,5 @@ protected Bath getBath() { return this.thermocycler.getColdBath(); } - - @Override - protected void onNextClick() { - this.thermocycler.start(); - } + } diff --git a/src/com/codlex/thermocycler/view/scenes/CyclesConfiguration.fxml b/src/com/codlex/thermocycler/view/scenes/CyclesConfiguration.fxml new file mode 100644 index 0000000..78573f2 --- /dev/null +++ b/src/com/codlex/thermocycler/view/scenes/CyclesConfiguration.fxml @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/com/codlex/thermocycler/view/scenes/CyclesConfiguration.java b/src/com/codlex/thermocycler/view/scenes/CyclesConfiguration.java new file mode 100644 index 0000000..5733400 --- /dev/null +++ b/src/com/codlex/thermocycler/view/scenes/CyclesConfiguration.java @@ -0,0 +1,150 @@ +package com.codlex.thermocycler.view.scenes; + +import java.util.function.Consumer; + +import com.codlex.thermocycler.view.ThermocyclerController; +import com.google.common.collect.ImmutableList; + +import javafx.beans.property.IntegerProperty; +import javafx.fxml.FXML; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.input.MouseEvent; + +public class CyclesConfiguration extends ThermocyclerController { + + @FXML + private Button increment1; + + @FXML + private Button increment10; + + @FXML + private Button increment100; + + @FXML + private Button increment1000; + + @FXML + private Button increment10000; + + @FXML + private Button increment100000; + + @FXML + private Button decrement1; + + @FXML + private Button decrement10; + + @FXML + private Button decrement100; + + @FXML + private Button decrement1000; + + @FXML + private Button decrement10000; + + @FXML + private Button decrement100000; + + @FXML + private Label digit1; + + @FXML + private Label digit10; + + @FXML + private Label digit100; + + @FXML + private Label digit1000; + + @FXML + private Label digit10000; + + @FXML + private Label digit100000; + + private ImmutableList + + diff --git a/src/com/codlex/thermocycler/view/scenes/ThermocyclerOverviewController.java b/src/com/codlex/thermocycler/view/scenes/ThermocyclerOverviewController.java new file mode 100644 index 0000000..ee210a9 --- /dev/null +++ b/src/com/codlex/thermocycler/view/scenes/ThermocyclerOverviewController.java @@ -0,0 +1,95 @@ +package com.codlex.thermocycler.view.scenes; + +import com.codlex.thermocycler.logic.bath.Bath; +import com.codlex.thermocycler.view.ThermocyclerController; + +import javafx.beans.property.StringProperty; +import javafx.fxml.FXML; +import javafx.scene.control.Label; + +public class ThermocyclerOverviewController extends ThermocyclerController { + + @FXML + private Label title; + + @FXML + private Label hotBathTemperature; + + @FXML + private Label coldBathTemperature; + + @FXML + private Label hotBathTime; + + @FXML + private Label coldBathTime; + + @FXML + private Label cycles; + + private boolean isWarmup; + + private static final String temperatureSensorFormat = "%.2f°C / %s"; + + private static final String temperatureFormat = "%d°C"; + + private static final String timeFormat = "%d:%02d"; + + @Override + protected void onModelInitialized() { + this.thermocycler.getColdBath().getCurrentTemperatureProperty().addListener((a) -> { + System.out.println("executed listener"); + + updateUI(); + }); + + this.thermocycler.getHotBath().getCurrentTemperatureProperty().addListener((a) -> { + System.out.println("executed listener"); + + updateUI(); + }); + } + + private String okStyle = "-fx-text-fill: green"; + private String notOkStyle = "-fx-text-fill: red"; + + @Override + protected void onUpdateUI() { + Bath hotBath = this.thermocycler.getHotBath(); + this.hotBathTemperature.textProperty().set(String.format(temperatureFormat, hotBath.getTemperatureProperty().get())); + int hotTime = hotBath.getTimeProperty().get(); + this.hotBathTime.textProperty().set(String.format(timeFormat, hotTime / 60, hotTime % 60)); + + Bath coldBath = this.thermocycler.getColdBath(); + this.coldBathTemperature.textProperty().set(String.format(temperatureFormat, coldBath.getTemperatureProperty().get())); + int coldTime = coldBath.getTimeProperty().get(); + this.coldBathTime.textProperty().set(String.format(timeFormat, coldTime / 60, coldTime % 60)); + + this.cycles.textProperty().set(Integer.toString(this.thermocycler.getCycles().get())); + + if (this.isWarmup) { + System.out.println("executed warmup"); + StringProperty coldBathTemperatureProperty = this.coldBathTemperature.textProperty(); + float currentColdBathTemperature = this.thermocycler.getColdBath().getCurrentTemperatureProperty().get(); + coldBathTemperatureProperty.set(String.format(temperatureSensorFormat, currentColdBathTemperature, coldBathTemperatureProperty.get())); + this.coldBathTemperature.setStyle(coldBath.isTemperatureOK() ? okStyle : notOkStyle); + + StringProperty hotBathTemperatureProperty = this.hotBathTemperature.textProperty(); + float currenthotBathTemperature = this.thermocycler.getHotBath().getCurrentTemperatureProperty().get(); + hotBathTemperatureProperty.set(String.format(temperatureSensorFormat, currenthotBathTemperature, hotBathTemperatureProperty.get())); + this.hotBathTemperature.setStyle(hotBath.isTemperatureOK() ? okStyle : notOkStyle); + + } + } + + @Override + protected void onNextClick() { + this.title.setText("Thermocycler is warming up..."); + this.nextButton.setVisible(false); + this.isWarmup = true; + + updateUI(); + + this.thermocycler.start(); + } +} From 65eb49c53e123bc3901ff092617d8f1178da96ec Mon Sep 17 00:00:00 2001 From: Dejan Pekter Date: Thu, 25 Aug 2016 20:24:08 +0200 Subject: [PATCH 09/75] Fixed scaling of UI. --- .../codlex/thermocycler/view/RootScene.fxml | 13 ++++------ .../thermocycler/view/ThermocyclerGUI.java | 26 ++++++------------- .../thermocycler/view/scenes/FillInBaths.fxml | 4 +-- .../ThermocyclerOverviewController.java | 2 +- 4 files changed, 16 insertions(+), 29 deletions(-) diff --git a/src/com/codlex/thermocycler/view/RootScene.fxml b/src/com/codlex/thermocycler/view/RootScene.fxml index d510a28..ea5c9ca 100644 --- a/src/com/codlex/thermocycler/view/RootScene.fxml +++ b/src/com/codlex/thermocycler/view/RootScene.fxml @@ -7,14 +7,11 @@ - + + - - - - - - + + - + diff --git a/src/com/codlex/thermocycler/view/ThermocyclerGUI.java b/src/com/codlex/thermocycler/view/ThermocyclerGUI.java index 00648ba..b7a63fc 100644 --- a/src/com/codlex/thermocycler/view/ThermocyclerGUI.java +++ b/src/com/codlex/thermocycler/view/ThermocyclerGUI.java @@ -10,6 +10,7 @@ import javafx.application.Application; import javafx.fxml.FXMLLoader; import javafx.scene.Scene; +import javafx.scene.layout.AnchorPane; import javafx.scene.layout.Pane; import javafx.stage.Stage; @@ -37,23 +38,6 @@ public Stage getPrimaryStage() { return this.primaryStage; } - // /** - // * Shows the person overview inside the root layout. - // */ - // public void showPersonOverview() { - // try { - // // Load person overview. - // FXMLLoader loader = new FXMLLoader(); - // loader.setLocation(MainApp.class.getResource("view/PersonOverview.fxml")); - // AnchorPane personOverview = (AnchorPane) loader.load(); - // - // // Set person overview into the center of root layout. - // rootLayout.setCenter(personOverview); - // } catch (IOException e) { - // e.printStackTrace(); - // } - // } - /** * Initializes the root layout. */ @@ -67,6 +51,7 @@ public void initRootLayout() { // Show the scene containing the root layout. Scene scene = new Scene(this.rootLayout); + this.primaryStage.setFullScreen(true); this.primaryStage.setScene(scene); this.primaryStage.show(); @@ -75,7 +60,7 @@ public void initRootLayout() { controller.setModel(this.thermocycler); controller.bind(); - setScene(ThermocyclerScene.CyclesConfiguration); + setScene(ThermocyclerScene.FillInBaths); } catch (IOException e) { e.printStackTrace(); @@ -91,6 +76,11 @@ private void setScene(ThermocyclerScene scene) { } this.rootLayout.getChildren().set(0, pane); + + AnchorPane.setTopAnchor(pane,0.0); + AnchorPane.setBottomAnchor(pane,0.0); + AnchorPane.setLeftAnchor(pane,0.0); + AnchorPane.setRightAnchor(pane, 300.0); } public void nextScene() { diff --git a/src/com/codlex/thermocycler/view/scenes/FillInBaths.fxml b/src/com/codlex/thermocycler/view/scenes/FillInBaths.fxml index 0f40ba9..137a4c5 100644 --- a/src/com/codlex/thermocycler/view/scenes/FillInBaths.fxml +++ b/src/com/codlex/thermocycler/view/scenes/FillInBaths.fxml @@ -6,7 +6,7 @@ - + diff --git a/src/com/codlex/thermocycler/view/scenes/FillRefillTanks.fxml b/src/com/codlex/thermocycler/view/scenes/FillRefillTanks.fxml index 3402062..72d66ed 100644 --- a/src/com/codlex/thermocycler/view/scenes/FillRefillTanks.fxml +++ b/src/com/codlex/thermocycler/view/scenes/FillRefillTanks.fxml @@ -16,13 +16,5 @@ - diff --git a/src/com/codlex/thermocycler/view/scenes/HotBathConfiguration.fxml b/src/com/codlex/thermocycler/view/scenes/HotBathConfiguration.fxml index 6456dbd..c2b31e7 100644 --- a/src/com/codlex/thermocycler/view/scenes/HotBathConfiguration.fxml +++ b/src/com/codlex/thermocycler/view/scenes/HotBathConfiguration.fxml @@ -6,117 +6,101 @@ - - + - - + + + + + + + - - + diff --git a/src/com/codlex/thermocycler/view/scenes/PutSpecimen.fxml b/src/com/codlex/thermocycler/view/scenes/PutSpecimen.fxml index 0e39af4..faa2c7a 100644 --- a/src/com/codlex/thermocycler/view/scenes/PutSpecimen.fxml +++ b/src/com/codlex/thermocycler/view/scenes/PutSpecimen.fxml @@ -16,13 +16,5 @@ - diff --git a/src/com/codlex/thermocycler/view/scenes/Shutdown.fxml b/src/com/codlex/thermocycler/view/scenes/Shutdown.fxml index 9b896c9..74f8402 100644 --- a/src/com/codlex/thermocycler/view/scenes/Shutdown.fxml +++ b/src/com/codlex/thermocycler/view/scenes/Shutdown.fxml @@ -16,13 +16,5 @@ - diff --git a/src/com/codlex/thermocycler/view/scenes/ThermocyclerOverview.fxml b/src/com/codlex/thermocycler/view/scenes/ThermocyclerOverview.fxml index ca9c56f..69602ce 100644 --- a/src/com/codlex/thermocycler/view/scenes/ThermocyclerOverview.fxml +++ b/src/com/codlex/thermocycler/view/scenes/ThermocyclerOverview.fxml @@ -98,13 +98,5 @@ - diff --git a/src/com/codlex/thermocycler/view/scenes/ThermocyclerOverviewController.java b/src/com/codlex/thermocycler/view/scenes/ThermocyclerOverviewController.java index 806f033..1bbaf39 100644 --- a/src/com/codlex/thermocycler/view/scenes/ThermocyclerOverviewController.java +++ b/src/com/codlex/thermocycler/view/scenes/ThermocyclerOverviewController.java @@ -93,6 +93,7 @@ protected void onUpdateUI() { int seconds = this.thermocycler.getTimeLeft() % 60; switch (this.currentState) { case NotStarted: + this.title.setText("Thermocycler overview"); break; case NotReady: this.title.setText("Thermocycler is warming up..."); From a6b2972b1612ec341078b8982a0fc9dd6c5f0aea Mon Sep 17 00:00:00 2001 From: Dejan Pekter Date: Tue, 13 Sep 2016 20:39:59 +0200 Subject: [PATCH 18/75] Fixed time issues. --- .../thermocycler/hardware/DallasSensorDS18B20.java | 2 +- .../thermocycler/hardware/DistanceMonitorImpl.java | 2 +- .../thermocycler/hardware/HardwareProvider.java | 11 +++++------ .../codlex/thermocycler/hardware/RefreshedSensor.java | 9 ++++++--- .../codlex/thermocycler/hardware/VirtualSensors.java | 8 ++++---- src/com/codlex/thermocycler/logic/Settings.java | 8 ++++++-- src/com/codlex/thermocycler/logic/StateLogic.java | 2 +- .../codlex/thermocycler/logic/ThermocyclerWorker.java | 5 +++-- src/com/codlex/thermocycler/view/ThermocyclerGUI.java | 3 ++- 9 files changed, 29 insertions(+), 21 deletions(-) diff --git a/src/com/codlex/thermocycler/hardware/DallasSensorDS18B20.java b/src/com/codlex/thermocycler/hardware/DallasSensorDS18B20.java index eafd8b0..0b3aa03 100644 --- a/src/com/codlex/thermocycler/hardware/DallasSensorDS18B20.java +++ b/src/com/codlex/thermocycler/hardware/DallasSensorDS18B20.java @@ -22,7 +22,7 @@ private static File deriveValueFile(File sensorFile) { private final File valueFile; DallasSensorDS18B20(File sensorFile) { - super(Duration.ofSeconds(Settings.TemperatureRefreshSeconds)); + super(Duration.ofMillis(Settings.TemperatureRefreshMillis)); this.sensorFile = sensorFile; this.valueFile = deriveValueFile(sensorFile); } diff --git a/src/com/codlex/thermocycler/hardware/DistanceMonitorImpl.java b/src/com/codlex/thermocycler/hardware/DistanceMonitorImpl.java index e1d1707..b74bc9a 100644 --- a/src/com/codlex/thermocycler/hardware/DistanceMonitorImpl.java +++ b/src/com/codlex/thermocycler/hardware/DistanceMonitorImpl.java @@ -59,7 +59,7 @@ public String toString() { private final GpioPinDigitalOutput trigPin; DistanceMonitorImpl(Pin echoPin, Pin trigPin) { - super(Duration.ofSeconds(Settings.DistanceRefreshSeconds)); + super(Duration.ofMillis(Settings.DistanceRefreshMillis)); this.echoPin = gpio.provisionDigitalInputPin(echoPin); this.trigPin = gpio.provisionDigitalOutputPin(trigPin); this.trigPin.low(); diff --git a/src/com/codlex/thermocycler/hardware/HardwareProvider.java b/src/com/codlex/thermocycler/hardware/HardwareProvider.java index 97f0dd6..4e06c6d 100644 --- a/src/com/codlex/thermocycler/hardware/HardwareProvider.java +++ b/src/com/codlex/thermocycler/hardware/HardwareProvider.java @@ -1,11 +1,10 @@ package com.codlex.thermocycler.hardware; +import com.codlex.thermocycler.logic.Settings; import com.pi4j.io.gpio.Pin; public class HardwareProvider { - private static final boolean PRODUCTION = false; - private static final HardwareProvider INSTANCE = new HardwareProvider(); public static HardwareProvider get() { @@ -13,7 +12,7 @@ public static HardwareProvider get() { } public Switch getSwitch(Pin pin, boolean inverse) { - if (PRODUCTION) { + if (Settings.Production) { return new SimpleSwitch(pin, inverse); } else { return VirtualSwitches.get().getSwitch(pin); @@ -21,7 +20,7 @@ public Switch getSwitch(Pin pin, boolean inverse) { } public Switch getSwitch(Pin pin) { - if (PRODUCTION) { + if (Settings.Production) { return new SimpleSwitch(pin); } else { return VirtualSwitches.get().getSwitch(pin); @@ -29,7 +28,7 @@ public Switch getSwitch(Pin pin) { } public Sensor getTemperatureSensor(String sensorId) { - if (PRODUCTION) { + if (Settings.Production) { return Sensors.getSensorById(sensorId).get(); } else { return VirtualSensors.get().getTemperatureSensorById(sensorId); @@ -37,7 +36,7 @@ public Sensor getTemperatureSensor(String sensorId) { } public Sensor getDistanceSensorForPins(Pin echo, Pin trigger) { - if (PRODUCTION) { + if (Settings.Production) { return new DistanceMonitorImpl(echo, trigger); } else { return VirtualSensors.get().getDistanceSensor(echo, trigger); diff --git a/src/com/codlex/thermocycler/hardware/RefreshedSensor.java b/src/com/codlex/thermocycler/hardware/RefreshedSensor.java index c5f4678..3046e25 100644 --- a/src/com/codlex/thermocycler/hardware/RefreshedSensor.java +++ b/src/com/codlex/thermocycler/hardware/RefreshedSensor.java @@ -45,9 +45,12 @@ private final void refreshValue() { try { Stopwatch stopwatch = Stopwatch.createStarted(); this.valueContainer.set(recalculateValue()); - log.debug(getClass().getSimpleName() + " took " - + stopwatch.elapsed(TimeUnit.MILLISECONDS) - + " to measure value."); + final int capForLog = 1000; + if (stopwatch.elapsed(TimeUnit.MILLISECONDS) > capForLog) { + log.warn(getClass().getSimpleName() + " took " + + stopwatch.elapsed(TimeUnit.MILLISECONDS) + + " to measure value."); + } } catch (Exception e) { log.error(getClass().getSimpleName() + " failed to recalculate value: ", diff --git a/src/com/codlex/thermocycler/hardware/VirtualSensors.java b/src/com/codlex/thermocycler/hardware/VirtualSensors.java index 0ac9343..d58b29c 100644 --- a/src/com/codlex/thermocycler/hardware/VirtualSensors.java +++ b/src/com/codlex/thermocycler/hardware/VirtualSensors.java @@ -64,7 +64,7 @@ private VirtualSensors() { private void addDistanceMonitor(Pin echo, Pin trigger, FloatProperty distance) { final Pair id = new Pair<>(echo, trigger); - this.distanceMonitors.put(id, new RefreshedSensor(Duration.ofSeconds(Settings.DistanceRefreshSeconds)) { + this.distanceMonitors.put(id, new RefreshedSensor(Duration.ofMillis(Settings.DistanceRefreshMillis)) { @Override public String getID() { @@ -74,7 +74,7 @@ public String getID() { @Override protected Float recalculateValue() throws Exception { // simulate duration of measuring - Thread.sleep(ThreadLocalRandom.current().nextLong(1500)); + // Thread.sleep(ThreadLocalRandom.current().nextLong(1500)); return distance.get(); } @@ -89,7 +89,7 @@ protected Float getDefaultValue() { private void addTemperatureSensor(final String id, final FloatProperty property) { - this.temperatureSensors.put(id, new RefreshedSensor(Duration.ofSeconds(Settings.TemperatureRefreshSeconds)) { + this.temperatureSensors.put(id, new RefreshedSensor(Duration.ofMillis(Settings.TemperatureRefreshMillis)) { @Override public String getID() { @@ -99,7 +99,7 @@ public String getID() { @Override protected Float recalculateValue() throws Exception { // simulate duration of measuring - Thread.sleep(ThreadLocalRandom.current().nextLong(1500)); + // Thread.sleep(ThreadLocalRandom.current().nextLong(1500)); return property.get(); } diff --git a/src/com/codlex/thermocycler/logic/Settings.java b/src/com/codlex/thermocycler/logic/Settings.java index d9e9060..15cd942 100644 --- a/src/com/codlex/thermocycler/logic/Settings.java +++ b/src/com/codlex/thermocycler/logic/Settings.java @@ -5,8 +5,12 @@ public class Settings { - public static int DistanceRefreshSeconds = 10; - public static int TemperatureRefreshSeconds = 1; + public static final boolean Production = true; + public static final boolean FullScreen = true; + public static final long TranslationTimeMillis = 1500; + + public static int DistanceRefreshMillis = 1000; + public static int TemperatureRefreshMillis = 1000; /** * Bath. diff --git a/src/com/codlex/thermocycler/logic/StateLogic.java b/src/com/codlex/thermocycler/logic/StateLogic.java index 3ee3651..7737343 100644 --- a/src/com/codlex/thermocycler/logic/StateLogic.java +++ b/src/com/codlex/thermocycler/logic/StateLogic.java @@ -34,7 +34,7 @@ public class StateLogic { } public long calculateImmersionTime() { - return this.time - this.immersionStart; + return Math.max(this.time - this.immersionStart - Settings.TranslationTimeMillis, 0); } void changeState(final State state) { diff --git a/src/com/codlex/thermocycler/logic/ThermocyclerWorker.java b/src/com/codlex/thermocycler/logic/ThermocyclerWorker.java index f57907a..949ab22 100644 --- a/src/com/codlex/thermocycler/logic/ThermocyclerWorker.java +++ b/src/com/codlex/thermocycler/logic/ThermocyclerWorker.java @@ -29,11 +29,12 @@ public void run() { this.thermocycler.update(deltaT); if (deltaT > 100) { - log.debug("Processing done in " + deltaT + " ms"); + // TODO: fix this it measures whole 500 ms + log.debug("Processing done in " + (deltaT - 500) + " ms"); } try { - Thread.sleep(1000); + Thread.sleep(500); } catch (InterruptedException e) { log.error(e); } diff --git a/src/com/codlex/thermocycler/view/ThermocyclerGUI.java b/src/com/codlex/thermocycler/view/ThermocyclerGUI.java index c61bcfa..7c3c7ef 100644 --- a/src/com/codlex/thermocycler/view/ThermocyclerGUI.java +++ b/src/com/codlex/thermocycler/view/ThermocyclerGUI.java @@ -4,6 +4,7 @@ import org.apache.log4j.BasicConfigurator; +import com.codlex.thermocycler.logic.Settings; import com.codlex.thermocycler.logic.Thermocycler; import com.codlex.thermocycler.logic.ThermocyclerWorker; @@ -55,7 +56,7 @@ public void initRootLayout() { // Show the scene containing the root layout. Scene scene = new Scene(this.rootLayout); - this.primaryStage.setFullScreen(true); + this.primaryStage.setFullScreen(Settings.FullScreen); this.primaryStage.setScene(scene); this.primaryStage.show(); From 8ed3c8c5c01d9292b386ffc67aefb711a1510470 Mon Sep 17 00:00:00 2001 From: Dejan Pekter Date: Tue, 13 Sep 2016 21:19:28 +0200 Subject: [PATCH 19/75] Fixed translator stuff. --- .../thermocycler/logic/Thermocycler.java | 5 +++-- .../codlex/thermocycler/logic/Translator.java | 9 +++++--- .../view/scenes/ShutdownController.java | 21 ++++++++++++++++++- .../ThermocyclerOverviewController.java | 1 - 4 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/com/codlex/thermocycler/logic/Thermocycler.java b/src/com/codlex/thermocycler/logic/Thermocycler.java index cfe2df4..9bef21b 100644 --- a/src/com/codlex/thermocycler/logic/Thermocycler.java +++ b/src/com/codlex/thermocycler/logic/Thermocycler.java @@ -77,7 +77,7 @@ void init() { // TODO Auto-generated catch block e.printStackTrace(); } - this.translator.errect(); + this.translator.errect(State.HotBath); } void logStatus() { @@ -116,6 +116,7 @@ public void update(long deltaT) { this.translator.update(this.stateLogic.getCurrentState()); if (this.stateLogic.getCurrentState() == State.Finished) { + this.translator.errect(State.ColdBath); this.isStarted.set(false); log.debug( "############################## CYCLING_FINISHED ##############################"); @@ -127,7 +128,7 @@ public void update(long deltaT) { } public void lowerTranslator() { - + this.translator.goToHot(); } public boolean lastFinishedSuccessfully() { diff --git a/src/com/codlex/thermocycler/logic/Translator.java b/src/com/codlex/thermocycler/logic/Translator.java index 65679b5..be83650 100644 --- a/src/com/codlex/thermocycler/logic/Translator.java +++ b/src/com/codlex/thermocycler/logic/Translator.java @@ -28,10 +28,13 @@ void changeState(State state) { } } - public void errect() { - // assume that state is HotBath + public void errect(State from) { this.power.turnOn(); - this.toCold.turnOn(); + if (State.HotBath.equals(from)) { + this.toCold.turnOn(); + } else { + this.toCold.turnOff(); + } this.pulse.turnOn(); try { Thread.sleep(750); diff --git a/src/com/codlex/thermocycler/view/scenes/ShutdownController.java b/src/com/codlex/thermocycler/view/scenes/ShutdownController.java index b220a19..cf88644 100644 --- a/src/com/codlex/thermocycler/view/scenes/ShutdownController.java +++ b/src/com/codlex/thermocycler/view/scenes/ShutdownController.java @@ -10,6 +10,7 @@ public class ShutdownController extends ThermocyclerController { @FXML private Label message; + private boolean alreadyClicked; @Override protected String getNextLabel() { @@ -18,8 +19,26 @@ protected String getNextLabel() { @Override protected void onNextClick() { + if (this.alreadyClicked) { + System.exit(0); + } this.thermocycler.lowerTranslator(); this.message.setText("You may now shutdown Thermocycler."); - System.exit(0); + this.alreadyClicked = true; + } + + @Override + protected boolean backValidation() { + return false; + } + + @Override + protected boolean validation() { + return false; + } + + @Override + protected String getBackLabel() { + return ""; } } diff --git a/src/com/codlex/thermocycler/view/scenes/ThermocyclerOverviewController.java b/src/com/codlex/thermocycler/view/scenes/ThermocyclerOverviewController.java index 1bbaf39..eb8ce88 100644 --- a/src/com/codlex/thermocycler/view/scenes/ThermocyclerOverviewController.java +++ b/src/com/codlex/thermocycler/view/scenes/ThermocyclerOverviewController.java @@ -188,7 +188,6 @@ protected void onNextClick() { break; case Finished: this.gui.nextScene(); - this.thermocycler.getTranslator().errect(); break; case UnexpectedShutdown: this.thermocycler.start(); From 710ebc1b08692d4a5b900b4654901ad2413245dd Mon Sep 17 00:00:00 2001 From: Dejan Pekter Date: Tue, 13 Sep 2016 21:48:20 +0200 Subject: [PATCH 20/75] Date estimation machine learning. --- src/com/codlex/thermocycler/logic/Settings.java | 2 +- src/com/codlex/thermocycler/logic/StateLogic.java | 12 ++++++++++++ src/com/codlex/thermocycler/logic/Thermocycler.java | 5 +++++ .../view/scenes/ThermocyclerOverview.fxml | 5 +++++ .../view/scenes/ThermocyclerOverviewController.java | 5 +++++ 5 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/com/codlex/thermocycler/logic/Settings.java b/src/com/codlex/thermocycler/logic/Settings.java index 15cd942..bb01eb7 100644 --- a/src/com/codlex/thermocycler/logic/Settings.java +++ b/src/com/codlex/thermocycler/logic/Settings.java @@ -5,7 +5,7 @@ public class Settings { - public static final boolean Production = true; + public static final boolean Production = false; public static final boolean FullScreen = true; public static final long TranslationTimeMillis = 1500; diff --git a/src/com/codlex/thermocycler/logic/StateLogic.java b/src/com/codlex/thermocycler/logic/StateLogic.java index 7737343..8a90756 100644 --- a/src/com/codlex/thermocycler/logic/StateLogic.java +++ b/src/com/codlex/thermocycler/logic/StateLogic.java @@ -166,4 +166,16 @@ public void reset() { this.hotBathImmersionCount = 0; this.coldBathImmersionCount = 0; } + + public long getFullTimeLeftMillis() { + int hotCyclesLeft = (int) (this.thermocycler.cycles.get() - this.hotBathImmersionCount); + long hotTimeLeft = TimeUnit.SECONDS.toMillis(hotCyclesLeft * this.thermocycler.getHotBath().time.get()); + + int coldCyclesLeft = (int) (this.thermocycler.cycles.get() - this.coldBathImmersionCount); + long coldTimeLeft = TimeUnit.SECONDS.toMillis(coldCyclesLeft * this.thermocycler.getColdBath().time.get()); + + long translatingTime = 2 * (hotCyclesLeft * Settings.TranslationTimeMillis); + + return hotTimeLeft + coldTimeLeft + translatingTime - this.calculateImmersionTime(); + } } \ No newline at end of file diff --git a/src/com/codlex/thermocycler/logic/Thermocycler.java b/src/com/codlex/thermocycler/logic/Thermocycler.java index 9bef21b..7ba0079 100644 --- a/src/com/codlex/thermocycler/logic/Thermocycler.java +++ b/src/com/codlex/thermocycler/logic/Thermocycler.java @@ -1,5 +1,6 @@ package com.codlex.thermocycler.logic; +import java.util.Date; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -152,4 +153,8 @@ public void setCurrentCycle(int lastCycle) { this.stateLogic.coldBathImmersionCount = lastCycle; this.stateLogic.hotBathImmersionCount = lastCycle; } + + public Date getFinishTime() { + return new Date(System.currentTimeMillis() + this.stateLogic.getFullTimeLeftMillis()); + } } \ No newline at end of file diff --git a/src/com/codlex/thermocycler/view/scenes/ThermocyclerOverview.fxml b/src/com/codlex/thermocycler/view/scenes/ThermocyclerOverview.fxml index 69602ce..34c4077 100644 --- a/src/com/codlex/thermocycler/view/scenes/ThermocyclerOverview.fxml +++ b/src/com/codlex/thermocycler/view/scenes/ThermocyclerOverview.fxml @@ -98,5 +98,10 @@ + diff --git a/src/com/codlex/thermocycler/view/scenes/ThermocyclerOverviewController.java b/src/com/codlex/thermocycler/view/scenes/ThermocyclerOverviewController.java index eb8ce88..a123e22 100644 --- a/src/com/codlex/thermocycler/view/scenes/ThermocyclerOverviewController.java +++ b/src/com/codlex/thermocycler/view/scenes/ThermocyclerOverviewController.java @@ -42,6 +42,8 @@ public class ThermocyclerOverviewController extends ThermocyclerController { @FXML private Label cycles; + @FXML + private Label estimateTime; private static final String temperatureSensorFormat = "%.0f°C / %s"; @@ -91,6 +93,9 @@ protected void onUpdateUI() { this.cycles.textProperty().set(Integer.toString(this.thermocycler.getCycles().get())); int minutes = this.thermocycler.getTimeLeft() / 60; int seconds = this.thermocycler.getTimeLeft() % 60; + + this.estimateTime.textProperty().set(this.thermocycler.getFinishTime().toString()); + switch (this.currentState) { case NotStarted: this.title.setText("Thermocycler overview"); From 9404b26b6f98cefae8987ee678b8413a214c6281 Mon Sep 17 00:00:00 2001 From: Dejan Pekter Date: Wed, 14 Sep 2016 20:43:00 +0200 Subject: [PATCH 21/75] Created safety checks. --- .../codlex/thermocycler/logic/Settings.java | 2 + .../thermocycler/logic/Thermocycler.java | 14 +++++++ .../logic/ThermocyclerWorker.java | 39 ++++++++++++++----- .../codlex/thermocycler/logic/bath/Bath.java | 4 ++ .../thermocycler/logic/bath/hot/HotBath.java | 21 ++++++++-- .../thermocycler/view/scenes/MockSensors.fxml | 16 ++++++++ .../view/scenes/MockSensorsController.java | 11 ++++++ 7 files changed, 93 insertions(+), 14 deletions(-) diff --git a/src/com/codlex/thermocycler/logic/Settings.java b/src/com/codlex/thermocycler/logic/Settings.java index bb01eb7..c26bb27 100644 --- a/src/com/codlex/thermocycler/logic/Settings.java +++ b/src/com/codlex/thermocycler/logic/Settings.java @@ -28,6 +28,8 @@ public class Settings { public static Pin HotBathHeaterPin = RaspiPin.GPIO_29; public static Pin HotBathWaterPump = RaspiPin.GPIO_27; public static Pin HotBathCirculationWaterPump = RaspiPin.GPIO_25; + + public static final float HotBathSafetyTemperatureMax = 120; // indices for one wire diff --git a/src/com/codlex/thermocycler/logic/Thermocycler.java b/src/com/codlex/thermocycler/logic/Thermocycler.java index 7ba0079..d24e218 100644 --- a/src/com/codlex/thermocycler/logic/Thermocycler.java +++ b/src/com/codlex/thermocycler/logic/Thermocycler.java @@ -157,4 +157,18 @@ public void setCurrentCycle(int lastCycle) { public Date getFinishTime() { return new Date(System.currentTimeMillis() + this.stateLogic.getFullTimeLeftMillis()); } + + public void performSafetyChecks() { + boolean success = this.hotBath.performSafetyChecks(); + success &= this.coldBath.performSafetyChecks(); + + if (!success) { + log.error("Thermocycler safety check failed, shutting down."); + shutdown(); + } + } + + private void shutdown() { + System.exit(1); + } } \ No newline at end of file diff --git a/src/com/codlex/thermocycler/logic/ThermocyclerWorker.java b/src/com/codlex/thermocycler/logic/ThermocyclerWorker.java index 949ab22..dd118fd 100644 --- a/src/com/codlex/thermocycler/logic/ThermocyclerWorker.java +++ b/src/com/codlex/thermocycler/logic/ThermocyclerWorker.java @@ -1,5 +1,9 @@ package com.codlex.thermocycler.logic; +import java.util.concurrent.TimeUnit; + +import com.google.common.base.Stopwatch; + import lombok.extern.log4j.Log4j; @Log4j @@ -16,21 +20,36 @@ public ThermocyclerWorker(final Thermocycler thermocycler) { this.thermocycler = thermocycler; } + private long lastLoopStart; + + private long pollDeltaT() { + long currentMillis = System.currentTimeMillis(); + long deltaT = currentMillis - lastLoopStart; + this.lastLoopStart = System.currentTimeMillis(); + return deltaT; + } + @Override public void run() { log.debug("Thermocycler worker started"); this.thermocycler.init(); - long lastLoopStart = System.currentTimeMillis(); + this.lastLoopStart = System.currentTimeMillis(); + while (true) { - long currentMillis = System.currentTimeMillis(); - long deltaT = currentMillis - lastLoopStart; - lastLoopStart = System.currentTimeMillis(); - - this.thermocycler.update(deltaT); - - if (deltaT > 100) { - // TODO: fix this it measures whole 500 ms - log.debug("Processing done in " + (deltaT - 500) + " ms"); + try { + Stopwatch stopwatch = Stopwatch.createStarted(); + + this.thermocycler.update(pollDeltaT()); + + long processingTime = stopwatch.elapsed(TimeUnit.MILLISECONDS); + if (processingTime > 10) { + log.error("Processing done in " + processingTime + " ms"); + } + + } catch (Exception e) { + log.error("Exception happened in themrocycler logic: ", e); + } finally { + this.thermocycler.performSafetyChecks(); } try { diff --git a/src/com/codlex/thermocycler/logic/bath/Bath.java b/src/com/codlex/thermocycler/logic/bath/Bath.java index 26b7985..eda7b47 100644 --- a/src/com/codlex/thermocycler/logic/bath/Bath.java +++ b/src/com/codlex/thermocycler/logic/bath/Bath.java @@ -109,4 +109,8 @@ public void update(long deltaT) { logStatus(); } + public boolean performSafetyChecks() { + // default bath doesn't have any security checks + return true; + } } diff --git a/src/com/codlex/thermocycler/logic/bath/hot/HotBath.java b/src/com/codlex/thermocycler/logic/bath/hot/HotBath.java index 01394fd..c9cff30 100644 --- a/src/com/codlex/thermocycler/logic/bath/hot/HotBath.java +++ b/src/com/codlex/thermocycler/logic/bath/hot/HotBath.java @@ -5,26 +5,28 @@ import com.codlex.thermocycler.hardware.Switch; import com.codlex.thermocycler.logic.Settings; import com.codlex.thermocycler.logic.bath.Bath; +import com.codlex.thermocycler.logic.bath.sensors.TemperatureSensor; import lombok.extern.log4j.Log4j; @Log4j public class HotBath extends Bath { - private Heater heater; - private Switch circulationWaterPump; - + private final Heater heater; + private final Switch circulationWaterPump; + private final TemperatureSensor temperatureSensor3; + public HotBath() { super(Settings.HotBathTemperatureSensor1, Settings.HotBathTemperatureSensor2, Settings.HotBathLevelEchoPin, Settings.HotBathLevelTriggerPin, Settings.HotBathWaterPump); this.heater = new Heater(Settings.HotBathHeaterPin); - this.temperature.set(20); this.time.set(1); this.circulationWaterPump = HardwareProvider.get().getSwitch(Settings.HotBathCirculationWaterPump); this.circulationWaterPump.turnOn(); + this.temperatureSensor3 = new TemperatureSensor(Settings.HotBathTemperatureSensor3); } @Override @@ -44,4 +46,15 @@ public void logStatus() { + this.temperatureSensor2.getTemperature() + ", level=" + this.level.getPercentageFilled() + ")"); } + + + @Override + public boolean performSafetyChecks() { + if (this.temperatureSensor3.getTemperature() > Settings.HotBathSafetyTemperatureMax) { + log.error("Safety check failed: maximum safe temperature exceeded, t = " + this.temperatureSensor3.getTemperature()); + return false; + } + + return true; + } } \ No newline at end of file diff --git a/src/com/codlex/thermocycler/view/scenes/MockSensors.fxml b/src/com/codlex/thermocycler/view/scenes/MockSensors.fxml index ac20672..4d9a817 100644 --- a/src/com/codlex/thermocycler/view/scenes/MockSensors.fxml +++ b/src/com/codlex/thermocycler/view/scenes/MockSensors.fxml @@ -46,6 +46,22 @@