Setting simulation speed higher should no longer have an effect on logic
[Mograsim.git] / plugins / net.mograsim.logic.model / src / net / mograsim / logic / model / LogicExecuter.java
index a9fde7a..c0cfeb1 100644 (file)
@@ -3,6 +3,7 @@ package net.mograsim.logic.model;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicLong;
 
+import net.mograsim.logic.core.timeline.PauseableTimeFunction;
 import net.mograsim.logic.core.timeline.Timeline;
 
 //TODO maybe move to logic core?
@@ -13,16 +14,21 @@ public class LogicExecuter
 
        private final AtomicBoolean shouldBeRunningLive;
        private final AtomicBoolean isRunningLive;
+       private final AtomicBoolean isPaused;
        private final AtomicLong nextExecSimulTime;
        private final Thread simulationThread;
 
+       PauseableTimeFunction tf;
+
        public LogicExecuter(Timeline timeline)
        {
                this.timeline = timeline;
 
-               timeline.setTimeFunction(System::currentTimeMillis);
+               tf = new PauseableTimeFunction();
+               timeline.setTimeFunction(tf);
                shouldBeRunningLive = new AtomicBoolean();
                isRunningLive = new AtomicBoolean();
+               isPaused = new AtomicBoolean();
                nextExecSimulTime = new AtomicLong();
                simulationThread = new Thread(() ->
                {
@@ -35,19 +41,25 @@ public class LogicExecuter
                        {
                                while (shouldBeRunningLive.get())
                                {
-                                       // always execute to keep timeline from "hanging behind" for too long
-                                       long current = System.currentTimeMillis();
-                                       timeline.executeUntil(timeline.laterThan(current), current + 10);
+                                       long current = tf.getTime();
+                                       timeline.executeUntil(timeline.laterThan(current), System.currentTimeMillis() + 10);
+                                       long nextEventTime = timeline.nextEventTime();
                                        long sleepTime;
                                        if (timeline.hasNext())
-                                               sleepTime = timeline.nextEventTime() - current;
+                                               sleepTime = (long) ((nextEventTime - current) * tf.getSimulTimeToRealTimeFactor());
                                        else
                                                sleepTime = 10000;
                                        try
                                        {
-                                               nextExecSimulTime.set(current + sleepTime);
+                                               nextExecSimulTime.set(nextEventTime);
                                                if (sleepTime > 0)
                                                        Thread.sleep(sleepTime);
+
+                                               synchronized (isPaused)
+                                               {
+                                                       while (isPaused.get())
+                                                               isPaused.wait();
+                                               }
                                        }
                                        catch (@SuppressWarnings("unused") InterruptedException e)
                                        {// do nothing; it is normal execution flow to be interrupted
@@ -69,6 +81,8 @@ public class LogicExecuter
                                if (Timeline.timeCmp(event.getTiming(), nextExecSimulTime.get()) < 0)
                                        simulationThread.interrupt();
                });
+               // not optimal; but we don't expect this to happen very often
+               tf.addSimulTimeToRealTimeFactorChangedListener(d -> simulationThread.interrupt());
        }
 
        public void executeNextStep()
@@ -94,6 +108,35 @@ public class LogicExecuter
                waitForIsRunning(false);
        }
 
+       public void unpauseLiveExecution()
+       {
+               synchronized (isPaused)
+               {
+                       tf.unpause();
+                       isPaused.set(false);
+                       isPaused.notify();
+               }
+       }
+
+       public void pauseLiveExecution()
+       {
+               synchronized (isPaused)
+               {
+                       tf.pause();
+                       isPaused.set(true);
+               }
+       }
+
+       public boolean isPaused()
+       {
+               return isPaused.get();
+       }
+
+       public void setSpeedFactor(double factor)
+       {
+               tf.setSpeedFactor(factor);
+       }
+
        private void waitForIsRunning(boolean expectedState)
        {
                while (isRunningLive.get() ^ expectedState)