diff --git a/Driver.cpp b/Driver.cpp index 6967e5f1..eb44fdf0 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -2226,10 +2226,12 @@ bool TController::PrepareEngine() if (AIControllFlag) { // część wykonawcza dla sterowania przez komputer mvOccupied->BatterySwitch( true ); - if( ( mvOccupied->EngineType == DieselElectric ) - || ( mvOccupied->EngineType == DieselEngine ) ) { - mvOccupied->FuelPumpSwitch( true ); - mvOccupied->OilPumpSwitch( true ); + if( ( mvControlling->EngineType == DieselElectric ) + || ( mvControlling->EngineType == DieselEngine ) ) { + mvControlling->OilPumpSwitch( true ); + if( true == UpdateHeating() ) { + mvControlling->FuelPumpSwitch( true ); + } } if (mvControlling->EnginePowerSource.SourceType == CurrentCollector) { // jeśli silnikowy jest pantografującym @@ -2298,22 +2300,13 @@ bool TController::PrepareEngine() else if (false == mvControlling->Mains) { while (DecSpeed(true)) ; // zerowanie napędu -/* - if( ( mvOccupied->EngineType == DieselEngine ) - || ( mvOccupied->EngineType == DieselElectric ) ) { - // start helper devices before spinning up the engine - // TODO: replace with dedicated diesel engine subsystems - mvOccupied->ConverterSwitch( true ); - mvOccupied->CompressorSwitch( true ); - } -*/ if( mvOccupied->TrainType == dt_SN61 ) { // specjalnie dla SN61 żeby nie zgasł if( mvControlling->RList[ mvControlling->MainCtrlPos ].Mn == 0 ) { mvControlling->IncMainCtrl( 1 ); } } - OK = mvControlling->MainSwitch(true); + mvControlling->MainSwitch(true); /* if (mvControlling->EngineType == DieselEngine) { // Ra 2014-06: dla SN61 trzeba wrzucić pierwszą pozycję - nie wiem, czy tutaj... @@ -2345,6 +2338,7 @@ bool TController::PrepareEngine() } else OK = false; + OK = OK && (mvOccupied->ActiveDir != 0) && (mvControlling->CompressorAllow); if (OK) { @@ -5168,6 +5162,59 @@ TController::UpdateSituation(double dt) { } // switch (OrderList[OrderPos]) } +// configures vehicle heating given current situation; returns: true if vehicle can be operated normally, false otherwise +bool +TController::UpdateHeating() { + + switch( mvControlling->EngineType ) { + + case DieselElectric: + case DieselEngine: { + + auto const &heat { mvControlling->dizel_heat }; + + // determine whether there's need to enable the water heater + // if the heater has configured maximum temperature, it'll disable itself automatically, so we can leave it always running + // otherwise enable the heater only to maintain minimum required temperature + auto const lowtemperature { ( + ( ( heat.water.config.temp_min > 0 ) && ( heat.temperatura1 < heat.water.config.temp_min + ( mvControlling->WaterHeater.is_active ? 5 : 0 ) ) ) + || ( ( heat.water_aux.config.temp_min > 0 ) && ( heat.temperatura2 < heat.water_aux.config.temp_min + ( mvControlling->WaterHeater.is_active ? 5 : 0 ) ) ) + || ( ( heat.oil.config.temp_min > 0 ) && ( heat.To < heat.oil.config.temp_min + ( mvControlling->WaterHeater.is_active ? 5 : 0 ) ) ) ) }; + auto const heateron { ( + ( mvControlling->WaterHeater.config.temp_max > 0 ) + || ( true == lowtemperature ) ) }; + if( true == heateron ) { + // make sure the water pump is running before enabling the heater + if( false == mvControlling->WaterPump.is_active ) { + mvControlling->WaterPumpBreakerSwitch( true ); + mvControlling->WaterPumpSwitch( true ); + } + if( true == mvControlling->WaterPump.is_active ) { + mvControlling->WaterHeaterBreakerSwitch( true ); + mvControlling->WaterHeaterSwitch( true ); + mvControlling->WaterCircuitsLinkSwitch( true ); + } + } + else { + // no need to heat anything up, switch the heater off + mvControlling->WaterCircuitsLinkSwitch( false ); + mvControlling->WaterHeaterSwitch( false ); + mvControlling->WaterHeaterBreakerSwitch( false ); + // optionally turn off the water pump as well + if( mvControlling->WaterPump.start_type != start::battery ) { + mvControlling->WaterPumpSwitch( false ); + mvControlling->WaterPumpBreakerSwitch( false ); + } + } + + return ( false == lowtemperature ); + } + default: { + return true; + } + } +} + void TController::JumpToNextOrder() { // wykonanie kolejnej komendy z tablicy rozkazów if (OrderList[OrderPos] != Wait_for_orders) diff --git a/Driver.h b/Driver.h index aef33df6..214df307 100644 --- a/Driver.h +++ b/Driver.h @@ -318,6 +318,7 @@ private: void PutCommand(std::string NewCommand, double NewValue1, double NewValue2, const TLocation &NewLocation, TStopReason reason = stopComm); bool PutCommand( std::string NewCommand, double NewValue1, double NewValue2, glm::dvec3 const *NewLocation, TStopReason reason = stopComm ); void UpdateSituation(double dt); // uruchamiac przynajmniej raz na sekundę + bool UpdateHeating(); // procedury dotyczace rozkazow dla maszynisty // uaktualnia informacje o prędkości void SetVelocity(double NewVel, double NewVelNext, TStopReason r = stopNone); diff --git a/DynObj.cpp b/DynObj.cpp index f1d3ea43..81b465a5 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -1978,7 +1978,34 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424" if( Random( 0, 100 ) <= flatchance ) { MoverParameters->WheelFlat += fixedflatsize + Random( 0, randomflatsize ); } - } + } // wheel + else if( ( ActPar.size() >= 2 ) + && ( ActPar[ 0 ] == 'T' ) ) { + // temperature + ActPar.erase( 0, 1 ); + + auto setambient { false }; + + while( false == ActPar.empty() ) { + switch( ActPar[ 0 ] ) { + case 'A': { + // cold start, set all temperatures to ambient level + setambient = true; + ActPar.erase( 0, 1 ); + break; + } + default: { + // unrecognized key + ActPar.erase( 0, 1 ); + break; + } + } + } + if( true == setambient ) { + // TODO: pull ambient temperature from environment data + MoverParameters->dizel_HeatSet( 15.f ); + } + } // temperature /* else if (ActPar.substr(0, 1) == "") // tu mozna wpisac inny prefiks i inne rzeczy { // jakies inne prefiksy @@ -2707,7 +2734,7 @@ histerezę czasową, aby te tryby pracy nie przełączały się zbyt szybko. bool TDynamicObject::Update(double dt, double dt1) { - if (dt == 0) + if (dt1 == 0) return true; // Ra: pauza if (!MoverParameters->PhysicActivation && !MechInside) // to drugie, bo będąc w maszynowym blokuje się fizyka @@ -2867,7 +2894,7 @@ bool TDynamicObject::Update(double dt, double dt1) tmpTraction.TractionVoltage = v; } else { - NoVoltTime += dt; + NoVoltTime += dt1; if( NoVoltTime > 0.2 ) { // jeśli brak zasilania dłużej niż 0.2 sekundy (25km/h pod izolatorem daje 0.15s) // Ra 2F1H: prowizorka, trzeba przechować napięcie, żeby nie wywalało WS pod izolatorem diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index 6a2d8bf1..97231ad9 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -165,7 +165,8 @@ enum range { enum start { manual, automatic, - manualwithautofallback + manualwithautofallback, + battery }; // recognized vehicle light locations and types; can be combined enum light { @@ -640,6 +641,78 @@ struct oil_pump { float pressure_present { 0.f }; }; +struct water_pump { + + bool breaker { true }; // device is allowed to operate + bool is_enabled { false }; // device is requested to operate + bool is_active { false }; // device is working + start start_type { start::manual }; +}; + +struct water_heater { + + bool breaker { true }; // device is allowed to operate + bool is_enabled { false }; // device is requested to operate + bool is_active { false }; // device is working + bool is_damaged { false }; // device is damaged + + struct heater_config_t { + float temp_min { -1 }; // lowest accepted temperature + float temp_max { -1 }; // highest accepted temperature + } config; +}; + +struct heat_data { + // input, state of relevant devices + bool cooling { false }; // TODO: user controlled device, implement +// bool okienko { true }; // window in the engine compartment + // system configuration + bool auxiliary_water_circuit { false }; // cooling system has an extra water circuit + // heat exchange factors + double kw { 0.35 }; + double kv { 0.6 }; + double kfe { 1.0 }; + double kfs { 80.0 }; + double kfo { 25.0 }; + double kfo2 { 25.0 }; + // system parts + struct fluid_circuit_t { + + struct circuit_config_t { + float temp_min { -1 }; // lowest accepted temperature + float temp_max { -1 }; // highest accepted temperature + float temp_cooling { -1 }; // active cooling activation point + float temp_flow { -1 }; // fluid flow activation point + bool shutters { false }; // the radiator has shutters to assist the cooling + } config; + bool is_cold { false }; // fluid is too cold + bool is_warm { false }; // fluid is too hot + bool is_hot { false }; // fluid temperature crossed cooling threshold + bool is_flowing { false }; // fluid is being pushed through the circuit + } water, + water_aux, + oil; + // output, state of affected devices + bool PA { false }; // malfunction flag + float rpmw { 0.0 }; // current main circuit fan revolutions + float rpmwz { 0.0 }; // desired main circuit fan revolutions + bool zaluzje1 { false }; + float rpmw2 { 0.0 }; // current auxiliary circuit fan revolutions + float rpmwz2 { 0.0 }; // desired auxiliary circuit fan revolutions + bool zaluzje2 { false }; + // output, temperatures + float Te { 15.0 }; // ambient temperature TODO: get it from environment data + // NOTE: by default the engine is initialized in warm, startup-ready state + float Ts { 50.0 }; // engine temperature + float To { 45.0 }; // oil temperature + float Tsr { 50.0 }; // main circuit radiator temperature (?) + float Twy { 50.0 }; // main circuit water temperature + float Tsr2 { 40.0 }; // secondary circuit radiator temperature (?) + float Twy2 { 40.0 }; // secondary circuit water temperature + float temperatura1 { 50.0 }; + float temperatura2 { 40.0 }; +}; + class TMoverParameters { // Ra: wrapper na kod pascalowy, przejmujący jego funkcje Q: 20160824 - juz nie wrapper a klasa bazowa :) public: @@ -928,6 +1001,10 @@ public: bool ConverterFlag = false; /*! czy wlaczona przetwornica NBMX*/ fuel_pump FuelPump; oil_pump OilPump; + water_pump WaterPump; + water_heater WaterHeater; + bool WaterCircuitsLink { false }; // optional connection between water circuits + heat_data dizel_heat; int BrakeCtrlPos = -2; /*nastawa hamulca zespolonego*/ double BrakeCtrlPosR = 0.0; /*nastawa hamulca zespolonego - plynna dla FV4a*/ @@ -1123,6 +1200,7 @@ public: void UpdateBatteryVoltage(double dt); double ComputeMovement(double dt, double dt1, const TTrackShape &Shape, TTrackParam &Track, TTractionParam &ElectricTraction, const TLocation &NewLoc, TRotation &NewRot); //oblicza przesuniecie pojazdu double FastComputeMovement(double dt, const TTrackShape &Shape, TTrackParam &Track, const TLocation &NewLoc, TRotation &NewRot); //oblicza przesuniecie pojazdu - wersja zoptymalizowana + void compute_movement_( double const Deltatime ); double ShowEngineRotation(int VehN); // Q ******************************************************************************************* @@ -1215,6 +1293,11 @@ public: /*--funkcje dla lokomotyw*/ bool DirectionBackward(void);/*! kierunek ruchu*/ + bool WaterPumpBreakerSwitch( bool State, int const Notify = range::consist ); // water pump breaker state toggle + bool WaterPumpSwitch( bool State, int const Notify = range::consist ); // water pump state toggle + bool WaterHeaterBreakerSwitch( bool State, int const Notify = range::consist ); // water heater breaker state toggle + bool WaterHeaterSwitch( bool State, int const Notify = range::consist ); // water heater state toggle + bool WaterCircuitsLinkSwitch( bool State, int const Notify = range::consist ); // water circuits link state toggle bool FuelPumpSwitch( bool State, int const Notify = range::consist ); // fuel pump state toggle bool OilPumpSwitch( bool State, int const Notify = range::consist ); // oil pump state toggle bool MainSwitch( bool const State, int const Notify = range::consist );/*! wylacznik glowny*/ @@ -1223,6 +1306,8 @@ public: /*-funkcje typowe dla lokomotywy elektrycznej*/ void ConverterCheck( double const Timestep ); // przetwornica + void WaterPumpCheck( double const Timestep ); + void WaterHeaterCheck( double const Timestep ); void FuelPumpCheck( double const Timestep ); void OilPumpCheck( double const Timestep ); bool FuseOn(void); //bezpiecznik nadamiary @@ -1256,6 +1341,8 @@ public: bool dizel_AutoGearCheck(void); double dizel_fillcheck(int mcp); double dizel_Momentum(double dizel_fill, double n, double dt); + void dizel_HeatSet( float const Value ); + void dizel_Heat( double const dt ); bool dizel_StartupCheck(); bool dizel_Update(double dt); diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index 3076ec0f..b340ca79 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -1372,46 +1372,7 @@ double TMoverParameters::ComputeMovement(double dt, double dt1, const TTrackShap dL = 0; // koniec procedury, tu nastepuja dodatkowe procedury pomocnicze - - // sprawdzanie i ewentualnie wykonywanie->kasowanie poleceń - if (LoadStatus > 0) // czas doliczamy tylko jeśli trwa (roz)ładowanie - LastLoadChangeTime += dt; // czas (roz)ładunku - - RunInternalCommand(); - - // automatyczny rozruch - if (EngineType == ElectricSeriesMotor) - - if (AutoRelayCheck()) - SetFlag(SoundFlag, sound::relay); - - if( ( EngineType == DieselEngine ) - || ( EngineType == DieselElectric ) ) { - if( dizel_Update( dt ) ) { - SetFlag( SoundFlag, sound::relay ); - } - } - // uklady hamulcowe: - if (VeselVolume > 0) - Compressor = CompressedVolume / VeselVolume; - else - { - Compressor = 0; - CompressorFlag = false; - }; - ConverterCheck(dt); - if (CompressorSpeed > 0.0) // sprężarka musi mieć jakąś niezerową wydajność - CompressorCheck(dt); //żeby rozważać jej załączenie i pracę - UpdateBrakePressure(dt); - UpdatePipePressure(dt); - UpdateBatteryVoltage(dt); - UpdateScndPipePressure(dt); // druga rurka, youBy - // hamulec antypoślizgowy - wyłączanie - if ((BrakeSlippingTimer > 0.8) && (ASBType != 128)) // ASBSpeed=0.8 - Hamulec->ASB(0); - BrakeSlippingTimer += dt; - // automatic doors - update_autonomous_doors( dt ); + compute_movement_( dt ); // security system if (!DebugModeFlag) SecuritySystemCheck(dt1); @@ -1491,16 +1452,32 @@ double TMoverParameters::FastComputeMovement(double dt, const TTrackShape &Shape dL = 0; // koniec procedury, tu nastepuja dodatkowe procedury pomocnicze + compute_movement_( dt ); + + return d; +}; + +// updates shared between 'fast' and regular movement computation methods +void TMoverParameters::compute_movement_( double const Deltatime ) { // sprawdzanie i ewentualnie wykonywanie->kasowanie poleceń if (LoadStatus > 0) // czas doliczamy tylko jeśli trwa (roz)ładowanie - LastLoadChangeTime += dt; // czas (roz)ładunku + LastLoadChangeTime += Deltatime; // czas (roz)ładunku RunInternalCommand(); - if (EngineType == DieselEngine) - if (dizel_Update(dt)) + // automatyczny rozruch + if (EngineType == ElectricSeriesMotor) + + if (AutoRelayCheck()) SetFlag(SoundFlag, sound::relay); + + if( ( EngineType == DieselEngine ) + || ( EngineType == DieselElectric ) ) { + if( dizel_Update( Deltatime ) ) { + SetFlag( SoundFlag, sound::relay ); + } + } // uklady hamulcowe: if (VeselVolume > 0) Compressor = CompressedVolume / VeselVolume; @@ -1509,22 +1486,24 @@ double TMoverParameters::FastComputeMovement(double dt, const TTrackShape &Shape Compressor = 0; CompressorFlag = false; }; - ConverterCheck(dt); - if (CompressorSpeed > 0.0) // sprężarka musi mieć jakąś niezerową wydajność - CompressorCheck(dt); //żeby rozważać jej załączenie i pracę - UpdateBrakePressure(dt); - UpdatePipePressure(dt); - UpdateScndPipePressure(dt); // druga rurka, youBy - UpdateBatteryVoltage(dt); - // hamulec antyposlizgowy - wyłączanie - if ((BrakeSlippingTimer > 0.8) && (ASBType != 128)) // ASBSpeed=0.8 - Hamulec->ASB(0); - BrakeSlippingTimer += dt; + ConverterCheck(Deltatime); + if( CompressorSpeed > 0.0 ) { + // sprężarka musi mieć jakąś niezerową wydajność żeby rozważać jej załączenie i pracę + CompressorCheck( Deltatime ); + } + UpdateBrakePressure(Deltatime); + UpdatePipePressure(Deltatime); + UpdateBatteryVoltage(Deltatime); + UpdateScndPipePressure(Deltatime); // druga rurka, youBy + + if( ( BrakeSlippingTimer > 0.8 ) && ( ASBType != 128 ) ) { // ASBSpeed=0.8 + // hamulec antypoślizgowy - wyłączanie + Hamulec->ASB( 0 ); + } + BrakeSlippingTimer += Deltatime; // automatic doors - update_autonomous_doors( dt ); - - return d; -}; + update_autonomous_doors( Deltatime ); +} double TMoverParameters::ShowEngineRotation(int VehN) { // Zwraca wartość prędkości obrotowej silnika wybranego pojazdu. Do 3 pojazdów (3×SN61). @@ -1576,6 +1555,35 @@ void TMoverParameters::ConverterCheck( double const Timestep ) { } }; +// water pump status check +void TMoverParameters::WaterPumpCheck( double const Timestep ) { + // NOTE: breaker override with start type is sm42 specific hack, replace with ability to define the presence of the breaker + WaterPump.is_active = ( + ( true == Battery ) + && ( true == WaterPump.breaker ) + && ( ( true == WaterPump.is_enabled ) || ( WaterPump.start_type == start::battery ) ) ); +} + +// water heater status check +void TMoverParameters::WaterHeaterCheck( double const Timestep ) { + + WaterHeater.is_active = ( + ( false == WaterHeater.is_damaged ) + && ( true == Battery ) + && ( true == WaterHeater.is_enabled ) + && ( true == WaterHeater.breaker ) + && ( ( WaterHeater.config.temp_min < 0 ) || ( dizel_heat.temperatura1 < WaterHeater.config.temp_min ) ) ); + + if( ( WaterHeater.config.temp_max > 0 ) + && ( dizel_heat.temperatura1 > WaterHeater.config.temp_max ) ) { + WaterHeater.is_active = false; + } + + WaterHeater.is_damaged |= ( + ( true == WaterHeater.is_active ) + && ( false == WaterPump.is_active ) ); +} + // fuel pump status update void TMoverParameters::FuelPumpCheck( double const Timestep ) { @@ -1590,12 +1598,12 @@ void TMoverParameters::FuelPumpCheck( double const Timestep ) { // oil pump status update void TMoverParameters::OilPumpCheck( double const Timestep ) { - OilPump.is_active = - ( ( true == Battery ) - && ( OilPump.start_type == start::manual ? ( OilPump.is_enabled ) : - OilPump.start_type == start::automatic ? ( dizel_startup || Mains ) : - OilPump.start_type == start::manualwithautofallback ? ( OilPump.is_enabled || dizel_startup || Mains ) : - false ) ); // shouldn't ever get this far but, eh + OilPump.is_active = ( + ( true == Battery ) + && ( OilPump.start_type == start::manual ? ( OilPump.is_enabled ) : + OilPump.start_type == start::automatic ? ( dizel_startup || Mains ) : + OilPump.start_type == start::manualwithautofallback ? ( OilPump.is_enabled || dizel_startup || Mains ) : + false ) ); // shouldn't ever get this far but, eh auto const maxrevolutions { EngineType == DieselEngine ? @@ -1604,13 +1612,13 @@ void TMoverParameters::OilPumpCheck( double const Timestep ) { auto const minpressure { OilPump.pressure_minimum > 0.f ? OilPump.pressure_minimum : - 0.1f }; // arbitrary fallback value + 0.15f }; // arbitrary fallback value auto const maxpressure { 0.65f }; // arbitrary value OilPump.pressure_target = ( - false == OilPump.is_active ? 0.f : - enrot > 0.1 ? std::max( minpressure, maxpressure * clamp( enrot / maxrevolutions, 0.0, 1.0 ) ) * OilPump.resource_amount : - minpressure ); + enrot > 0.1 ? interpolate( minpressure, maxpressure, static_cast( clamp( enrot / maxrevolutions, 0.0, 1.0 ) ) ) * OilPump.resource_amount : + true == OilPump.is_active ? minpressure : + 0.f ); if( OilPump.pressure_present < OilPump.pressure_target ) { // TODO: scale change rate from 0.01-0.05 with oil/engine temperature/idle time @@ -2396,6 +2404,131 @@ bool TMoverParameters::AntiSlippingButton(void) return (AntiSlippingBrake() /*|| Sandbox(true)*/); } +// water pump breaker state toggle +bool TMoverParameters::WaterPumpBreakerSwitch( bool State, int const Notify ) { +/* + if( FuelPump.start_type == start::automatic ) { + // automatic fuel pump ignores 'manual' state commands + return false; + } +*/ + bool const initialstate { WaterPump.breaker }; + + WaterPump.breaker = State; + + if( Notify != range::local ) { + SendCtrlToNext( + "WaterPumpBreakerSwitch", + ( WaterPump.breaker ? 1 : 0 ), + CabNo, + ( Notify == range::unit ? + coupling::control | coupling::permanent : + coupling::control ) ); + } + + return ( WaterPump.breaker != initialstate ); +} + +// water pump state toggle +bool TMoverParameters::WaterPumpSwitch( bool State, int const Notify ) { + + if( WaterPump.start_type == start::battery ) { + // automatic fuel pump ignores 'manual' state commands + return false; + } + + bool const initialstate { WaterPump.is_enabled }; + + WaterPump.is_enabled = State; + + if( Notify != range::local ) { + SendCtrlToNext( + "WaterPumpSwitch", + ( WaterPump.is_enabled ? 1 : 0 ), + CabNo, + ( Notify == range::unit ? + coupling::control | coupling::permanent : + coupling::control ) ); + } + + return ( WaterPump.is_enabled != initialstate ); +} + +// water heater breaker state toggle +bool TMoverParameters::WaterHeaterBreakerSwitch( bool State, int const Notify ) { +/* + if( FuelPump.start_type == start::automatic ) { + // automatic fuel pump ignores 'manual' state commands + return false; + } +*/ + bool const initialstate { WaterHeater.breaker }; + + WaterHeater.breaker = State; + + if( Notify != range::local ) { + SendCtrlToNext( + "WaterHeaterBreakerSwitch", + ( WaterHeater.breaker ? 1 : 0 ), + CabNo, + ( Notify == range::unit ? + coupling::control | coupling::permanent : + coupling::control ) ); + } + + return ( WaterHeater.breaker != initialstate ); +} + +// water heater state toggle +bool TMoverParameters::WaterHeaterSwitch( bool State, int const Notify ) { +/* + if( FuelPump.start_type == start::automatic ) { + // automatic fuel pump ignores 'manual' state commands + return false; + } +*/ + bool const initialstate { WaterHeater.is_enabled }; + + WaterHeater.is_enabled = State; + + if( Notify != range::local ) { + SendCtrlToNext( + "WaterHeaterSwitch", + ( WaterHeater.is_enabled ? 1 : 0 ), + CabNo, + ( Notify == range::unit ? + coupling::control | coupling::permanent : + coupling::control ) ); + } + + return ( WaterHeater.is_enabled != initialstate ); +} + +// water circuits link state toggle +bool TMoverParameters::WaterCircuitsLinkSwitch( bool State, int const Notify ) { + + if( false == dizel_heat.auxiliary_water_circuit ) { + // can't link the circuits if the vehicle only has one + return false; + } + + bool const initialstate { WaterCircuitsLink }; + + WaterCircuitsLink = State; + + if( Notify != range::local ) { + SendCtrlToNext( + "WaterCircuitsLinkSwitch", + ( WaterCircuitsLink ? 1 : 0 ), + CabNo, + ( Notify == range::unit ? + coupling::control | coupling::permanent : + coupling::control ) ); + } + + return ( WaterCircuitsLink != initialstate ); +} + // fuel pump state toggle bool TMoverParameters::FuelPumpSwitch( bool State, int const Notify ) { @@ -4417,12 +4550,30 @@ double TMoverParameters::TractionForce(double dt) } case DieselElectric: { + // NOTE: for this type RventRot is the speed of motor blowers; we also update radiator fans while at it if( true == Mains ) { // TBD, TODO: currently ignores RVentType, fix this? - RventRot += clamp( DElist[ MainCtrlPos ].RPM / 60.0 - RventRot, -100.0, 50.0 ) * dt; + RventRot += clamp( enrot - RventRot, -100.0, 50.0 ) * dt; + dizel_heat.rpmw += clamp( dizel_heat.rpmwz - dizel_heat.rpmw, -100.f, 50.f ) * dt; + dizel_heat.rpmw += clamp( dizel_heat.rpmwz - dizel_heat.rpmw, -100.f, 50.f ) * dt; } else { RventRot *= std::max( 0.0, 1.0 - RVentSpeed * dt ); + dizel_heat.rpmw *= std::max( 0.0, 1.0 - dizel_heat.rpmw * dt ); + dizel_heat.rpmw2 *= std::max( 0.0, 1.0 - dizel_heat.rpmw2 * dt ); + } + break; + } + + case DieselEngine: { + // NOTE: we update only radiator fans, as vehicles with diesel engine don't have other ventilators + if( true == Mains ) { + dizel_heat.rpmw += clamp( dizel_heat.rpmwz - dizel_heat.rpmw, -100.f, 50.f ) * dt; + dizel_heat.rpmw += clamp( dizel_heat.rpmwz - dizel_heat.rpmw, -100.f, 50.f ) * dt; + } + else { + dizel_heat.rpmw *= std::max( 0.0, 1.0 - dizel_heat.rpmw * dt ); + dizel_heat.rpmw2 *= std::max( 0.0, 1.0 - dizel_heat.rpmw2 * dt ); } break; } @@ -4521,11 +4672,9 @@ double TMoverParameters::TractionForce(double dt) if( MainSwitch( false, ( TrainType == dt_EZT ? range::unit : range::local ) ) ) // TODO: check whether we need to send this EMU-wide EventFlag = true; // wywalanie szybkiego z powodu niewłaściwego napięcia - if (((DynamicBrakeType == dbrake_automatic) || (DynamicBrakeType == dbrake_switch)) && - (DynamicBrakeFlag)) + if (((DynamicBrakeType == dbrake_automatic) || (DynamicBrakeType == dbrake_switch)) && (DynamicBrakeFlag)) Itot = Im * 2; // 2x2 silniki w EP09 - else if ((TrainType == dt_EZT) && (Imin == IminLo) && - (ScndS)) // yBARC - boczniki na szeregu poprawnie + else if ((TrainType == dt_EZT) && (Imin == IminLo) && (ScndS)) // yBARC - boczniki na szeregu poprawnie Itot = Im; else Itot = Im * RList[MainCtrlActualPos].Bn; // prad silnika * ilosc galezi @@ -5847,6 +5996,12 @@ bool TMoverParameters::dizel_StartupCheck() { dizel_startup = false; } } + // test the water circuits and water temperature + if( true == dizel_heat.PA ) { + engineisready = false; + // TBD, TODO: reset startup procedure depending on pump and heater control mode + dizel_startup = false; + } return engineisready; } @@ -5857,6 +6012,8 @@ bool TMoverParameters::dizel_StartupCheck() { // ************************************************************************************************* bool TMoverParameters::dizel_Update(double dt) { + WaterPumpCheck( dt ); + WaterHeaterCheck( dt ); OilPumpCheck( dt ); FuelPumpCheck( dt ); if( ( true == dizel_startup ) @@ -5897,6 +6054,8 @@ bool TMoverParameters::dizel_Update(double dt) { dizel_fill = dizel_fill + fillspeed * dt * ( dizel_fillcheck( MainCtrlPos ) - dizel_fill ); } + dizel_Heat( dt ); + return DU; } @@ -6103,6 +6262,205 @@ double TMoverParameters::dizel_Momentum(double dizel_fill, double n, double dt) return gearMoment; } +// sets component temperatures to specified value +void TMoverParameters::dizel_HeatSet( float const Value ) { + + dizel_heat.Te = // TODO: don't include ambient temperature, pull it from environment data instead + dizel_heat.Ts = + dizel_heat.To = + dizel_heat.Tsr = + dizel_heat.Twy = + dizel_heat.Tsr2 = + dizel_heat.Twy2 = + dizel_heat.temperatura1 = + dizel_heat.temperatura2 = Value; +} + +// calculates diesel engine temperature and heat transfers +// adapted from scripts written by adamst +// NOTE: originally executed twice per second +void TMoverParameters::dizel_Heat( double const dt ) { + + auto const qs { 44700.0 }; + auto const Cs { 11000.0 }; + auto const Cw { 4.189 }; + auto const Co { 1.885 }; + auto const gwmin { 400.0 }; + auto const gwmax { 4000.0 }; + auto const gwmin2 { 400.0 }; + auto const gwmax2 { 4000.0 }; + + auto const engineon { ( Mains ? 1 : 0 ) }; + auto const engineoff { ( Mains ? 0 : 1 ) }; + auto const rpm { enrot * 60 }; + // TODO: calculate this once and cache for further use, instead of doing it repeatedly all over the place + auto const maxrevolutions { ( + EngineType == DieselEngine ? dizel_nmax * 60 : + EngineType == DieselElectric ? DElist[ MainCtrlPosNo ].RPM : + std::numeric_limits::max() ) }; // shouldn't ever get here but, eh + auto const revolutionsfactor { clamp( rpm / maxrevolutions, 0.0, 1.0 ) }; + auto const waterpump { WaterPump.is_active ? 1 : 0 }; + + auto const gw = engineon * interpolate( gwmin, gwmax, revolutionsfactor ) + waterpump * 1000 + engineoff * 200; + auto const gw2 = engineon * interpolate( gwmin2, gwmax2, revolutionsfactor ) + waterpump * 1000 + engineoff * 200; + auto const gwO = interpolate( gwmin, gwmax, revolutionsfactor ); + + dizel_heat.water.is_cold = ( + ( dizel_heat.water.config.temp_min > 0 ) + && ( dizel_heat.temperatura1 < dizel_heat.water.config.temp_min - ( Mains ? 5 : 0 ) ) ); + dizel_heat.water.is_hot = ( + ( dizel_heat.water.config.temp_max > 0 ) + && ( dizel_heat.temperatura1 > dizel_heat.water.config.temp_max - ( dizel_heat.water.is_hot ? 8 : 0 ) ) ); + dizel_heat.water_aux.is_cold = ( + ( dizel_heat.water_aux.config.temp_min > 0 ) + && ( dizel_heat.temperatura2 < dizel_heat.water_aux.config.temp_min - ( Mains ? 5 : 0 ) ) ); + dizel_heat.water_aux.is_hot = ( + ( dizel_heat.water_aux.config.temp_max > 0 ) + && ( dizel_heat.temperatura2 > dizel_heat.water_aux.config.temp_max - ( dizel_heat.water_aux.is_hot ? 8 : 0 ) ) ); + dizel_heat.oil.is_cold = ( + ( dizel_heat.oil.config.temp_min > 0 ) + && ( dizel_heat.To < dizel_heat.oil.config.temp_min - ( Mains ? 5 : 0 ) ) ); + dizel_heat.oil.is_hot = ( + ( dizel_heat.oil.config.temp_max > 0 ) + && ( dizel_heat.To > dizel_heat.oil.config.temp_max - ( dizel_heat.oil.is_hot ? 8 : 0 ) ) ); + + auto const PT = ( + ( false == dizel_heat.water.is_cold ) + && ( false == dizel_heat.water.is_hot ) + && ( false == dizel_heat.water_aux.is_cold ) + && ( false == dizel_heat.water_aux.is_hot ) + && ( false == dizel_heat.oil.is_cold ) + && ( false == dizel_heat.oil.is_hot ) /* && ( false == awaria_termostatow ) */ ) /* || PTp */; + auto const PPT = ( false == PT ) /* && ( false == PPTp ) */; + dizel_heat.PA = ( /* ( ( !zamkniecie or niedomkniecie ) and !WBD ) || */ PPT /* || nurnik || ( woda < 7 ) */ ) /* && ( !PAp ) */; + + // engine heat transfers + auto const Ge { engineon * ( 0.21 * EnginePower + 12 ) / 3600 }; + // TODO: replace fixed heating power cost with more accurate calculation + auto const obciazenie { engineon * ( ( EnginePower / 950 ) + ( Heating ? HeatingPower : 0 ) + 70 ) }; + auto const Qd { qs * Ge - obciazenie }; + // silnik oddaje czesc ciepla do wody chlodzacej, a takze pewna niewielka czesc do otoczenia, modyfikowane przez okienko + auto const Qs { ( Qd - ( dizel_heat.kfs * ( dizel_heat.Ts - dizel_heat.Tsr ) ) - ( dizel_heat.kfe * /* ( 0.3 + 0.7 * ( dizel_heat.okienko ? 1 : 0 ) ) * */ ( dizel_heat.Ts - dizel_heat.Te ) ) ) }; + auto const dTss { Qs / Cs }; + dizel_heat.Ts += ( dTss * dt ); + + // oil heat transfers + // olej oddaje cieplo do wody gdy krazy przez wymiennik ciepla == wlaczona pompka lub silnik + auto const dTo { ( + dizel_heat.auxiliary_water_circuit ? + ( ( dizel_heat.kfo * ( dizel_heat.Ts - dizel_heat.To ) ) - ( dizel_heat.kfs * ( 0.3 ) * ( dizel_heat.To - dizel_heat.Tsr2 ) ) ) / ( gwO * Co ) : + ( ( dizel_heat.kfo * ( dizel_heat.Ts - dizel_heat.To ) ) - ( dizel_heat.kfo2 * ( dizel_heat.To - dizel_heat.Tsr ) ) ) / ( gwO * Co ) ) }; + dizel_heat.To += ( dTo * dt ); + + // heater +/* + if( typ == "SP45" ) + Qp = (float)( podgrzewacz and ( true == WaterPump.is_active ) and ( Twy < 55 ) and ( Twy2 < 55 ) ) * 1000; + else +*/ + auto const Qp = ( ( ( true == WaterHeater.is_active ) && ( true == WaterPump.is_active ) && ( dizel_heat.Twy < 60 ) && ( dizel_heat.Twy2 < 60 ) ) ? 1 : 0 ) * 1000; + + auto const kurek07 { 1 }; // unknown/unimplemented device TBD, TODO: identify and implement? + + if( true == dizel_heat.auxiliary_water_circuit ) { + // auxiliary water circuit setup + dizel_heat.water_aux.is_warm = ( + ( true == dizel_heat.cooling ) + || ( ( true == Mains ) + && ( BatteryVoltage > 70 ) /* && !bezpompy && !awaria_chlodzenia && !WS10 */ + && ( dizel_heat.water_aux.config.temp_cooling > 0 ) + && ( dizel_heat.temperatura2 > dizel_heat.water_aux.config.temp_cooling - ( dizel_heat.water_aux.is_warm ? 8 : 0 ) ) ) ); + auto const PTC2 { ( dizel_heat.water_aux.is_warm /*or PTC2p*/ ? 1 : 0 ) }; + dizel_heat.rpmwz2 = PTC2 * 80 * rpm / ( ( 0.5 * rpm ) + 500 ); + dizel_heat.zaluzje2 = ( dizel_heat.water_aux.config.shutters ? PTC2 : true ); // no shutters is an equivalent to having them open + auto const zaluzje2 { ( dizel_heat.zaluzje2 ? 1 : 0 ) }; + // auxiliary water circuit heat transfer values + auto const kf2 { kurek07 * ( ( dizel_heat.kw * ( 0.3 + 0.7 * zaluzje2 ) ) * dizel_heat.rpmw2 + ( dizel_heat.kv * ( 0.3 + 0.7 * zaluzje2 ) * Vel / 3.6 ) ) + 2 }; + auto const dTs2 { ( ( dizel_heat.kfs * ( 0.3 ) * ( dizel_heat.To - dizel_heat.Tsr2 ) ) ) / ( gw2 * Cw ) }; + // przy otwartym kurku B ma³y obieg jest dogrzewany przez du¿y - stosujemy przy korzystaniu z podgrzewacza oraz w zimie + auto const Qch2 { -kf2 * ( dizel_heat.Tsr2 - dizel_heat.Te ) + ( 80 * ( true == WaterCircuitsLink ? 1 : 0 ) * ( dizel_heat.Twy - dizel_heat.Tsr2 ) ) }; + auto const dTch2 { Qch2 / ( gw2 * Cw ) }; + // auxiliary water circuit heat transfers finalization + // NOTE: since primary circuit doesn't read data from the auxiliary one, we can pretty safely finalize auxiliary updates before touching the primary circuit + auto const Twe2 { dizel_heat.Twy2 + ( dTch2 * dt ) }; + dizel_heat.Twy2 = Twe2 + ( dTs2 * dt ); + dizel_heat.Tsr2 = 0.5 * ( dizel_heat.Twy2 + Twe2 ); + dizel_heat.temperatura2 = dizel_heat.Twy2; + } + // primary water circuit setup + dizel_heat.water.is_flowing = ( + ( dizel_heat.water.config.temp_flow < 0 ) + || ( dizel_heat.temperatura1 > dizel_heat.water.config.temp_flow - ( dizel_heat.water.is_flowing ? 5 : 0 ) ) ); + auto const obieg { ( dizel_heat.water.is_flowing ? 1 : 0 ) }; + dizel_heat.water.is_warm = ( + ( true == dizel_heat.cooling ) + || ( ( true == Mains ) + && ( BatteryVoltage > 70 ) /* && !bezpompy && !awaria_chlodzenia && !WS10 */ + && ( dizel_heat.water.config.temp_cooling > 0 ) + && ( dizel_heat.temperatura1 > dizel_heat.water.config.temp_cooling - ( dizel_heat.water.is_warm ? 8 : 0 ) ) ) ); + auto const PTC1 { ( dizel_heat.water.is_warm /*or PTC1p*/ ? 1 : 0 ) }; + dizel_heat.rpmwz = PTC1 * 80 * rpm / ( ( 0.5 * rpm ) + 500 ); + dizel_heat.zaluzje1 = ( dizel_heat.water.config.shutters ? PTC1 : true ); // no shutters is an equivalent to having them open + auto const zaluzje1 { ( dizel_heat.zaluzje1 ? 1 : 0 ) }; + // primary water circuit heat transfer values + auto const kf { obieg * kurek07 * ( ( dizel_heat.kw * ( 0.3 + 0.7 * zaluzje1 ) ) * dizel_heat.rpmw + ( dizel_heat.kv * ( 0.3 + 0.7 * zaluzje1 ) * Vel / 3.6 ) + 3 ) + 2 }; + auto const dTs { ( + dizel_heat.auxiliary_water_circuit ? + ( ( dizel_heat.kfs * ( dizel_heat.Ts - dizel_heat.Tsr ) ) ) / ( gw * Cw ) : + ( ( dizel_heat.kfs * ( dizel_heat.Ts - dizel_heat.Tsr ) ) + ( dizel_heat.kfo2 * ( dizel_heat.To - dizel_heat.Tsr ) ) ) / ( gw * Cw ) ) }; + auto const Qch { -kf * ( dizel_heat.Tsr - dizel_heat.Te ) + Qp }; + auto const dTch { Qch / ( gw * Cw ) }; + // primary water circuit heat transfers finalization + auto const Twe { dizel_heat.Twy + ( dTch * dt ) }; + dizel_heat.Twy = Twe + ( dTs * dt ); + dizel_heat.Tsr = 0.5 * ( dizel_heat.Twy + Twe ); + dizel_heat.temperatura1 = dizel_heat.Twy; +/* + fuelConsumed = fuelConsumed + ( Ge * 0.5 ); + + while( fuelConsumed >= 0.83 ) { + fuelConsumed = fuelConsumed - 0.83; + fuelQueue.DestroyProductMatching( null, 1 ); + }//if + + if( engineon ) + temp_turbo = temp_turbo + 0.3 * ( t_pozycja ); + if( t_pozycja == 0 and cisnienie > 0.04 ) + temp_turbo = temp_turbo - 1; + + if( temp_turbo > 400 ) + temp_turbo = 400; + if( temp_turbo < 0 ) + temp_turbo = 0; + + if( temp_turbo > 50 and cisnienie < 0.05 ) + timer_turbo = timer_turbo + 1; + + if( temp_turbo == 0 ) + timer_turbo = 0; + + if( timer_turbo > 360 ) { + awaria_turbo = true; + timer_turbo = 400; + } + + if( Ts < 50 ) + p_odpal = 3; + if( Ts > 49 and Ts < 76 ) + p_odpal = 4; + if( Ts > 75 ) + p_odpal = 7; + + stukanie = stukanie or awaria_oleju; + + if( awaria_oleju == true and ilosc_oleju > 0 ) { + ilosc_oleju = ilosc_oleju - ( 0.002 * rpm / 1500 ); + } + if( awaria_oleju == true and cisnienie < 0.06 ) + damage = 1; +*/ +} + // ************************************************************************************************* // Q: 20160713 // Test zakończenia załadunku / rozładunku @@ -7775,6 +8133,19 @@ void TMoverParameters::LoadFIZ_Cntrl( std::string const &line ) { lookup->second : start::manual; } + + // water pump + { + std::map starts { + { "Manual", start::manual }, + { "Battery", start::battery } + }; + auto lookup = starts.find( extract_value( "WaterStart", line ) ); + WaterPump.start_type = + lookup != starts.end() ? + lookup->second : + start::manual; + } } void TMoverParameters::LoadFIZ_Light( std::string const &line ) { @@ -7987,7 +8358,31 @@ void TMoverParameters::LoadFIZ_Engine( std::string const &Input ) { default: { // nothing here } - } + } // engine type + + // engine cooling factore + extract_value( dizel_heat.kw, "HeatKW", Input, "" ); + extract_value( dizel_heat.kv, "HeatKV", Input, "" ); + extract_value( dizel_heat.kfe, "HeatKFE", Input, "" ); + extract_value( dizel_heat.kfs, "HeatKFS", Input, "" ); + extract_value( dizel_heat.kfo, "HeatKFO", Input, "" ); + extract_value( dizel_heat.kfo2, "HeatKFO2", Input, "" ); + // engine cooling systems + extract_value( dizel_heat.water.config.temp_min, "WaterMinTemperature", Input, "" ); + extract_value( dizel_heat.water.config.temp_max, "WaterMaxTemperature", Input, "" ); + extract_value( dizel_heat.water.config.temp_flow, "WaterFlowTemperature", Input, "" ); + extract_value( dizel_heat.water.config.temp_cooling, "WaterCoolingTemperature", Input, "" ); + extract_value( dizel_heat.water.config.shutters, "WaterShutters", Input, "" ); + extract_value( dizel_heat.auxiliary_water_circuit, "WaterAuxCircuit", Input, "" ); + extract_value( dizel_heat.water_aux.config.temp_min, "WaterAuxMinTemperature", Input, "" ); + extract_value( dizel_heat.water_aux.config.temp_max, "WaterAuxMaxTemperature", Input, "" ); + extract_value( dizel_heat.water_aux.config.temp_cooling, "WaterAuxCoolingTemperature", Input, "" ); + extract_value( dizel_heat.water_aux.config.shutters, "WaterAuxShutters", Input, "" ); + extract_value( dizel_heat.oil.config.temp_min, "OilMinTemperature", Input, "" ); + extract_value( dizel_heat.oil.config.temp_max, "OilMaxTemperature", Input, "" ); + // water heater + extract_value( WaterHeater.config.temp_min, "HeaterMinTemperature", Input, "" ); + extract_value( WaterHeater.config.temp_max, "HeaterMaxTemperature", Input, "" ); } void TMoverParameters::LoadFIZ_Switches( std::string const &Input ) { @@ -8671,15 +9066,63 @@ bool TMoverParameters::RunCommand( std::string Command, double CValue1, double C OK = BrakeReleaser(Round(CValue1)); // samo się przesyła dalej // OK:=SendCtrlToNext(command,CValue1,CValue2); //to robiło kaskadę 2^n } + else if( Command == "WaterPumpBreakerSwitch" ) { +/* + if( FuelPump.start_type != start::automatic ) { + // automatic fuel pump ignores 'manual' state commands +*/ + WaterPump.breaker = ( CValue1 == 1 ); +/* + } +*/ + OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype ); + } + else if( Command == "WaterPumpSwitch" ) { + + if( WaterPump.start_type != start::battery ) { + // automatic fuel pump ignores 'manual' state commands + WaterPump.is_enabled = ( CValue1 == 1 ); + } + OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype ); + } + else if( Command == "WaterHeaterBreakerSwitch" ) { +/* + if( FuelPump.start_type != start::automatic ) { + // automatic fuel pump ignores 'manual' state commands +*/ + WaterHeater.breaker = ( CValue1 == 1 ); +/* + } +*/ + OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype ); + } + else if( Command == "WaterHeaterSwitch" ) { +/* + if( FuelPump.start_type != start::automatic ) { + // automatic fuel pump ignores 'manual' state commands +*/ + WaterHeater.is_enabled = ( CValue1 == 1 ); +/* + } +*/ + OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype ); + } + else if( Command == "WaterCircuitsLinkSwitch" ) { + if( true == dizel_heat.auxiliary_water_circuit ) { + // can only link circuits if the vehicle has more than one of them + WaterCircuitsLink = ( CValue1 == 1 ); + } + OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype ); + } else if (Command == "FuelPumpSwitch") { - if( FuelPump.start_type == start::manual ) { + if( FuelPump.start_type != start::automatic ) { // automatic fuel pump ignores 'manual' state commands FuelPump.is_enabled = ( CValue1 == 1 ); } OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype ); } else if (Command == "OilPumpSwitch") { - if( OilPump.start_type == start::manual ) { + if( OilPump.start_type != start::automatic ) { // automatic pump ignores 'manual' state commands OilPump.is_enabled = ( CValue1 == 1 ); } diff --git a/Train.cpp b/Train.cpp index 60301c0d..9a991709 100644 --- a/Train.cpp +++ b/Train.cpp @@ -228,6 +228,21 @@ TTrain::commandhandler_map const TTrain::m_commandhandlers = { { user_command::oilpumptoggle, &TTrain::OnCommand_oilpumptoggle }, { user_command::oilpumpenable, &TTrain::OnCommand_oilpumpenable }, { user_command::oilpumpdisable, &TTrain::OnCommand_oilpumpdisable }, + { user_command::waterheaterbreakertoggle, &TTrain::OnCommand_waterheaterbreakertoggle }, + { user_command::waterheaterbreakerclose, &TTrain::OnCommand_waterheaterbreakerclose }, + { user_command::waterheaterbreakeropen, &TTrain::OnCommand_waterheaterbreakeropen }, + { user_command::waterheatertoggle, &TTrain::OnCommand_waterheatertoggle }, + { user_command::waterheaterenable, &TTrain::OnCommand_waterheaterenable }, + { user_command::waterheaterdisable, &TTrain::OnCommand_waterheaterdisable }, + { user_command::waterpumpbreakertoggle, &TTrain::OnCommand_waterpumpbreakertoggle }, + { user_command::waterpumpbreakerclose, &TTrain::OnCommand_waterpumpbreakerclose }, + { user_command::waterpumpbreakeropen, &TTrain::OnCommand_waterpumpbreakeropen }, + { user_command::waterpumptoggle, &TTrain::OnCommand_waterpumptoggle }, + { user_command::waterpumpenable, &TTrain::OnCommand_waterpumpenable }, + { user_command::waterpumpdisable, &TTrain::OnCommand_waterpumpdisable }, + { user_command::watercircuitslinktoggle, &TTrain::OnCommand_watercircuitslinktoggle }, + { user_command::watercircuitslinkenable, &TTrain::OnCommand_watercircuitslinkenable }, + { user_command::watercircuitslinkdisable, &TTrain::OnCommand_watercircuitslinkdisable }, { user_command::convertertoggle, &TTrain::OnCommand_convertertoggle }, { user_command::converterenable, &TTrain::OnCommand_converterenable }, { user_command::converterdisable, &TTrain::OnCommand_converterdisable }, @@ -2078,6 +2093,201 @@ void TTrain::OnCommand_oilpumpdisable( TTrain *Train, command_data const &Comman } } +void TTrain::OnCommand_waterheaterbreakertoggle( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if( false == Train->mvControlled->WaterHeater.breaker ) { + // turn on + OnCommand_waterheaterbreakerclose( Train, Command ); + } + else { + //turn off + OnCommand_waterheaterbreakeropen( Train, Command ); + } + } +} + +void TTrain::OnCommand_waterheaterbreakerclose( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + // visual feedback + Train->ggWaterHeaterBreakerButton.UpdateValue( 1.0, Train->dsbSwitch ); + + if( true == Train->mvControlled->WaterHeater.breaker ) { return; } // already enabled + + Train->mvControlled->WaterHeaterBreakerSwitch( true ); + } +} + +void TTrain::OnCommand_waterheaterbreakeropen( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + // visual feedback + Train->ggWaterHeaterBreakerButton.UpdateValue( 0.0, Train->dsbSwitch ); + + if( false == Train->mvControlled->WaterHeater.breaker ) { return; } // already enabled + + Train->mvControlled->WaterHeaterBreakerSwitch( false ); + } +} + +void TTrain::OnCommand_waterheatertoggle( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if( false == Train->mvControlled->WaterHeater.is_enabled ) { + // turn on + OnCommand_waterheaterenable( Train, Command ); + } + else { + //turn off + OnCommand_waterheaterdisable( Train, Command ); + } + } +} + +void TTrain::OnCommand_waterheaterenable( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + // visual feedback + Train->ggWaterHeaterButton.UpdateValue( 1.0, Train->dsbSwitch ); + + if( true == Train->mvControlled->WaterHeater.is_enabled ) { return; } // already enabled + + Train->mvControlled->WaterHeaterSwitch( true ); + } +} + +void TTrain::OnCommand_waterheaterdisable( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + // visual feedback + Train->ggWaterHeaterButton.UpdateValue( 0.0, Train->dsbSwitch ); + + if( false == Train->mvControlled->WaterHeater.is_enabled ) { return; } // already disabled + + Train->mvControlled->WaterHeaterSwitch( false ); + } +} + +void TTrain::OnCommand_waterpumpbreakertoggle( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if( false == Train->mvControlled->WaterPump.breaker ) { + // turn on + OnCommand_waterpumpbreakerclose( Train, Command ); + } + else { + //turn off + OnCommand_waterpumpbreakeropen( Train, Command ); + } + } +} + +void TTrain::OnCommand_waterpumpbreakerclose( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + // visual feedback + Train->ggWaterPumpBreakerButton.UpdateValue( 1.0, Train->dsbSwitch ); + + if( true == Train->mvControlled->WaterPump.breaker ) { return; } // already enabled + + Train->mvControlled->WaterPumpBreakerSwitch( true ); + } +} + +void TTrain::OnCommand_waterpumpbreakeropen( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + // visual feedback + Train->ggWaterPumpBreakerButton.UpdateValue( 0.0, Train->dsbSwitch ); + + if( false == Train->mvControlled->WaterPump.breaker ) { return; } // already enabled + + Train->mvControlled->WaterPumpBreakerSwitch( false ); + } +} + +void TTrain::OnCommand_waterpumptoggle( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if( false == Train->mvControlled->WaterPump.is_enabled ) { + // turn on + OnCommand_waterpumpenable( Train, Command ); + } + else { + //turn off + OnCommand_waterpumpdisable( Train, Command ); + } + } +} + +void TTrain::OnCommand_waterpumpenable( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + // visual feedback + Train->ggWaterPumpButton.UpdateValue( 1.0, Train->dsbSwitch ); + + if( true == Train->mvControlled->WaterPump.is_enabled ) { return; } // already enabled + + Train->mvControlled->WaterPumpSwitch( true ); + } +} + +void TTrain::OnCommand_waterpumpdisable( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + // visual feedback + Train->ggWaterPumpButton.UpdateValue( 0.0, Train->dsbSwitch ); + + if( false == Train->mvControlled->WaterPump.is_enabled ) { return; } // already disabled + + Train->mvControlled->WaterPumpSwitch( false ); + } +} + +void TTrain::OnCommand_watercircuitslinktoggle( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if( false == Train->mvControlled->WaterCircuitsLink ) { + // turn on + OnCommand_watercircuitslinkenable( Train, Command ); + } + else { + //turn off + OnCommand_watercircuitslinkdisable( Train, Command ); + } + } +} + +void TTrain::OnCommand_watercircuitslinkenable( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + // visual feedback + Train->ggWaterCircuitsLinkButton.UpdateValue( 1.0, Train->dsbSwitch ); + + if( true == Train->mvControlled->WaterCircuitsLink ) { return; } // already enabled + + Train->mvControlled->WaterCircuitsLinkSwitch( true ); + } +} + +void TTrain::OnCommand_watercircuitslinkdisable( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + // visual feedback + Train->ggWaterCircuitsLinkButton.UpdateValue( 0.0, Train->dsbSwitch ); + + if( false == Train->mvControlled->WaterCircuitsLink ) { return; } // already disabled + + Train->mvControlled->WaterCircuitsLinkSwitch( false ); + } +} + void TTrain::OnCommand_convertertoggle( TTrain *Train, command_data const &Command ) { if( Command.action == GLFW_PRESS ) { @@ -3938,8 +4148,8 @@ bool TTrain::Update( double const Deltatime ) } } if( m_linebreakerstate == 1 ) { - if( false == mvControlled->Mains ) { - // crude way to catch cases where the main was knocked out and the user is trying to restart it + if( false == ( mvControlled->Mains || mvControlled->dizel_startup ) ) { + // crude way to catch cases where the main was knocked out // because the state of the line breaker isn't changed to match, we need to do it here manually m_linebreakerstate = 0; } @@ -4481,8 +4691,11 @@ bool TTrain::Update( double const Deltatime ) mvControlled->ResistorsFlagCheck() : false ); - btLampkaBezoporowa.Turn( mvControlled->ResistorsFlagCheck() || ( mvControlled->MainCtrlActualPos == 0 ) ); // do EU04 - if( ( mvControlled->Itot != 0 ) + btLampkaBezoporowa.Turn( + ( true == mvControlled->ResistorsFlagCheck() ) + || ( mvControlled->MainCtrlActualPos == 0 ) ); // do EU04 + + if( ( mvControlled->Im != 0 ) || ( mvOccupied->BrakePress > 2 ) || ( mvOccupied->PipePress < 3.6 ) ) { // Ra: czy to jest udawanie działania styczników liniowych? @@ -4721,6 +4934,9 @@ bool TTrain::Update( double const Deltatime ) btLampkaRearRightLight.Turn( ( mvOccupied->iLights[ side::rear ] & light::headlight_right ) != 0 ); btLampkaRearLeftEndLight.Turn( ( mvOccupied->iLights[ side::rear ] & light::redmarker_left ) != 0 ); btLampkaRearRightEndLight.Turn( ( mvOccupied->iLights[ side::rear ] & light::redmarker_right ) != 0 ); + // others + btLampkaMalfunction.Turn( mvControlled->dizel_heat.PA ); + btLampkaMotorBlowers.Turn( mvControlled->RventRot > 0.1 ); } else { // gdy bateria wyłączona @@ -4752,6 +4968,9 @@ bool TTrain::Update( double const Deltatime ) btLampkaRearRightLight.Turn( false ); btLampkaRearLeftEndLight.Turn( false ); btLampkaRearRightEndLight.Turn( false ); + // others + btLampkaMalfunction.Turn( false ); + btLampkaMotorBlowers.Turn( false ); } // McZapkie-080602: obroty (albo translacje) regulatorow @@ -4967,6 +5186,11 @@ bool TTrain::Update( double const Deltatime ) ggCabLightDimButton.Update(); ggBatteryButton.Update(); + ggWaterPumpBreakerButton.Update(); + ggWaterPumpButton.Update(); + ggWaterHeaterBreakerButton.Update(); + ggWaterHeaterButton.Update(); + ggWaterCircuitsLinkButton.Update(); ggFuelPumpButton.Update(); ggOilPumpButton.Update(); //------ @@ -6013,6 +6237,11 @@ void TTrain::clear_cab_controls() ggMainGearStatus.Clear(); ggIgnitionKey.Clear(); + ggWaterPumpBreakerButton.Clear(); + ggWaterPumpButton.Clear(); + ggWaterHeaterBreakerButton.Clear(); + ggWaterHeaterButton.Clear(); + ggWaterCircuitsLinkButton.Clear(); ggFuelPumpButton.Clear(); ggOilPumpButton.Clear(); @@ -6075,6 +6304,10 @@ void TTrain::clear_cab_controls() btLampkaRearLeftEndLight.Clear(); btLampkaRearRightEndLight.Clear(); btCabLight.Clear(); // hunter-171012 + // others + btLampkaMalfunction.Clear(); + btLampkaMotorBlowers.Clear(); + ggLeftLightButton.Clear(); ggRightLightButton.Clear(); ggUpperLightButton.Clear(); @@ -6280,14 +6513,36 @@ void TTrain::set_cab_controls() { ShowNextCurrent ? 1.0 : 0.0 ); + // water pump + ggWaterPumpBreakerButton.PutValue( + mvControlled->WaterPump.breaker ? + 1.0 : + 0.0 ); + ggWaterPumpButton.PutValue( + mvControlled->WaterPump.is_enabled ? + 1.0 : + 0.0 ); + // water heater + ggWaterHeaterBreakerButton.PutValue( + mvControlled->WaterHeater.breaker ? + 1.0 : + 0.0 ); + ggWaterHeaterButton.PutValue( + mvControlled->WaterHeater.is_enabled ? + 1.0 : + 0.0 ); + ggWaterCircuitsLinkButton.PutValue( + mvControlled->WaterCircuitsLink ? + 1.0 : + 0.0 ); // fuel pump ggFuelPumpButton.PutValue( - mvOccupied->FuelPump.is_enabled ? + mvControlled->FuelPump.is_enabled ? 1.0 : 0.0 ); // oil pump ggOilPumpButton.PutValue( - mvOccupied->OilPump.is_enabled ? + mvControlled->OilPump.is_enabled ? 1.0 : 0.0 ); @@ -6329,6 +6584,7 @@ bool TTrain::initialize_button(cParser &Parser, std::string const &Label, int co { "i-no_resistors_b:", btLampkaBezoporowaB }, { "i-highcurrent:", btLampkaWysRozr }, { "i-vent_trim:", btLampkaWentZaluzje }, + { "i-motorblowers:", btLampkaMotorBlowers }, { "i-trainheating:", btLampkaOgrzewanieSkladu }, { "i-security_aware:", btLampkaCzuwaka }, { "i-security_cabsignal:", btLampkaSHP }, @@ -6358,6 +6614,7 @@ bool TTrain::initialize_button(cParser &Parser, std::string const &Label, int co { "i-resistorsb:", btLampkaOporyB }, { "i-contactorsb:", btLampkaStycznB }, { "i-conv_ovldb:", btLampkaNadmPrzetwB }, + { "i-malfunction:", btLampkaMalfunction }, { "i-forward:", btLampkaForward }, { "i-backward:", btLampkaBackward }, { "i-upperlight:", btLampkaUpperLight }, @@ -6396,6 +6653,14 @@ bool TTrain::initialize_button(cParser &Parser, std::string const &Label, int co button.Load(Parser, DynamicObject, DynamicObject->mdKabina); button.AssignBool(bDoors[0] + 3 * i); } +/* + else if( Label == "i-malfunction:" ) { + // generic malfunction indicator + auto &button = Cabine[ Cabindex ].Button( -1 ); // pierwsza wolna gałka + button.Load( Parser, DynamicObject, DynamicObject->mdKabina ); + button.AssignBool( &mvOccupied->dizel_heat.PA ); + } +*/ else { // failed to match the label @@ -6454,6 +6719,11 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con { "converterlocal_sw:", ggConverterLocalButton }, { "converteroff_sw:", ggConverterOffButton }, { "main_sw:", ggMainButton }, + { "waterpumpbreaker_sw:", ggWaterPumpBreakerButton }, + { "waterpump_sw:", ggWaterPumpButton }, + { "waterheaterbreaker_sw:", ggWaterHeaterBreakerButton }, + { "waterheater_sw:", ggWaterHeaterButton }, + { "watercircuitslink_sw:", ggWaterCircuitsLinkButton }, { "fuelpump_sw:", ggFuelPumpButton }, { "oilpump_sw:", ggOilPumpButton }, { "radio_sw:", ggRadioButton }, @@ -6619,7 +6889,25 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con // oil pressure auto &gauge = Cabine[ Cabindex ].Gauge( -1 ); // pierwsza wolna gałka gauge.Load( Parser, DynamicObject, DynamicObject->mdKabina, nullptr ); - gauge.AssignFloat( &mvOccupied->OilPump.pressure_present ); + gauge.AssignFloat( &mvControlled->OilPump.pressure_present ); + } + else if( Label == "oiltemp:" ) { + // oil temperature + auto &gauge = Cabine[ Cabindex ].Gauge( -1 ); // pierwsza wolna gałka + gauge.Load( Parser, DynamicObject, DynamicObject->mdKabina, nullptr ); + gauge.AssignFloat( &mvControlled->dizel_heat.To ); + } + else if( Label == "water1temp:" ) { + // main circuit water temperature + auto &gauge = Cabine[ Cabindex ].Gauge( -1 ); // pierwsza wolna gałka + gauge.Load( Parser, DynamicObject, DynamicObject->mdKabina, nullptr ); + gauge.AssignFloat( &mvControlled->dizel_heat.temperatura1 ); + } + else if( Label == "water2temp:" ) { + // auxiliary circuit water temperature + auto &gauge = Cabine[ Cabindex ].Gauge( -1 ); // pierwsza wolna gałka + gauge.Load( Parser, DynamicObject, DynamicObject->mdKabina, nullptr ); + gauge.AssignFloat( &mvControlled->dizel_heat.temperatura2 ); } // yB - dla drugiej sekcji else if (Label == "hvbcurrent1:") diff --git a/Train.h b/Train.h index c9bc1e7b..60636020 100644 --- a/Train.h +++ b/Train.h @@ -219,6 +219,21 @@ class TTrain static void OnCommand_oilpumptoggle( TTrain *Train, command_data const &Command ); static void OnCommand_oilpumpenable( TTrain *Train, command_data const &Command ); static void OnCommand_oilpumpdisable( TTrain *Train, command_data const &Command ); + static void OnCommand_waterheaterbreakertoggle( TTrain *Train, command_data const &Command ); + static void OnCommand_waterheaterbreakerclose( TTrain *Train, command_data const &Command ); + static void OnCommand_waterheaterbreakeropen( TTrain *Train, command_data const &Command ); + static void OnCommand_waterheatertoggle( TTrain *Train, command_data const &Command ); + static void OnCommand_waterheaterenable( TTrain *Train, command_data const &Command ); + static void OnCommand_waterheaterdisable( TTrain *Train, command_data const &Command ); + static void OnCommand_waterpumpbreakertoggle( TTrain *Train, command_data const &Command ); + static void OnCommand_waterpumpbreakerclose( TTrain *Train, command_data const &Command ); + static void OnCommand_waterpumpbreakeropen( TTrain *Train, command_data const &Command ); + static void OnCommand_waterpumptoggle( TTrain *Train, command_data const &Command ); + static void OnCommand_waterpumpenable( TTrain *Train, command_data const &Command ); + static void OnCommand_waterpumpdisable( TTrain *Train, command_data const &Command ); + static void OnCommand_watercircuitslinktoggle( TTrain *Train, command_data const &Command ); + static void OnCommand_watercircuitslinkenable( TTrain *Train, command_data const &Command ); + static void OnCommand_watercircuitslinkdisable( TTrain *Train, command_data const &Command ); static void OnCommand_convertertoggle( TTrain *Train, command_data const &Command ); static void OnCommand_converterenable( TTrain *Train, command_data const &Command ); static void OnCommand_converterdisable( TTrain *Train, command_data const &Command ); @@ -408,6 +423,11 @@ public: // reszta może by?publiczna TGauge ggSignallingButton; TGauge ggDoorSignallingButton; + TGauge ggWaterPumpBreakerButton; // water pump breaker switch + TGauge ggWaterPumpButton; // water pump switch + TGauge ggWaterHeaterBreakerButton; // water heater breaker switch + TGauge ggWaterHeaterButton; // water heater switch + TGauge ggWaterCircuitsLinkButton; TGauge ggFuelPumpButton; // fuel pump switch TGauge ggOilPumpButton; // fuel pump switch @@ -468,7 +488,6 @@ public: // reszta może by?publiczna TButton btLampkaBrakeProfileG; // cargo train brake acting speed TButton btLampkaBrakeProfileP; // passenger train brake acting speed TButton btLampkaBrakeProfileR; // rapid brake acting speed - // KURS90 TButton btLampkaBoczniki; TButton btLampkaMaxSila; @@ -491,6 +510,9 @@ public: // reszta może by?publiczna TButton btLampkaRearRightLight; TButton btLampkaRearLeftEndLight; TButton btLampkaRearRightEndLight; + // other + TButton btLampkaMalfunction; + TButton btLampkaMotorBlowers; TButton btCabLight; // hunter-171012: lampa oswietlajaca kabine // Ra 2013-12: wirtualne "lampki" do odbijania na haslerze w PoKeys diff --git a/command.cpp b/command.cpp index 935e2d4c..c7b0073f 100644 --- a/command.cpp +++ b/command.cpp @@ -63,6 +63,21 @@ commanddescription_sequence Commands_descriptions = { { "reverserforward", command_target::vehicle }, { "reverserneutral", command_target::vehicle }, { "reverserbackward", command_target::vehicle }, + { "waterpumpbreakertoggle", command_target::vehicle }, + { "waterpumpbreakerclose", command_target::vehicle }, + { "waterpumpbreakeropen", command_target::vehicle }, + { "waterpumptoggle", command_target::vehicle }, + { "waterpumpenable", command_target::vehicle }, + { "waterpumpdisable", command_target::vehicle }, + { "waterheaterbreakertoggle", command_target::vehicle }, + { "waterheaterbreakerclose", command_target::vehicle }, + { "waterheaterbreakeropen", command_target::vehicle }, + { "waterheatertoggle", command_target::vehicle }, + { "waterheaterenable", command_target::vehicle }, + { "waterheaterdisable", command_target::vehicle }, + { "watercircuitslinktoggle", command_target::vehicle }, + { "watercircuitslinkenable", command_target::vehicle }, + { "watercircuitslinkdisable", command_target::vehicle }, { "fuelpumptoggle", command_target::vehicle }, { "fuelpumpenable", command_target::vehicle }, { "fuelpumpdisable", command_target::vehicle }, diff --git a/command.h b/command.h index d34f936b..be90b1c8 100644 --- a/command.h +++ b/command.h @@ -57,6 +57,21 @@ enum class user_command { reverserforward, reverserneutral, reverserbackward, + waterpumpbreakertoggle, + waterpumpbreakerclose, + waterpumpbreakeropen, + waterpumptoggle, + waterpumpenable, + waterpumpdisable, + waterheaterbreakertoggle, + waterheaterbreakerclose, + waterheaterbreakeropen, + waterheatertoggle, + waterheaterenable, + waterheaterdisable, + watercircuitslinktoggle, + watercircuitslinkenable, + watercircuitslinkdisable, fuelpumptoggle, fuelpumpenable, fuelpumpdisable, diff --git a/keyboardinput.cpp b/keyboardinput.cpp index f4f72199..4f60b08f 100644 --- a/keyboardinput.cpp +++ b/keyboardinput.cpp @@ -255,6 +255,36 @@ keyboard_input::default_bindings() { { -1 }, // reverserbackward { -1 }, + // waterpumpbreakertoggle + { GLFW_KEY_W | keymodifier::control }, + // waterpumpbreakerclose + { -1 }, + // waterpumpbreakeropen + { -1 }, + // waterpumptoggle + { GLFW_KEY_W }, + // waterpumpenable + { -1 }, + // waterpumpdisable + { -1 }, + // waterheaterbreakertoggle + { GLFW_KEY_W | keymodifier::control | keymodifier::shift }, + // waterheaterbreakerclose + { -1 }, + // waterheaterbreakeropen + { -1 }, + // waterheatertoggle + { GLFW_KEY_W | keymodifier::shift }, + // waterheaterenable + { -1 }, + // waterheaterdisable + { -1 }, + // watercircuitslinktoggle + { GLFW_KEY_H | keymodifier::shift }, + // watercircuitslinkenable + { -1 }, + // watercircuitslinkdisable + { -1 }, // fuelpumptoggle { GLFW_KEY_F }, // fuelpumpenable, diff --git a/mouseinput.cpp b/mouseinput.cpp index 5b2e6826..5e4ea8ee 100644 --- a/mouseinput.cpp +++ b/mouseinput.cpp @@ -243,6 +243,18 @@ mouse_input::default_bindings() { { "maxcurrent_sw:", { user_command::motoroverloadrelaythresholdtoggle, user_command::none } }, + { "waterpumpbreaker_sw:", { + user_command::waterpumpbreakertoggle, + user_command::none } }, + { "waterpump_sw:", { + user_command::waterpumptoggle, + user_command::none } }, + { "waterheaterbreaker_sw:", { + user_command::waterheaterbreakertoggle, + user_command::none } }, + { "waterheater_sw:", { + user_command::waterheatertoggle, + user_command::none } }, { "fuelpump_sw:", { user_command::fuelpumptoggle, user_command::none } }, diff --git a/translation.h b/translation.h index 2c1fd25b..d60c3fef 100644 --- a/translation.h +++ b/translation.h @@ -29,6 +29,11 @@ static std::unordered_map m_cabcontrols = { { "brakeprofileg_sw:", "brake acting speed: cargo" }, { "brakeprofiler_sw:", "brake acting speed: rapid" }, { "maxcurrent_sw:", "motor overload relay threshold" }, + { "waterpump_sw:", "water pump" }, + { "waterpumpbreaker_sw:", "water pump breaker" }, + { "waterheater_sw:", "water heater" }, + { "waterheaterbreaker_sw:", "water heater breaker" }, + { "watercircuitslink_sw:", "water circuits link" }, { "fuelpump_sw:", "fuel pump" }, { "oilpump_sw:", "oil pump" }, { "main_off_bt:", "line breaker" }, diff --git a/uilayer.cpp b/uilayer.cpp index b0a597b3..21b71d02 100644 --- a/uilayer.cpp +++ b/uilayer.cpp @@ -423,7 +423,9 @@ ui_layer::update() { uitextline2 += ( vehicle->MoverParameters->PantRearUp ? ( vehicle->MoverParameters->PantRearVolt > 0.0 ? "O" : "o" ) : "." ); uitextline2 += ( vehicle->MoverParameters->PantFrontUp ? ( vehicle->MoverParameters->PantFrontVolt > 0.0 ? "P" : "p" ) : "." ); uitextline2 += ( vehicle->MoverParameters->PantPressLockActive ? "!" : ( vehicle->MoverParameters->PantPressSwitchActive ? "*" : "." ) ); - uitextline2 += ( vehicle->MoverParameters->FuelPump.is_enabled ? ( vehicle->MoverParameters->FuelPump.is_active ? "F" : "f" ) : "." ); + uitextline2 += ( vehicle->MoverParameters->WaterPump.is_active ? "W" : ( false == vehicle->MoverParameters->WaterPump.breaker ? "-" : ( vehicle->MoverParameters->WaterPump.is_enabled ? "w" : "." ) ) ); + uitextline2 += ( true == vehicle->MoverParameters->WaterHeater.is_damaged ? "!" : ( vehicle->MoverParameters->WaterHeater.is_active ? "H" : ( false == vehicle->MoverParameters->WaterHeater.breaker ? "-" : ( vehicle->MoverParameters->WaterHeater.is_enabled ? "h" : "." ) ) ) ); + uitextline2 += ( vehicle->MoverParameters->FuelPump.is_active ? "F" : ( vehicle->MoverParameters->FuelPump.is_enabled ? "f" : "." ) ); uitextline2 += ( vehicle->MoverParameters->OilPump.is_active ? "O" : ( vehicle->MoverParameters->OilPump.is_enabled ? "o" : "." ) ); uitextline2 += ( false == vehicle->MoverParameters->ConverterAllowLocal ? "-" : ( vehicle->MoverParameters->ConverterAllow ? ( vehicle->MoverParameters->ConverterFlag ? "X" : "x" ) : "." ) ); uitextline2 += ( vehicle->MoverParameters->ConvOvldFlag ? "!" : "." ); @@ -673,7 +675,8 @@ ui_layer::update() { + ", PM=" + to_string( vehicle->MoverParameters->WheelFlat, 1 ) + " mm; enrot=" + to_string( vehicle->MoverParameters->enrot * 60, 0 ) + " tmrot=" + to_string( std::abs( vehicle->MoverParameters->nrot ) * vehicle->MoverParameters->Transmision.Ratio * 60, 0 ) - + "; ventrot=" + to_string( vehicle->MoverParameters->RventRot * 60, 1 ); + + "; ventrot=" + to_string( vehicle->MoverParameters->RventRot * 60, 1 ) + + "; fanrot=" + to_string( vehicle->MoverParameters->dizel_heat.rpmw, 1 ) + ", " + to_string( vehicle->MoverParameters->dizel_heat.rpmw2, 1 ); uitextline2 = "HamZ=" + to_string( vehicle->MoverParameters->fBrakeCtrlPos, 2 ) @@ -702,7 +705,12 @@ ui_layer::update() { /* uitextline2 += " eAngle=" + to_string( std::cos( vehicle->MoverParameters->eAngle ), 2 ); */ - uitextline2 += " oilP=" + to_string( vehicle->MoverParameters->OilPump.pressure_present, 3 ); + uitextline2 += "; oilP=" + to_string( vehicle->MoverParameters->OilPump.pressure_present, 3 ); + uitextline2 += " oilT=" + to_string( vehicle->MoverParameters->dizel_heat.To, 2 ); + uitextline2 += "; waterT=" + to_string( vehicle->MoverParameters->dizel_heat.temperatura1, 2 ); + uitextline2 += ( vehicle->MoverParameters->WaterCircuitsLink ? "-" : "|" ); + uitextline2 += to_string( vehicle->MoverParameters->dizel_heat.temperatura2, 2 ); + uitextline2 += "; engineT=" + to_string( vehicle->MoverParameters->dizel_heat.Ts, 2 ); uitextline3 = "cyl.ham. " + to_string( vehicle->MoverParameters->BrakePress, 2 )