diff --git a/server/src/hardware/throttle/throttle.cpp b/server/src/hardware/throttle/throttle.cpp index fdcee79f..959eea99 100644 --- a/server/src/hardware/throttle/throttle.cpp +++ b/server/src/hardware/throttle/throttle.cpp @@ -87,14 +87,21 @@ Throttle::Throttle(World& world, std::string_view _id) return false; }} , stop{*this, "stop", - [this]() + [this](bool immediate) { if(acquired()) { if(train) { train->emergencyStop = false; - train->stop(); + if(immediate) + { + train->setSpeed(*this, 0.0); + } + else + { + train->setTargetSpeed(*this, 0.0); + } } if(m_decoder) { @@ -106,32 +113,50 @@ Throttle::Throttle(World& world, std::string_view _id) return false; }} , faster{*this, "faster", - [this]() + [this](bool immediate) { if(acquired()) { if(train) { - const double value = train->throttleSpeed.value(); - const double step = getValueStep(value, train->throttleSpeed.unit()); train->emergencyStop = false; - train->setTargetSpeed(*this, valueStepUp(value, step)); + if(immediate) + { + const double value = train->speed.value(); + const double step = getValueStep(value, train->speed.unit()); + train->setSpeed(*this, valueStepUp(value, step)); + } + else + { + const double value = train->throttleSpeed.value(); + const double step = getValueStep(value, train->throttleSpeed.unit()); + train->setTargetSpeed(*this, valueStepUp(value, step)); + } } return true; } return false; }} , slower{*this, "slower", - [this]() + [this](bool immediate) { if(acquired()) { if(train) { - const double value = train->throttleSpeed.value(); - const double step = getValueStep(value, train->throttleSpeed.unit()); train->emergencyStop = false; - train->setTargetSpeed(*this, valueStepDown(value, step)); + if(immediate) + { + const double value = train->speed.value(); + const double step = getValueStep(value, train->speed.unit()); + train->setSpeed(*this, valueStepDown(value, step)); + } + else + { + const double value = train->throttleSpeed.value(); + const double step = getValueStep(value, train->throttleSpeed.unit()); + train->setTargetSpeed(*this, valueStepDown(value, step)); + } } return true; } diff --git a/server/src/hardware/throttle/throttle.hpp b/server/src/hardware/throttle/throttle.hpp index dd44971e..615d95f6 100644 --- a/server/src/hardware/throttle/throttle.hpp +++ b/server/src/hardware/throttle/throttle.hpp @@ -72,9 +72,9 @@ class Throttle : public IdObject Property throttle; ObjectProperty train; Method emergencyStop; - Method stop; - Method faster; - Method slower; + Method stop; + Method faster; + Method slower; Method setDirection; #ifndef NDEBUG diff --git a/server/src/network/webthrottleconnection.cpp b/server/src/network/webthrottleconnection.cpp index e6de3309..fabbeefd 100644 --- a/server/src/network/webthrottleconnection.cpp +++ b/server/src/network/webthrottleconnection.cpp @@ -301,15 +301,15 @@ void WebThrottleConnection::processMessage(const nlohmann::json& message) } else if(action == "stop") { - throttle->stop(); + throttle->stop(message.value("immediate", false)); } else if(action == "faster") { - throttle->faster(); + throttle->faster(message.value("immediate", false)); } else if(action == "slower") { - throttle->slower(); + throttle->slower(message.value("immediate", false)); } else if(action == "reverse" || action == "forward") { diff --git a/server/src/train/train.cpp b/server/src/train/train.cpp index 802e0c82..f16ec5df 100644 --- a/server/src/train/train.cpp +++ b/server/src/train/train.cpp @@ -501,6 +501,30 @@ std::error_code Train::release(Throttle& throttle) return {}; } +std::error_code Train::setSpeed(Throttle& throttle, double value) +{ + if(m_throttle.get() != &throttle) + { + return make_error_code(TrainError::InvalidThrottle); + } + assert(active); + + value = std::clamp(value, Attributes::getMin(speed), Attributes::getMax(speed)); + + setSpeed(convertUnit(value, speed.unit(), SpeedUnit::KiloMeterPerHour)); + throttleSpeed.setValue(convertUnit(value, speed.unit(), throttleSpeed.unit())); + m_speedTimer.cancel(); + m_speedState = SpeedState::Idle; + + const bool currentValue = isStopped; + isStopped.setValueInternal(m_speedState == SpeedState::Idle && almostZero(speed.value()) && almostZero(throttleSpeed.value())); + if(currentValue != isStopped) + { + updateEnabled(); + } + return {}; +} + std::error_code Train::setTargetSpeed(Throttle& throttle, double value) { if(m_throttle.get() != &throttle) diff --git a/server/src/train/train.hpp b/server/src/train/train.hpp index 3e75c41e..a2c6e8d4 100644 --- a/server/src/train/train.hpp +++ b/server/src/train/train.hpp @@ -124,6 +124,7 @@ class Train : public IdObject std::string throttleName() const; std::error_code acquire(Throttle& throttle, bool steal = false); std::error_code release(Throttle& throttle); + std::error_code setSpeed(Throttle& throttle, double value); std::error_code setTargetSpeed(Throttle& throttle, double value); std::error_code setDirection(Throttle& throttle, Direction value); diff --git a/server/www/js/throttle.js b/server/www/js/throttle.js index f5beee99..6cf26944 100644 --- a/server/www/js/throttle.js +++ b/server/www/js/throttle.js @@ -35,10 +35,15 @@ function Throttle(parent, id) e.setAttribute('action', action); e.onclick = function () { - tm.send({ + var msg = { 'throttle_id': parseInt(this.getAttribute('throttle-id')), 'action': this.getAttribute('action'), - }); + }; + if(msg.action == 'faster' || msg.action == 'slower' || msg.action == 'stop') + { + msg.immediate = localStorage.immediateSpeedControl != 'false'; + } + tm.send(msg); }; return e; }; @@ -331,6 +336,10 @@ var tm = new function () { document.getElementById('stop_train_on_release').value = localStorage.throttleStopOnRelease; } + if(localStorage.immediateSpeedControl) + { + document.getElementById('immediate_speed_control').value = localStorage.immediateSpeedControl; + } document.getElementById('open_settings').onclick = function () { @@ -348,7 +357,8 @@ var tm = new function () document.getElementById('close_settings').onclick = function () { localStorage.throttleName = document.getElementById('throttle_name').value; - localStorage.throttleStopOnRelease = document.getElementById('stop_train_on_release').value == 'on'; + localStorage.throttleStopOnRelease = document.getElementById('stop_train_on_release').checked; + localStorage.immediateSpeedControl = document.getElementById('immediate_speed_control').checked; document.getElementById('settings').classList.add('hide'); tm.connect(); }; diff --git a/server/www/throttle.html b/server/www/throttle.html index be63e960..92ef5379 100644 --- a/server/www/throttle.html +++ b/server/www/throttle.html @@ -24,6 +24,10 @@ +
+ + +