diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index 9d2ae870..52a1753c 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -295,6 +295,14 @@ enum TProblem // lista problemów taboru, które uniemożliwiają jazdę pr_Ostatni = 0x80000000 // ostatnia flaga bitowa }; +enum TCompressorList // lista parametrów w programatorze sprężarek +{ // pozycje kolejne + cl_Allow = 0, // zezwolenie na pracę sprężarek + cl_SpeedFactor = 1, // mnożnik wydajności + cl_MinFactor = 2, // mnożnik progu załącznika ciśnieniowego + cl_MaxFactor = 3 // mnożnik progu wyłącznika ciśnieniowego +}; + /*ogolne*/ /*lokacja*/ struct TLocation @@ -1003,6 +1011,14 @@ public: double MinCompressor = 0.0; double MaxCompressor = 0.0; double CompressorSpeed = 0.0; + int CompressorList[4][9]; // pozycje świateł, przód - tył, 1 .. 16 + double EmergencyValveOn = 0.0; + double EmergencyValveOff = 0.0; + bool EmergencyValveOpen = false; + double EmergencyValveArea = 0.0; + int CompressorListPosNo = 0; + int CompressorListDefPos = 1; + bool CompressorListWrap = false; /*cisnienie wlaczania, zalaczania sprezarki, wydajnosc sprezarki*/ TBrakeDelayTable BrakeDelay; /*opoznienie hamowania/odhamowania t/o*/ double AirLeakRate{ 0.01 }; // base rate of air leak from brake system components ( 0.001 = 1 l/sec ) @@ -1297,7 +1313,8 @@ public: double MainsInitTimeCountdown{ 0.0 }; // current state of main circuit initialization, remaining time (in seconds) until it's ready int MainCtrlPos = 0; /*polozenie glownego nastawnika*/ int ScndCtrlPos = 0; /*polozenie dodatkowego nastawnika*/ - int LightsPos = 0; + int LightsPos = 0; /*polozenie przelacznika wielopozycyjnego swiatel*/ + int CompressorListPos = 0; /*polozenie przelacznika wielopozycyjnego sprezarek*/ int ActiveDir = 0; //czy lok. jest wlaczona i w ktorym kierunku: //względem wybranej kabiny: -1 - do tylu, +1 - do przodu, 0 - wylaczona int MaxMainCtrlPosNoDirChange { 0 }; // can't change reverser state with master controller set above this position @@ -1674,6 +1691,7 @@ private: void LoadFIZ_DList( std::string const &Input ); void LoadFIZ_FFList( std::string const &Input ); void LoadFIZ_LightsList( std::string const &Input ); + void LoadFIZ_CompressorList(std::string const &Input); void LoadFIZ_PowerParamsDecode( TPowerParameters &Powerparameters, std::string const Prefix, std::string const &Input ); TPowerType LoadFIZ_PowerDecode( std::string const &Power ); TPowerSource LoadFIZ_SourceDecode( std::string const &Source ); @@ -1690,6 +1708,7 @@ private: bool readFFList( std::string const &line ); bool readWWList( std::string const &line ); bool readLightsList( std::string const &Input ); + bool readCompressorList(std::string const &Input); void BrakeValveDecode( std::string const &s ); //Q 20160719 void BrakeSubsystemDecode(); //Q 20160719 bool EIMDirectionChangeAllow( void ); diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index 9c4f785b..682c97e9 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -420,6 +420,12 @@ ActiveCab( Cab ) for (int k = 0; k < 17; ++k) Lights[b][k] = 0; + for (int b = 0; b < 4; ++b) + for (int k = 1; k < 9; ++k) + CompressorList[ b ][ k ] = 0; + CompressorList[0][0] = 0.0; + CompressorList[1][0] = CompressorList[2][0] = CompressorList[3][0] = 1.0; + for (int b = -1; b <= MainBrakeMaxPos; ++b) { BrakePressureTable[b].PipePressureVal = 0.0; @@ -3529,12 +3535,31 @@ void TMoverParameters::UpdateBrakePressure(double dt) // TODO: clean the method up, a lot of the code is redundant void TMoverParameters::CompressorCheck(double dt) { + + double MaxCompressorF = CompressorList[TCompressorList::cl_MaxFactor][CompressorListPos] * MaxCompressor; + double MinCompressorF = CompressorList[TCompressorList::cl_MinFactor][CompressorListPos] * MinCompressor; + double CompressorSpeedF = CompressorList[TCompressorList::cl_SpeedFactor][CompressorListPos] * CompressorSpeed; + double AllowFactor = CompressorList[TCompressorList::cl_Allow][CompressorListPos]; + + //checking the impact on the compressor allowance + if (AllowFactor > 0.5) { + CompressorAllow = AllowFactor > 1.5; + } + if( VeselVolume == 0.0 ) { return; } + //EmergencyValve + EmergencyValveOpen = (Compressor > (EmergencyValveOpen ? EmergencyValveOff : EmergencyValveOn)); + if (EmergencyValveOpen) { + float dV = PF(0, Compressor, EmergencyValveArea)* dt; + CompressedVolume -= dV; + } + + CompressedVolume = std::max( 0.0, CompressedVolume - dt * AirLeakRate * 0.1 ); // nieszczelności: 0.001=1l/s if( ( true == CompressorGovernorLock ) - && ( Compressor < MinCompressor ) ) { + && ( Compressor < MinCompressorF ) ) { // if the pressure drops below the cut-in level, we can reset compressor governor // TBD, TODO: don't operate the lock without battery power? CompressorGovernorLock = false; @@ -3544,25 +3569,25 @@ void TMoverParameters::CompressorCheck(double dt) CompressorAllow = ConverterAllow; } - if (MaxCompressor - MinCompressor < 0.0001) { + if (MaxCompressorF - MinCompressorF < 0.0001) { // TODO: investigate purpose of this branch and whether it can be removed as it duplicates later code if( ( true == CompressorAllow ) && ( true == CompressorAllowLocal ) && ( true == Mains ) && ( MainCtrlPowerPos() > 0 ) ) { - if( Compressor < MaxCompressor ) { + if( Compressor < MaxCompressorF ) { if( ( EngineType == TEngineType::DieselElectric ) && ( CompressorPower > 0 ) ) { CompressedVolume += - CompressorSpeed - * ( 2.0 * MaxCompressor - Compressor ) / MaxCompressor + CompressorSpeedF + * ( 2.0 * MaxCompressorF - Compressor ) / MaxCompressorF * ( ( 60.0 * std::abs( enrot ) ) / DElist[ MainCtrlPosNo ].RPM ) * dt; } else { CompressedVolume += - CompressorSpeed - * ( 2.0 * MaxCompressor - Compressor ) / MaxCompressor + CompressorSpeedF + * ( 2.0 * MaxCompressorF - Compressor ) / MaxCompressorF * dt; TotalCurrent += 0.0015 * Voltage; // tymczasowo tylko obciążenie sprężarki, tak z 5A na sprężarkę } @@ -3614,7 +3639,7 @@ void TMoverParameters::CompressorCheck(double dt) || ( CompressorPower == 0 ) || ( CompressorPower == 3 ) ) ); - if( Compressor > MaxCompressor ) { + if( Compressor > MaxCompressorF ) { // wyłącznik ciśnieniowy jest niezależny od sposobu zasilania // TBD, TODO: don't operate the lock without battery power? if( CompressorPower == 3 ) { @@ -3650,8 +3675,8 @@ void TMoverParameters::CompressorCheck(double dt) else { // jeśli nie załączona if( ( LastSwitchingTime > CtrlDelay ) - && ( ( Compressor < MinCompressor ) - || ( ( Compressor < MaxCompressor ) + && ( ( Compressor < MinCompressorF ) + || ( ( Compressor < MaxCompressorF ) && ( false == CompressorGovernorLock ) ) ) ) { // załączenie przy małym ciśnieniu // jeśli nie załączona, a ciśnienie za małe @@ -3726,7 +3751,7 @@ void TMoverParameters::CompressorCheck(double dt) 1.0 ) }; // shouldn't ever get here but, eh CompressedVolume += CompressorSpeed - * ( 2.0 * MaxCompressor - Compressor ) / MaxCompressor + * ( 2.0 * MaxCompressorF - Compressor ) / MaxCompressorF * enginefactor * dt; } @@ -3740,8 +3765,8 @@ void TMoverParameters::CompressorCheck(double dt) else { // the compressor is a stand-alone device, working at steady pace CompressedVolume += - CompressorSpeed - * ( 2.0 * MaxCompressor - Compressor ) / MaxCompressor + CompressorSpeedF + * ( 2.0 * MaxCompressorF - Compressor ) / MaxCompressorF * dt; if( ( CompressorPower == 5 ) && ( Couplers[ 1 ].Connected != NULL ) ) { @@ -7802,6 +7827,7 @@ bool startMPT, startMPT0; bool startRLIST, startUCLIST; bool startDLIST, startFFLIST, startWWLIST; bool startLIGHTSLIST; +bool startCOMPRESSORLIST; int LISTLINE; bool issection( std::string const &Name, std::string const &Input ) { @@ -8101,12 +8127,33 @@ bool TMoverParameters::readLightsList( std::string const &Input ) { return false; } parser - >> Lights[ 0 ][ idx ] - >> Lights[ 1 ][ idx ]; + >> Lights[0][idx] + >> Lights[1][idx]; return true; } +bool TMoverParameters::readCompressorList(std::string const &Input) { + + cParser parser(Input); + if (false == parser.getTokens(4, false)) { + WriteLog("Read CompressorList: arguments missing in line " + std::to_string(LISTLINE + 1)); + return false; + } + int idx = LISTLINE++; + if (idx > 8) { + WriteLog("Read CompressorList: number of entries exceeded capacity of the data table"); + return false; + } + parser + >> CompressorList[ 0 ][ idx + 1 ] + >> CompressorList[ 1 ][ idx + 1 ] + >> CompressorList[ 2 ][ idx + 1 ] + >> CompressorList[ 3 ][ idx + 1 ]; + + return true; +} + // ************************************************************************************************* // Q: 20160719 // ************************************************************************************************* @@ -8213,6 +8260,7 @@ bool TMoverParameters::LoadFIZ(std::string chkpath) startFFLIST = false; startWWLIST = false; startLIGHTSLIST = false; + startCOMPRESSORLIST = false; std::string file = chkpath + TypeName + ".fiz"; WriteLog("LOAD FIZ FROM " + file); @@ -8301,6 +8349,11 @@ bool TMoverParameters::LoadFIZ(std::string chkpath) startLIGHTSLIST = false; continue; } + if ( issection( "endCL", inputline ) ) { + startBPT = false; + startCOMPRESSORLIST = false; + continue; + } // ...then all recognized sections... if( issection( "Param.", inputline ) ) { @@ -8532,6 +8585,14 @@ bool TMoverParameters::LoadFIZ(std::string chkpath) continue; } + if (issection("CompressorList:", inputline)) { + startBPT = false; + fizlines.emplace("CompressorList", inputline); + startCOMPRESSORLIST = true; LISTLINE = 0; + LoadFIZ_CompressorList( inputline ); + continue; + } + // ...and finally, table parsers. // NOTE: once table parsing is enabled it lasts until switched off, when another section is recognized if( true == startBPT ) { @@ -8570,6 +8631,10 @@ bool TMoverParameters::LoadFIZ(std::string chkpath) readLightsList( inputline ); continue; } + if (true == startCOMPRESSORLIST) { + readCompressorList(inputline); + continue; + } } // while line /* in.close(); @@ -8811,6 +8876,9 @@ void TMoverParameters::LoadFIZ_Brake( std::string const &line ) { extract_value( MinCompressor, "MinCP", line, "" ); extract_value( MaxCompressor, "MaxCP", line, "" ); extract_value( CompressorSpeed, "CompressorSpeed", line, "" ); + extract_value( EmergencyValveOff, "MinEVP", line, "" ); + extract_value( EmergencyValveOn, "MaxEVP", line, "" ); + extract_value( EmergencyValveArea, "EVArea", line, "" ); { std::map compressorpowers{ { "Main", 0 }, @@ -9664,6 +9732,13 @@ void TMoverParameters::LoadFIZ_LightsList( std::string const &Input ) { extract_value( LightsDefPos, "Default", Input, "" ); } +void TMoverParameters::LoadFIZ_CompressorList(std::string const &Input) { + + extract_value( CompressorListPosNo, "Size", Input, "" ); + extract_value( CompressorListWrap, "Wrap", Input, "" ); + extract_value( CompressorListDefPos, "Default", Input, "" ); +} + void TMoverParameters::LoadFIZ_PowerParamsDecode( TPowerParameters &Powerparameters, std::string const Prefix, std::string const &Line ) { switch( Powerparameters.SourceType ) { @@ -10030,6 +10105,8 @@ bool TMoverParameters::CheckLocomotiveParameters(bool ReadyFlag, int Dir) if( LightsPosNo > 0 ) LightsPos = LightsDefPos; + if (CompressorListPosNo > 0) + CompressorListPos = CompressorListDefPos; // NOTE: legacy compatibility behaviour for vehicles without defined heating power source if( ( EnginePowerSource.SourceType == TPowerSource::CurrentCollector ) diff --git a/Train.cpp b/Train.cpp index c582f4b8..e9900d8b 100644 --- a/Train.cpp +++ b/Train.cpp @@ -263,6 +263,9 @@ TTrain::commandhandler_map const TTrain::m_commandhandlers = { { user_command::compressorenable, &TTrain::OnCommand_compressorenable }, { user_command::compressordisable, &TTrain::OnCommand_compressordisable }, { user_command::compressortogglelocal, &TTrain::OnCommand_compressortogglelocal }, + { user_command::compressorpresetactivatenext, &TTrain::OnCommand_compressorpresetactivatenext }, + { user_command::compressorpresetactivateprevious, &TTrain::OnCommand_compressorpresetactivateprevious }, + { user_command::compressorpresetactivatedefault, &TTrain::OnCommand_compressorpresetactivatedefault }, { user_command::motorblowerstogglefront, &TTrain::OnCommand_motorblowerstogglefront }, { user_command::motorblowerstogglerear, &TTrain::OnCommand_motorblowerstogglerear }, { user_command::motorblowersdisableall, &TTrain::OnCommand_motorblowersdisableall }, @@ -2924,6 +2927,77 @@ void TTrain::OnCommand_compressortogglelocal( TTrain *Train, command_data const } } +void TTrain::OnCommand_compressorpresetactivatenext(TTrain *Train, command_data const &Command) { + + if (Train->mvOccupied->CompressorListPosNo == 0) { + // lights are controlled by preset selector + return; + } + if (Command.action != GLFW_PRESS) { + // one change per key press + return; + } + + if ((Train->mvOccupied->CompressorListPos < Train->mvOccupied->CompressorListPosNo) + || (true == Train->mvOccupied->CompressorListWrap)) { + // active light preset is stored as value in range 1-LigthPosNo + Train->mvOccupied->CompressorListPos = ( + Train->mvOccupied->CompressorListPos < Train->mvOccupied->CompressorListPosNo ? + Train->mvOccupied->CompressorListPos + 1 : + 1); // wrap mode + + // visual feedback + if (Train->ggCompressorListButton.SubModel != nullptr) { + Train->ggCompressorListButton.UpdateValue(Train->mvOccupied->CompressorListPos - 1, Train->dsbSwitch); + } + } +} + +void TTrain::OnCommand_compressorpresetactivateprevious(TTrain *Train, command_data const &Command) { + + if (Train->mvOccupied->CompressorListPosNo == 0) { + // lights are controlled by preset selector + return; + } + if (Command.action != GLFW_PRESS) { + // one change per key press + return; + } + + if ((Train->mvOccupied->CompressorListPos > 1) + || (true == Train->mvOccupied->CompressorListWrap)) { + // active light preset is stored as value in range 1-LigthPosNo + Train->mvOccupied->CompressorListPos = ( + Train->mvOccupied->CompressorListPos > 1 ? + Train->mvOccupied->CompressorListPos - 1 : + Train->mvOccupied->CompressorListPosNo); // wrap mode + + // visual feedback + if (Train->ggCompressorListButton.SubModel != nullptr) { + Train->ggCompressorListButton.UpdateValue(Train->mvOccupied->CompressorListPos - 1, Train->dsbSwitch); + } + } +} + +void TTrain::OnCommand_compressorpresetactivatedefault(TTrain *Train, command_data const &Command) { + + if (Train->mvOccupied->CompressorListPosNo == 0) { + // lights are controlled by preset selector + return; + } + if (Command.action != GLFW_PRESS) { + // one change per key press + return; + } + + Train->mvOccupied->CompressorListPos = Train->mvOccupied->CompressorListDefPos; + + // visual feedback + if (Train->ggCompressorListButton.SubModel != nullptr) { + Train->ggCompressorListButton.UpdateValue(Train->mvOccupied->CompressorListPos - 1, Train->dsbSwitch); + } +} + void TTrain::OnCommand_motorblowerstogglefront( TTrain *Train, command_data const &Command ) { if( Command.action == GLFW_REPEAT ) { return; } @@ -6232,6 +6306,7 @@ bool TTrain::Update( double const Deltatime ) // NBMX dzwignia sprezarki ggCompressorButton.Update(); ggCompressorLocalButton.Update(); + ggCompressorListButton.Update(); //--------- // hunter-080812: poprawka na ogrzewanie w elektrykach - usuniete uzaleznienie od przetwornicy @@ -7882,6 +7957,7 @@ void TTrain::set_cab_controls( int const Cab ) { mvControlled->CompressorAllowLocal ? 1.f : 0.f ); + ggCompressorListButton.PutValue(mvOccupied->CompressorListPos - 1); // motor overload relay threshold / shunt mode ggMaxCurrentCtrl.PutValue( ( true == mvControlled->ShuntModeAllow ? @@ -8296,6 +8372,7 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con { "rearrightend_sw:", ggRearRightEndLightButton }, { "compressor_sw:", ggCompressorButton }, { "compressorlocal_sw:", ggCompressorLocalButton }, + { "compressorlist_sw:", ggCompressorListButton }, { "converter_sw:", ggConverterButton }, { "converterlocal_sw:", ggConverterLocalButton }, { "converteroff_sw:", ggConverterOffButton }, diff --git a/Train.h b/Train.h index a696ebf8..8cc88e58 100644 --- a/Train.h +++ b/Train.h @@ -272,6 +272,9 @@ class TTrain { static void OnCommand_compressorenable( TTrain *Train, command_data const &Command ); static void OnCommand_compressordisable( TTrain *Train, command_data const &Command ); static void OnCommand_compressortogglelocal( TTrain *Train, command_data const &Command ); + static void OnCommand_compressorpresetactivatenext( TTrain *Train, command_data const &Command ); + static void OnCommand_compressorpresetactivateprevious( TTrain *Train, command_data const &Command ); + static void OnCommand_compressorpresetactivatedefault(TTrain *Train, command_data const &Command); static void OnCommand_motorblowerstogglefront( TTrain *Train, command_data const &Command ); static void OnCommand_motorblowersenablefront( TTrain *Train, command_data const &Command ); static void OnCommand_motorblowersdisablefront( TTrain *Train, command_data const &Command ); @@ -454,6 +457,7 @@ public: // reszta może by?publiczna TGauge ggCompressorButton; TGauge ggCompressorLocalButton; // controls only compressor of its own unit (et42-specific) + TGauge ggCompressorListButton; // controls compressors with various settings TGauge ggConverterButton; TGauge ggConverterLocalButton; // controls only converter of its own unit (et42-specific) TGauge ggConverterOffButton; diff --git a/command.cpp b/command.cpp index f34f24fa..60f75e7a 100644 --- a/command.cpp +++ b/command.cpp @@ -60,6 +60,9 @@ commanddescription_sequence Commands_descriptions = { { "alarmchaintoggle", command_target::vehicle, command_mode::oneoff }, { "wheelspinbrakeactivate", command_target::vehicle, command_mode::oneoff }, { "sandboxactivate", command_target::vehicle, command_mode::oneoff }, + { "autosandboxtoggle", command_target::vehicle, command_mode::oneoff }, + { "autosandboxactivate", command_target::vehicle, command_mode::oneoff }, + { "autosandboxdeactivate", command_target::vehicle, command_mode::oneoff }, { "reverserincrease", command_target::vehicle, command_mode::oneoff }, { "reverserdecrease", command_target::vehicle, command_mode::oneoff }, { "reverserforwardhigh", command_target::vehicle, command_mode::oneoff }, @@ -99,6 +102,9 @@ commanddescription_sequence Commands_descriptions = { { "compressorenable", command_target::vehicle, command_mode::oneoff }, { "compressordisable", command_target::vehicle, command_mode::oneoff }, { "compressortogglelocal", command_target::vehicle, command_mode::oneoff }, + { "compressorpresetactivatenext", command_target::vehicle, command_mode::oneoff }, + { "compressorpresetactivateprevious", command_target::vehicle, command_mode::oneoff }, + { "compressorpresetactivatedefault", command_target::vehicle, command_mode::oneoff }, { "motoroverloadrelaythresholdtoggle", command_target::vehicle, command_mode::oneoff }, { "motoroverloadrelaythresholdsetlow", command_target::vehicle, command_mode::oneoff }, { "motoroverloadrelaythresholdsethigh", command_target::vehicle, command_mode::oneoff }, diff --git a/command.h b/command.h index 478bdb6f..839860f0 100644 --- a/command.h +++ b/command.h @@ -54,6 +54,9 @@ enum class user_command { alarmchaintoggle, wheelspinbrakeactivate, sandboxactivate, + autosandboxtoggle, + autosandboxactivate, + autosandboxdeactivate, reverserincrease, reverserdecrease, reverserforwardhigh, @@ -93,6 +96,9 @@ enum class user_command { compressorenable, compressordisable, compressortogglelocal, + compressorpresetactivatenext, + compressorpresetactivateprevious, + compressorpresetactivatedefault, motoroverloadrelaythresholdtoggle, motoroverloadrelaythresholdsetlow, motoroverloadrelaythresholdsethigh, diff --git a/drivermouseinput.cpp b/drivermouseinput.cpp index cd5d2d7d..4487dc96 100644 --- a/drivermouseinput.cpp +++ b/drivermouseinput.cpp @@ -689,6 +689,9 @@ drivermouse_input::default_bindings() { { "compressorlocal_sw:", { user_command::compressortogglelocal, user_command::none } }, + { "compressorlist_sw:", { + user_command::compressorpresetactivatenext, + user_command::compressorpresetactivateprevious } }, { "converter_sw:", { user_command::convertertoggle, user_command::none } },