diff --git a/Button.cpp b/Button.cpp index 7ff6a3e9..cddcee09 100644 --- a/Button.cpp +++ b/Button.cpp @@ -132,6 +132,7 @@ void TButton::Update() { if( pModelOn != nullptr ) { pModelOn->iVisible = m_state; } if( pModelOff != nullptr ) { pModelOff->iVisible = (!m_state); } +#ifdef _WIN32 if (iFeedbackBit) { // jeżeli generuje informację zwrotną if (m_state) // zapalenie @@ -139,6 +140,7 @@ void TButton::Update() { else Console::BitsClear(iFeedbackBit); } +#endif }; void TButton::AssignBool(bool const *bValue) { diff --git a/Button.h b/Button.h index 5ac94579..7eced4e4 100644 --- a/Button.h +++ b/Button.h @@ -19,10 +19,14 @@ public: // methods TButton() = default; void Clear(int const i = -1); - inline void FeedbackBitSet( int const i ) { + inline + void FeedbackBitSet( int const i ) { iFeedbackBit = 1 << i; }; void Turn( bool const State ); inline + bool GetValue() const { + return ( m_state ? 1 : 0 ); } + inline bool Active() { return ( ( pModelOn != nullptr ) || ( pModelOff != nullptr ) ); } diff --git a/Console.cpp b/Console.cpp index 94712fa6..5dc0cd3e 100644 --- a/Console.cpp +++ b/Console.cpp @@ -12,7 +12,6 @@ http://mozilla.org/MPL/2.0/. #include "Globals.h" #include "LPT.h" #include "Logs.h" -#include "MWD.h" // maciek001: obsluga portu COM #include "PoKeys55.h" #include "utilities.h" @@ -54,31 +53,6 @@ Działanie jest następujące: /*******************************/ -/* //kod do przetrawienia: -//aby się nie włączacz wygaszacz ekranu, co jakiś czas naciska się wirtualnie ScrollLock - -[DllImport("user32.dll")] -static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, UIntPtr dwExtraInfo); - -private static void PressScrollLock() -{//przyciska i zwalnia ScrollLock - const byte vkScroll = 0x91; - const byte keyeventfKeyup = 0x2; - keybd_event(vkScroll, 0x45, 0, (UIntPtr)0); - keybd_event(vkScroll, 0x45, keyeventfKeyup, (UIntPtr)0); -}; - -[DllImport("user32.dll")] -private static extern bool SystemParametersInfo(int uAction,int uParam,int &lpvParam,int flags); - -public static Int32 GetScreenSaverTimeout() -{ - Int32 value=0; - SystemParametersInfo(14,0,&value,0); - return value; -}; -*/ - // static class member storage allocation TKeyTrans Console::ktTable[4 * 256]; @@ -99,7 +73,6 @@ int Console::iMode = 0; int Console::iConfig = 0; TPoKeys55 *Console::PoKeys55[2] = {NULL, NULL}; TLPT *Console::LPT = NULL; -TMWDComm *Console::MWDComm = NULL; // maciek001: obiekt dla MWD int Console::iSwitch[8]; // bistabilne w kabinie, załączane z [Shift], wyłączane bez int Console::iButton[8]; // monostabilne w kabinie, załączane podczas trzymania klawisza @@ -111,14 +84,12 @@ Console::Console() iSwitch[i] = 0; // bity 0..127 - bez [Ctrl], 128..255 - z [Ctrl] iButton[i] = 0; // bity 0..127 - bez [Shift], 128..255 - z [Shift] } - MWDComm = NULL; }; Console::~Console() { delete PoKeys55[0]; delete PoKeys55[1]; - delete MWDComm; }; void Console::ModeSet(int m, int h) @@ -166,18 +137,6 @@ int Console::On() break; } - if (Global.bMWDmasterEnable) - { - WriteLog("Opening ComPort"); - MWDComm = new TMWDComm(); - if (!(MWDComm->Open())) // jeżeli nie otwarł portu - { - WriteLog("ERROR: ComPort is NOT OPEN!"); - delete MWDComm; - MWDComm = NULL; - } - } - return 0; }; @@ -190,14 +149,9 @@ void Console::Off() SetLedState(VK_SCROLL, true); // przyciśnięty SetLedState(VK_SCROLL, false); // zwolniony } - delete PoKeys55[0]; - PoKeys55[0] = NULL; - delete PoKeys55[1]; - PoKeys55[1] = NULL; - delete LPT; - LPT = NULL; - delete MWDComm; - MWDComm = NULL; + SafeDelete( PoKeys55[0] ); + SafeDelete( PoKeys55[1] ); + SafeDelete( LPT ); }; void Console::BitsSet(int mask, int entry) @@ -289,56 +243,6 @@ void Console::BitsUpdate(int mask) } break; } - if (Global.bMWDmasterEnable) - { - // maciek001: MWDComm lampki i kontrolki - // out3: ogrzewanie sk?adu, opory rozruchowe, poslizg, zaluzjewent, -, -, czuwak, shp - // out4: stycz.liniowe, pezekaznikr??nicobwpomoc, nadmiarprzetw, roznicowy obw. g?, nadmiarsilniki, wylszybki, zanikpr?duprzyje?dzienaoporach, nadmiarsprezarki - // out5: HASLER */ - if (mask & 0x0001) if (iBits & 1) { - MWDComm->WriteDataBuff[4] |= 1 << 7; // SHP HASLER też - if (!MWDComm->bSHPstate) { - MWDComm->bSHPstate = true; - MWDComm->bPrzejazdSHP = true; - } - else MWDComm->bPrzejazdSHP = false; - } - else { - MWDComm->WriteDataBuff[4] &= ~(1 << 7); - MWDComm->bPrzejazdSHP = false; - MWDComm->bSHPstate = false; - } - if (mask & 0x0002) if (iBits & 2) MWDComm->WriteDataBuff[4] |= 1 << 6; // CA - else MWDComm->WriteDataBuff[4] &= ~(1 << 6); - if (mask & 0x0004) if (iBits & 4) MWDComm->WriteDataBuff[4] |= 1 << 1; // jazda na oporach rozruchowych - else MWDComm->WriteDataBuff[4] &= ~(1 << 1); - if (mask & 0x0008) if (iBits & 8) MWDComm->WriteDataBuff[5] |= 1 << 5; // wyłącznik szybki - else MWDComm->WriteDataBuff[5] &= ~(1 << 5); - if (mask & 0x0010) if (iBits & 0x10) MWDComm->WriteDataBuff[5] |= 1 << 4; // nadmiarowy silników trakcyjnych - else MWDComm->WriteDataBuff[5] &= ~(1 << 4); - if (mask & 0x0020) if (iBits & 0x20) MWDComm->WriteDataBuff[5] |= 1 << 0; // styczniki liniowe - else MWDComm->WriteDataBuff[5] &= ~(1 << 0); - if (mask & 0x0040) if (iBits & 0x40) MWDComm->WriteDataBuff[4] |= 1 << 2; // poślizg - else MWDComm->WriteDataBuff[4] &= ~(1 << 2); - if (mask & 0x0080) if (iBits & 0x80) MWDComm->WriteDataBuff[5] |= 1 << 2; // (nadmiarowy) przetwornicy? ++ - else MWDComm->WriteDataBuff[5] &= ~(1 << 2); - if (mask & 0x0100) if (iBits & 0x100) MWDComm->WriteDataBuff[5] |= 1 << 7; // nadmiarowy sprężarki - else MWDComm->WriteDataBuff[5] &= ~(1 << 7); - if (mask & 0x0200) if (iBits & 0x200) MWDComm->WriteDataBuff[2] |= 1 << 1; // wentylatory i opory - else MWDComm->WriteDataBuff[2] &= ~(1 << 1); - if (mask & 0x0400) if (iBits & 0x400) MWDComm->WriteDataBuff[2] |= 1 << 2; // wysoki rozruch - else MWDComm->WriteDataBuff[2] &= ~(1 << 2); - if (mask & 0x0800) if (iBits & 0x800) MWDComm->WriteDataBuff[4] |= 1 << 0; // ogrzewanie pociągu - else MWDComm->WriteDataBuff[4] &= ~(1 << 0); - if (mask & 0x1000) if (iBits & 0x1000) MWDComm->bHamowanie = true; // hasler: ciśnienie w hamulcach HASLER rysik 2 - else MWDComm->bHamowanie = false; - if (mask & 0x2000) if (iBits & 0x2000) MWDComm->WriteDataBuff[6] |= 1 << 4; // hasler: prąd "na" silnikach - HASLER rysik 3 - else MWDComm->WriteDataBuff[6] &= ~(1 << 4); - if (mask & 0x4000) if (iBits & 0x4000) MWDComm->WriteDataBuff[6] |= 1 << 7; // brzęczyk SHP/CA - else MWDComm->WriteDataBuff[6] &= ~(1 << 7); - //if(mask & 0x8000) if(iBits & 0x8000) MWDComm->WriteDataBuff[1] |= 1<<7; (puste) - //else MWDComm->WriteDataBuff[0] &= ~(1<<7); - } }; bool Console::Pressed(int x) @@ -351,85 +255,39 @@ bool Console::Pressed(int x) void Console::ValueSet(int x, double y) { // ustawienie wartości (y) na kanale analogowym (x) - if (iMode == 4) - if (PoKeys55[0]) - { - x = Global.iPoKeysPWM[x]; - if (Global.iCalibrateOutDebugInfo == x) - WriteLog("CalibrateOutDebugInfo: oryginal=" + std::to_string(y)); - if (Global.fCalibrateOutMax[x] > 0) - { - y = clamp( y, 0.0, Global.fCalibrateOutMax[x]); - if (Global.iCalibrateOutDebugInfo == x) - WriteLog(" cutted=" + std::to_string(y)); - y = y / Global.fCalibrateOutMax[x]; // sprowadzenie do <0,1> jeśli podana - // maksymalna wartość - if (Global.iCalibrateOutDebugInfo == x) - WriteLog(" fraction=" + std::to_string(y)); - } - double temp = (((((Global.fCalibrateOut[x][5] * y) + Global.fCalibrateOut[x][4]) * y + - Global.fCalibrateOut[x][3]) * - y + - Global.fCalibrateOut[x][2]) * - y + - Global.fCalibrateOut[x][1]) * - y + - Global.fCalibrateOut[x][0]; // zakres <0;1> - if (Global.iCalibrateOutDebugInfo == x) - WriteLog(" calibrated=" + std::to_string(temp)); - PoKeys55[0]->PWM(x, temp); + if( iMode != 4 ) { return; } + + if (PoKeys55[0]) + { + x = Global.iPoKeysPWM[x]; + if( Global.iCalibrateOutDebugInfo == x ) { + WriteLog( "CalibrateOutDebugInfo: oryginal=" + std::to_string( y ) ); } - if (Global.bMWDmasterEnable) - { - unsigned int iliczba; - switch (x) - { - case 0: iliczba = (unsigned int)floor((y / (Global.fMWDzg[0] * 10) * Global.fMWDzg[1]) + 0.5); // zbiornik główny - MWDComm->WriteDataBuff[12] = (unsigned char)(iliczba >> 8); - MWDComm->WriteDataBuff[11] = (unsigned char)iliczba; - if (Global.bMWDmasterEnable && Global.iMWDDebugMode & 8) WriteLog("Main tank press " + to_string(MWDComm->WriteDataBuff[12]) + " " + to_string(MWDComm->WriteDataBuff[11])); - break; - case 1: iliczba = (unsigned int)floor((y / (Global.fMWDpg[0] * 10) * Global.fMWDpg[1]) + 0.5); // przewód główny - MWDComm->WriteDataBuff[10] = (unsigned char)(iliczba >> 8); - MWDComm->WriteDataBuff[9] = (unsigned char)iliczba; - if (Global.bMWDmasterEnable && Global.iMWDDebugMode & 8) WriteLog("Main pipe press " + to_string(MWDComm->WriteDataBuff[10]) + " " + to_string(MWDComm->WriteDataBuff[9])); - break; - case 2: iliczba = (unsigned int)floor((y / (Global.fMWDph[0] * 10) * Global.fMWDph[1]) + 0.5); // cylinder hamulcowy - MWDComm->WriteDataBuff[8] = (unsigned char)(iliczba >> 8); - MWDComm->WriteDataBuff[7] = (unsigned char)iliczba; - if (Global.bMWDmasterEnable && Global.iMWDDebugMode & 8) WriteLog("Break press " + to_string(MWDComm->WriteDataBuff[8]) + " " + to_string(MWDComm->WriteDataBuff[7])); - break; - case 3: iliczba = (unsigned int)floor((y / Global.fMWDvolt[0] * Global.fMWDvolt[1]) + 0.5); // woltomierz WN - MWDComm->WriteDataBuff[14] = (unsigned char)(iliczba >> 8); - MWDComm->WriteDataBuff[13] = (unsigned char)iliczba; - if (Global.bMWDmasterEnable && Global.iMWDDebugMode & 8) WriteLog("Hi Volt meter " + to_string(MWDComm->WriteDataBuff[14]) + " " + to_string(MWDComm->WriteDataBuff[13])); - break; - case 4: iliczba = (unsigned int)floor((y / Global.fMWDamp[0] * Global.fMWDamp[1]) + 0.5); // amp WN 1 - MWDComm->WriteDataBuff[16] = (unsigned char)(iliczba >> 8); - MWDComm->WriteDataBuff[15] = (unsigned char)iliczba; - if (Global.bMWDmasterEnable && Global.iMWDDebugMode & 8) WriteLog("Apm meter1 " + to_string(MWDComm->WriteDataBuff[16]) + " " + to_string(MWDComm->WriteDataBuff[15])); - break; - case 5: iliczba = (unsigned int)floor((y / Global.fMWDamp[0] * Global.fMWDamp[1]) + 0.5); // amp WN 2 - MWDComm->WriteDataBuff[18] = (unsigned char)(iliczba >> 8); - MWDComm->WriteDataBuff[17] = (unsigned char)iliczba; - if (Global.bMWDmasterEnable && Global.iMWDDebugMode & 8) WriteLog("Apm meter2 " + to_string(MWDComm->WriteDataBuff[18]) + " " + to_string(MWDComm->WriteDataBuff[17])); - break; - case 6: iliczba = (unsigned int)floor((y / Global.fMWDamp[0] * Global.fMWDamp[1]) + 0.5); // amp WN 3 - MWDComm->WriteDataBuff[20] = (unsigned int)(iliczba >> 8); - MWDComm->WriteDataBuff[19] = (unsigned char)iliczba; - if (Global.bMWDmasterEnable && Global.iMWDDebugMode & 8) WriteLog("Apm meter3 " + to_string(MWDComm->WriteDataBuff[20]) + " " + to_string(MWDComm->WriteDataBuff[19])); - break; - case 7: if (Global.iPause) MWDComm->WriteDataBuff[0] = 0; //skoro pauza to hasler stoi i nie nabija kilometrów CHYBA NIE DZIAŁA! - else MWDComm->WriteDataBuff[0] = (unsigned char)floor(y); // prędkość dla np haslera - if (Global.bMWDmasterEnable && Global.iMWDDebugMode & 8) WriteLog("Speed: " + to_string(MWDComm->WriteDataBuff[0])); - break; - case 8: iliczba = (unsigned int)floor((y / Global.fMWDlowVolt[0] * Global.fMWDlowVolt[1]) + 0.5); // volt NN - MWDComm->WriteDataBuff[22] = (unsigned int)(iliczba >> 8); - MWDComm->WriteDataBuff[21] = (unsigned char)iliczba; - if (Global.bMWDmasterEnable && Global.iMWDDebugMode & 8) WriteLog("Low Volt meter " + to_string(MWDComm->WriteDataBuff[22]) + " " + to_string(MWDComm->WriteDataBuff[21])); - break; // przygotowane do wdrożenia, jeszcze nie wywoływane - } - } + if (Global.fCalibrateOutMax[x] > 0) + { + y = clamp( y, 0.0, Global.fCalibrateOutMax[x]); + if( Global.iCalibrateOutDebugInfo == x ) { + WriteLog( " cutted=" + std::to_string( y ) ); + } + // sprowadzenie do <0,1> jeśli podana maksymalna wartość + y = y / Global.fCalibrateOutMax[x]; + if( Global.iCalibrateOutDebugInfo == x ) { + WriteLog( " fraction=" + std::to_string( y ) ); + } + } + double temp = (((((Global.fCalibrateOut[x][5] * y) + Global.fCalibrateOut[x][4]) * y + + Global.fCalibrateOut[x][3]) * + y + + Global.fCalibrateOut[x][2]) * + y + + Global.fCalibrateOut[x][1]) * + y + + Global.fCalibrateOut[x][0]; // zakres <0;1> + if( Global.iCalibrateOutDebugInfo == x ) { + WriteLog( " calibrated=" + std::to_string( temp ) ); + } + PoKeys55[0]->PWM(x, temp); + } }; void Console::Update() @@ -447,11 +305,6 @@ void Console::Update() Global.iPause |= 8; // tak??? PoKeys55[0]->Connect(); // próba ponownego podłączenia } - if (Global.bMWDmasterEnable) - { - if (MWDComm->GetMWDState()) MWDComm->Run(); - else MWDComm->Close(); - } }; float Console::AnalogGet(int x) @@ -476,11 +329,6 @@ float Console::AnalogCalibrateGet(int x) if (x == 1) return b/10; else return b; } - if (Global.bMWDmasterEnable && Global.bMWDBreakEnable) - { - float b = (float)MWDComm->uiAnalog[x]; - return (b - Global.fMWDAnalogInCalib[x][0]) / (Global.fMWDAnalogInCalib[x][1] - Global.fMWDAnalogInCalib[x][0]); - } return -1.0; // odcięcie }; @@ -515,6 +363,7 @@ void Console::OnKeyDown(int k) } } }; + void Console::OnKeyUp(int k) { // puszczenie klawisza w zasadzie nie ma znaczenia dla iSwitch, ale zeruje iButton if ((k & 0x20000) == 0) // monostabilne tylko bez [Ctrl] @@ -523,10 +372,12 @@ void Console::OnKeyUp(int k) else iButton[char(k) >> 5] &= ~(1 << (k & 31)); // wyłącz monostabilny podstawowy }; + int Console::KeyDownConvert(int k) { return int(ktTable[k & 0x3FF].iDown); }; + int Console::KeyUpConvert(int k) { return int(ktTable[k & 0x3FF].iUp); diff --git a/Console.h b/Console.h index aedaff1f..fd9f6631 100644 --- a/Console.h +++ b/Console.h @@ -13,7 +13,6 @@ http://mozilla.org/MPL/2.0/. class TConsoleDevice; // urządzenie podłączalne za pomocą DLL class TPoKeys55; class TLPT; -class TMWDComm; // maciek001: dodana obsluga portu COM // klasy konwersji znaków wprowadzanych z klawiatury class TKeyTrans @@ -32,7 +31,6 @@ class Console static int iBits; // podstawowy zestaw lampek static TPoKeys55 *PoKeys55[2]; // może ich być kilka static TLPT *LPT; - static TMWDComm *MWDComm; // maciek001: na potrzeby MWD static void BitsUpdate(int mask); // zmienne dla trybu "jednokabinowego", potrzebne do współpracy z pulpitem (PoKeys) // używając klawiatury, każdy pojazd powinien mieć własny stan przełączników diff --git a/EU07.cpp b/EU07.cpp index 966256bc..ab3af211 100644 --- a/EU07.cpp +++ b/EU07.cpp @@ -32,6 +32,7 @@ Stele, firleju, szociu, hunter, ZiomalCl, OLI_EU and others #include "mouseinput.h" #include "gamepadinput.h" #include "Console.h" +#include "uart.h" #include "PyInt.h" #ifdef EU07_BUILD_STATIC @@ -50,6 +51,7 @@ Stele, firleju, szociu, hunter, ZiomalCl, OLI_EU and others #pragma comment( lib, "openal32.lib") #pragma comment( lib, "setupapi.lib" ) #pragma comment( lib, "python27.lib" ) +#pragma comment( lib, "libserialport-0.lib" ) #pragma comment (lib, "dbghelp.lib") #pragma comment (lib, "version.lib") #ifdef CAN_I_HAS_LIBPNG @@ -68,6 +70,7 @@ keyboard_input Keyboard; mouse_input Mouse; gamepad_input Gamepad; glm::dvec2 mouse_pickmodepos; // stores last mouse position in control picking mode +std::unique_ptr uart; } @@ -411,6 +414,9 @@ int main(int argc, char *argv[]) input::Keyboard.init(); input::Mouse.init(); input::Gamepad.init(); + if( true == Global.uart_conf.enable ) { + input::uart = std::make_unique(); + } Global.pWorld = &World; // Ra: wskaźnik potrzebny do usuwania pojazdów try { @@ -443,6 +449,7 @@ int main(int argc, char *argv[]) input::Keyboard.poll(); if( true == Global.InputMouse ) { input::Mouse.poll(); } if( true == Global.InputGamepad ) { input::Gamepad.poll(); } + if( input::uart != nullptr ) { input::uart->poll(); } } } catch( std::bad_alloc const &Error ) { diff --git a/Globals.cpp b/Globals.cpp index e40eb860..62c33e69 100644 --- a/Globals.cpp +++ b/Globals.cpp @@ -579,102 +579,44 @@ global_settings::ConfigParse(cParser &Parser) { Parser.getTokens(); Parser >> InputGamepad; } - // maciek001: ustawienia MWD - else if (token == "mwdmasterenable") { // główne włączenie maszyny! - Parser.getTokens(); - Parser >> bMWDmasterEnable; - if (bMWDdebugEnable) WriteLog("SerialPort Master Enable"); - } - else if (token == "mwddebugenable") { // logowanie pracy - Parser.getTokens(); - Parser >> bMWDdebugEnable; - if (bMWDdebugEnable) WriteLog("MWD Debug Mode On"); - } - else if (token == "mwddebugmode") { // co ma być debugowane? - Parser.getTokens(1, false); - Parser >> iMWDDebugMode; - if (bMWDdebugEnable) WriteLog("Debug Mode = " + to_string(iMWDDebugMode)); - } - else if (token == "mwdcomportname") { // nazwa portu COM - Parser.getTokens(); - Parser >> sMWDPortId; - if (bMWDdebugEnable) WriteLog("PortName " + sMWDPortId); - } - else if (token == "mwdbaudrate") { // prędkość transmisji danych - Parser.getTokens(1, false); - Parser >> iMWDBaudrate; - if (bMWDdebugEnable) WriteLog("Baud rate = " + to_string((int)(iMWDBaudrate / 1000)) + (" kbps")); - } - else if (token == "mwdinputenable") { // włącz wejścia - Parser.getTokens(); - Parser >> bMWDInputEnable; - if (bMWDdebugEnable && bMWDInputEnable) WriteLog("MWD Input Enable"); - } - else if (token == "mwdbreakenable") { // włącz obsługę hamulców - Parser.getTokens(); - Parser >> bMWDBreakEnable; - if (bMWDdebugEnable && bMWDBreakEnable) WriteLog("MWD Break Enable"); - } - else if (token == "mwdmainbreakconfig") { // ustawienia hamulca zespolonego - Parser.getTokens(2, false); - Parser >> fMWDAnalogInCalib[0][0] >> fMWDAnalogInCalib[0][1]; - if (bMWDdebugEnable) WriteLog("Main break settings: " + to_string(fMWDAnalogInCalib[0][0]) + (" ") + to_string(fMWDAnalogInCalib[0][1])); - } - else if (token == "mwdlocbreakconfig") { // ustawienia hamulca lokomotywy - Parser.getTokens(2, false); - Parser >> fMWDAnalogInCalib[1][0] >> fMWDAnalogInCalib[1][1]; - if (bMWDdebugEnable) WriteLog("Locomotive break settings: " + to_string(fMWDAnalogInCalib[1][0]) + (" ") + to_string(fMWDAnalogInCalib[1][1])); - } - else if (token == "mwdanalogin1config") { // ustawienia hamulca zespolonego - Parser.getTokens(2, false); - Parser >> fMWDAnalogInCalib[2][0] >> fMWDAnalogInCalib[2][1]; - if (bMWDdebugEnable) WriteLog("Analog input 1 settings: " + to_string(fMWDAnalogInCalib[2][0]) + (" ") + to_string(fMWDAnalogInCalib[2][1])); - } - else if (token == "mwdanalogin2config") { // ustawienia hamulca lokomotywy - Parser.getTokens(2, false); - Parser >> fMWDAnalogInCalib[3][0] >> fMWDAnalogInCalib[3][1]; - if (bMWDdebugEnable) WriteLog("Analog input 2 settings: " + to_string(fMWDAnalogInCalib[3][0]) + (" ") + to_string(fMWDAnalogInCalib[3][1])); - } - else if (token == "mwdmaintankpress") { // max ciśnienie w zbiorniku głownym i rozdzielczość - Parser.getTokens(2, false); - Parser >> fMWDzg[0] >> fMWDzg[1]; - if (bMWDdebugEnable) WriteLog("MainAirTank settings: " + to_string(fMWDzg[0]) + (" ") + to_string(fMWDzg[1])); - } - else if (token == "mwdmainpipepress") { // max ciśnienie w przewodzie głownym i rozdzielczość - Parser.getTokens(2, false); - Parser >> fMWDpg[0] >> fMWDpg[1]; - if (bMWDdebugEnable) WriteLog("MainAirPipe settings: " + to_string(fMWDpg[0]) + (" ") + to_string(fMWDpg[1])); - } - else if (token == "mwdbreakpress") { // max ciśnienie w hamulcach i rozdzielczość - Parser.getTokens(2, false); - Parser >> fMWDph[0] >> fMWDph[1]; - if (bMWDdebugEnable) WriteLog("AirPipe settings: " + to_string(fMWDph[0]) + (" ") + to_string(fMWDph[1])); - } - else if (token == "mwdhivoltmeter") { // max napięcie na woltomierzu WN - Parser.getTokens(2, false); - Parser >> fMWDvolt[0] >> fMWDvolt[1]; - if (bMWDdebugEnable) WriteLog("VoltMeter settings: " + to_string(fMWDvolt[0]) + (" ") + to_string(fMWDvolt[1])); - } - else if (token == "mwdhiampmeter") { - Parser.getTokens(2, false); - Parser >> fMWDamp[0] >> fMWDamp[1]; - if (bMWDdebugEnable) WriteLog("Amp settings: " + to_string(fMWDamp[0]) + (" ") + to_string(fMWDamp[1])); - } - else if (token == "mwdlowvoltmeter") { - Parser.getTokens(2, false); - Parser >> fMWDlowVolt[0] >> fMWDlowVolt[1]; - if (bMWDdebugEnable) WriteLog("Low VoltMeter settings: " + to_string(fMWDlowVolt[0]) + (" ") + to_string(fMWDlowVolt[1])); - } - else if (token == "mwddivider") { - Parser.getTokens(1, false); - Parser >> iMWDdivider; - if (iMWDdivider == 0) - { - WriteLog("Dzielnik nie może być równy ZERO! Ustawiam na 1!"); - iMWDdivider = 1; - } - if (bMWDdebugEnable) WriteLog("Divider = " + to_string(iMWDdivider)); - } + else if( token == "uart" ) { + uart_conf.enable = true; + Parser.getTokens( 3, false ); + Parser + >> uart_conf.port + >> uart_conf.baud + >> uart_conf.updatetime; + } + else if( token == "uarttune" ) { + Parser.getTokens( 14 ); + Parser + >> uart_conf.mainbrakemin + >> uart_conf.mainbrakemax + >> uart_conf.localbrakemin + >> uart_conf.localbrakemax + >> uart_conf.tankmax + >> uart_conf.tankuart + >> uart_conf.pipemax + >> uart_conf.pipeuart + >> uart_conf.brakemax + >> uart_conf.brakeuart + >> uart_conf.hvmax + >> uart_conf.hvuart + >> uart_conf.currentmax + >> uart_conf.currentuart; + } + else if( token == "uartfeature" ) { + Parser.getTokens( 4 ); + Parser + >> uart_conf.mainenable + >> uart_conf.scndenable + >> uart_conf.trainenable + >> uart_conf.localenable; + } + else if( token == "uartdebug" ) { + Parser.getTokens( 1 ); + Parser >> uart_conf.debug; + } } while ((token != "") && (token != "endconfig")); //(!Parser->EndOfFile) // na koniec trochę zależności if (!bLoadTraction) // wczytywanie drutów i słupów diff --git a/Globals.h b/Globals.h index 19ecd7b3..59a8a487 100644 --- a/Globals.h +++ b/Globals.h @@ -13,6 +13,7 @@ http://mozilla.org/MPL/2.0/. #include "dumb3d.h" #include "float3d.h" #include "light.h" +#include "uart.h" #include "utilities.h" struct global_settings { @@ -60,8 +61,6 @@ struct global_settings { int iWriteLogEnabled{ 3 }; // maska bitowa: 1-zapis do pliku, 2-okienko, 4-nazwy torów bool MultipleLogs{ false }; unsigned int DisabledLogTypes{ 0 }; - bool bMWDdebugEnable{ false }; // włącz dodawanie do logu - int iMWDDebugMode{ 0 }; // co ma wyświetlać w logu // simulation bool RealisticControlMode{ false }; // controls ability to steer the vehicle from outside views bool bFreeFly{ false }; @@ -159,25 +158,7 @@ struct global_settings { 0, 0, 0, 0, 0, 0, 0 }; int iCalibrateOutDebugInfo { -1 }; // numer wyjścia kalibrowanego dla którego wyświetlać informacje podczas kalibracji int iPoKeysPWM[ 7 ] = { 0, 1, 2, 3, 4, 5, 6 }; // numery wejść dla PWM - // maciek001: konfiguracja wstępna portu COM - bool bMWDmasterEnable { false };// główne włączenie portu! - std::string sMWDPortId { "COM1" }; // nazwa portu z którego korzystamy - unsigned long int iMWDBaudrate{ 9600 }; // prędkość transmisji danych - bool bMWDInputEnable { false }; // włącz wejścia - bool bMWDBreakEnable { false }; // włącz wejścia analogowe - // wartość max potencjometru, wartość min potencjometru, rozdzielczość (max. wartość jaka może być) - double fMWDAnalogInCalib[ 4 ][ 2 ] = { - { 0, 1023 }, - { 0, 1023 }, - { 0, 1023 }, - { 0, 1023 } }; - double fMWDzg[ 2 ] = { 0.9, 1023 }; - double fMWDpg[ 2 ] = { 0.8, 1023 }; - double fMWDph[ 2 ] = { 0.6, 1023 }; - double fMWDvolt[ 2 ] = { 4000, 1023 }; - double fMWDamp[ 2 ] = { 800, 1023 }; - double fMWDlowVolt[ 2 ] = { 150, 1023 }; - int iMWDdivider { 5 }; + uart_input::conf_t uart_conf; // multiplayer int iMultiplayer{ 0 }; // blokada działania niektórych eventów na rzecz kominikacji // other diff --git a/Train.cpp b/Train.cpp index a121654d..100df383 100644 --- a/Train.cpp +++ b/Train.cpp @@ -159,19 +159,23 @@ TTrain::commandhandler_map const TTrain::m_commandhandlers = { { user_command::mastercontrollerincreasefast, &TTrain::OnCommand_mastercontrollerincreasefast }, { user_command::mastercontrollerdecrease, &TTrain::OnCommand_mastercontrollerdecrease }, { user_command::mastercontrollerdecreasefast, &TTrain::OnCommand_mastercontrollerdecreasefast }, + { user_command::mastercontrollerset, &TTrain::OnCommand_mastercontrollerset }, { user_command::secondcontrollerincrease, &TTrain::OnCommand_secondcontrollerincrease }, { user_command::secondcontrollerincreasefast, &TTrain::OnCommand_secondcontrollerincreasefast }, { user_command::secondcontrollerdecrease, &TTrain::OnCommand_secondcontrollerdecrease }, { user_command::secondcontrollerdecreasefast, &TTrain::OnCommand_secondcontrollerdecreasefast }, + { user_command::secondcontrollerset, &TTrain::OnCommand_secondcontrollerset }, { user_command::notchingrelaytoggle, &TTrain::OnCommand_notchingrelaytoggle }, { user_command::mucurrentindicatorothersourceactivate, &TTrain::OnCommand_mucurrentindicatorothersourceactivate }, { user_command::independentbrakeincrease, &TTrain::OnCommand_independentbrakeincrease }, { user_command::independentbrakeincreasefast, &TTrain::OnCommand_independentbrakeincreasefast }, { user_command::independentbrakedecrease, &TTrain::OnCommand_independentbrakedecrease }, { user_command::independentbrakedecreasefast, &TTrain::OnCommand_independentbrakedecreasefast }, + { user_command::independentbrakeset, &TTrain::OnCommand_independentbrakeset }, { user_command::independentbrakebailoff, &TTrain::OnCommand_independentbrakebailoff }, { user_command::trainbrakeincrease, &TTrain::OnCommand_trainbrakeincrease }, { user_command::trainbrakedecrease, &TTrain::OnCommand_trainbrakedecrease }, + { user_command::trainbrakeset, &TTrain::OnCommand_trainbrakeset }, { user_command::trainbrakecharging, &TTrain::OnCommand_trainbrakecharging }, { user_command::trainbrakerelease, &TTrain::OnCommand_trainbrakerelease }, { user_command::trainbrakefirstservice, &TTrain::OnCommand_trainbrakefirstservice }, @@ -437,9 +441,9 @@ PyObject *TTrain::GetTrainState() { PyDict_SetItemString( dict, "fuse", PyGetBool( mover->FuseFlag ) ); PyDict_SetItemString( dict, "epfuse", PyGetBool( mover->EpFuse )); // induction motor state data - char* TXTT[ 10 ] = { "fd", "fdt", "fdb", "pd", "pdt", "pdb", "itothv", "1", "2", "3" }; - char* TXTC[ 10 ] = { "fr", "frt", "frb", "pr", "prt", "prb", "im", "vm", "ihv", "uhv" }; - char* TXTP[ 3 ] = { "bc", "bp", "sp" }; + char const *TXTT[ 10 ] = { "fd", "fdt", "fdb", "pd", "pdt", "pdb", "itothv", "1", "2", "3" }; + char const *TXTC[ 10 ] = { "fr", "frt", "frb", "pr", "prt", "prb", "im", "vm", "ihv", "uhv" }; + char const *TXTP[ 3 ] = { "bc", "bp", "sp" }; for( int j = 0; j < 10; ++j ) PyDict_SetItemString( dict, ( std::string( "eimp_t_" ) + std::string( TXTT[ j ] ) ).c_str(), PyGetFloatS( fEIMParams[ 0 ][ j ] ) ); for( int i = 0; i < 8; ++i ) { @@ -496,6 +500,35 @@ PyObject *TTrain::GetTrainState() { return dict; } +TTrain::state_t +TTrain::get_state() const { + + return { + btLampkaSHP.GetValue(), + btLampkaCzuwaka.GetValue(), + btLampkaOpory.GetValue(), + btLampkaWylSzybki.GetValue(), + btLampkaNadmSil.GetValue(), + btLampkaStyczn.GetValue(), + btLampkaPoslizg.GetValue(), + btLampkaNadmPrzetw.GetValue(), + btLampkaPrzetwOff.GetValue(), + btLampkaNadmSpr.GetValue(), + btLampkaNadmWent.GetValue(), + btLampkaWysRozr.GetValue(), + btLampkaOgrzewanieSkladu.GetValue(), + btHaslerBrakes.GetValue(), + btHaslerCurrent.GetValue(), + ( TestFlag( mvOccupied->SecuritySystem.Status, s_CAalarm ) || TestFlag( mvOccupied->SecuritySystem.Status, s_SHPalarm ) ), + fTachoVelocity, + static_cast( mvOccupied->Compressor ), + static_cast( mvOccupied->PipePress ), + static_cast( mvOccupied->BrakePress ), + fHVoltage, + { fHCurrent[ ( mvControlled->TrainType & dt_EZT ) ? 0 : 1 ], fHCurrent[ 2 ], fHCurrent[ 3 ] } + }; +} + bool TTrain::is_eztoer() const { return @@ -596,6 +629,17 @@ void TTrain::OnCommand_mastercontrollerdecreasefast( TTrain *Train, command_data } } +void TTrain::OnCommand_mastercontrollerset( TTrain *Train, command_data const &Command ) { + + auto const targetposition { std::min( Command.param1, Train->mvControlled->MainCtrlPosNo ) }; + while( targetposition < Train->mvControlled->MainCtrlPos ) { + Train->mvControlled->DecMainCtrl( 1 ); + } + while( targetposition > Train->mvControlled->MainCtrlPos ) { + Train->mvControlled->IncMainCtrl( 1 ); + } +} + void TTrain::OnCommand_secondcontrollerincrease( TTrain *Train, command_data const &Command ) { if( Command.action != GLFW_RELEASE ) { @@ -678,6 +722,17 @@ void TTrain::OnCommand_secondcontrollerdecreasefast( TTrain *Train, command_data } } +void TTrain::OnCommand_secondcontrollerset( TTrain *Train, command_data const &Command ) { + + auto const targetposition { std::min( Command.param1, Train->mvControlled->ScndCtrlPosNo ) }; + while( targetposition < Train->mvControlled->ScndCtrlPos ) { + Train->mvControlled->DecScndCtrl( 1 ); + } + while( targetposition > Train->mvControlled->ScndCtrlPos ) { + Train->mvControlled->IncScndCtrl( 1 ); + } +} + void TTrain::OnCommand_independentbrakeincrease( TTrain *Train, command_data const &Command ) { if( Command.action != GLFW_RELEASE ) { @@ -724,6 +779,18 @@ void TTrain::OnCommand_independentbrakedecreasefast( TTrain *Train, command_data } } +void TTrain::OnCommand_independentbrakeset( TTrain *Train, command_data const &Command ) { + + Train->mvControlled->LocalBrakePos = ( + std::round( + interpolate( + 0.0, + LocalBrakePosNo, + clamp( + reinterpret_cast( Command.param1 ), + 0.0, 1.0 ) ) ) ); +} + void TTrain::OnCommand_independentbrakebailoff( TTrain *Train, command_data const &Command ) { if( false == FreeFlyModeFlag ) { @@ -801,6 +868,17 @@ void TTrain::OnCommand_trainbrakedecrease( TTrain *Train, command_data const &Co } } +void TTrain::OnCommand_trainbrakeset( TTrain *Train, command_data const &Command ) { + + Train->mvControlled->BrakeLevelSet( + interpolate( + Train->mvControlled->Handle->GetPos( bh_MIN ), + Train->mvControlled->Handle->GetPos( bh_MAX ), + clamp( + reinterpret_cast( Command.param1 ), + 0.0, 1.0 ) ) ); +} + void TTrain::OnCommand_trainbrakecharging( TTrain *Train, command_data const &Command ) { if( Command.action != GLFW_RELEASE ) { @@ -1293,6 +1371,8 @@ void TTrain::OnCommand_batterytoggle( TTrain *Train, command_data const &Command // only reacting to press, so the switch doesn't flip back and forth if key is held down if( false == Train->mvOccupied->Battery ) { // turn on + if( Command.hint == command_hint::off ) { return; } // caller wants the other state + // wyłącznik jest też w SN61, ewentualnie załączać prąd na stałe z poziomu FIZ if( Train->mvOccupied->BatterySwitch( true ) ) { // bateria potrzebna np. do zapalenia świateł @@ -1312,6 +1392,8 @@ void TTrain::OnCommand_batterytoggle( TTrain *Train, command_data const &Command } else { //turn off + if( Command.hint == command_hint::on ) { return; } // caller wants the other state + if( Train->mvOccupied->BatterySwitch( false ) ) { // ewentualnie zablokować z FIZ, np. w samochodach się nie odłącza akumulatora if( Train->ggBatteryButton.SubModel ) { @@ -1334,6 +1416,8 @@ void TTrain::OnCommand_pantographtogglefront( TTrain *Train, command_data const // only reacting to press, so the switch doesn't flip back and forth if key is held down if( false == Train->mvControlled->PantFrontUp ) { // turn on... + if( Command.hint == command_hint::off ) { return; } // caller wants the other state + Train->mvControlled->PantFrontSP = false; if( Train->mvControlled->PantFront( true ) ) { if( Train->mvControlled->PantFrontStart != 1 ) { @@ -1356,6 +1440,8 @@ void TTrain::OnCommand_pantographtogglefront( TTrain *Train, command_data const } else { // ...or turn off + if( Command.hint == command_hint::on ) { return; } // caller wants the other state + if( Train->mvOccupied->PantSwitchType == "impulse" ) { if( ( Train->ggPantFrontButtonOff.SubModel == nullptr ) && ( Train->ggPantSelectedDownButton.SubModel == nullptr ) ) { @@ -1414,6 +1500,8 @@ void TTrain::OnCommand_pantographtogglerear( TTrain *Train, command_data const & // only reacting to press, so the switch doesn't flip back and forth if key is held down if( false == Train->mvControlled->PantRearUp ) { // turn on... + if( Command.hint == command_hint::off ) { return; } // caller wants the other state + Train->mvControlled->PantRearSP = false; if( Train->mvControlled->PantRear( true ) ) { if( Train->mvControlled->PantRearStart != 1 ) { @@ -1436,6 +1524,8 @@ void TTrain::OnCommand_pantographtogglerear( TTrain *Train, command_data const & } else { // ...or turn off + if( Command.hint == command_hint::on ) { return; } // caller wants the other state + if( Train->mvOccupied->PantSwitchType == "impulse" ) { if( ( Train->ggPantRearButtonOff.SubModel == nullptr ) && ( Train->ggPantSelectedDownButton.SubModel == nullptr ) ) { @@ -1603,6 +1693,8 @@ void TTrain::OnCommand_linebreakertoggle( TTrain *Train, command_data const &Com // press or hold... if( Train->m_linebreakerstate == 0 ) { // ...to close the circuit + if( Command.hint == command_hint::off ) { return; } // caller wants the other state + if( Command.action == GLFW_PRESS ) { // fresh press, start fresh closing delay calculation Train->fMainRelayTimer = 0.0f; @@ -1649,6 +1741,8 @@ void TTrain::OnCommand_linebreakertoggle( TTrain *Train, command_data const &Com } else if( Train->m_linebreakerstate == 1 ) { // ...to open the circuit + if( Command.hint == command_hint::on ) { return; } // caller wants the other state + if( true == Train->mvControlled->MainSwitch( false ) ) { Train->m_linebreakerstate = -1; @@ -1755,6 +1849,8 @@ void TTrain::OnCommand_convertertoggle( TTrain *Train, command_data const &Comma if( ( false == Train->mvControlled->ConverterAllow ) && ( Train->ggConverterButton.GetValue() < 0.5 ) ) { // turn on + if( Command.hint == command_hint::off ) { return; } // caller wants the other state + // visual feedback Train->ggConverterButton.UpdateValue( 1.0, Train->dsbSwitch ); /* @@ -1782,6 +1878,8 @@ void TTrain::OnCommand_convertertoggle( TTrain *Train, command_data const &Comma } else { //turn off + if( Command.hint == command_hint::on ) { return; } // caller wants the other state + // visual feedback Train->ggConverterButton.UpdateValue( 0.0, Train->dsbSwitch ); if( Train->ggConverterOffButton.SubModel != nullptr ) { @@ -1907,6 +2005,8 @@ void TTrain::OnCommand_compressortoggle( TTrain *Train, command_data const &Comm // only reacting to press, so the switch doesn't flip back and forth if key is held down if( false == Train->mvControlled->CompressorAllow ) { // turn on + if( Command.hint == command_hint::off ) { return; } // caller wants the other state + // visual feedback Train->ggCompressorButton.UpdateValue( 1.0, Train->dsbSwitch ); // impulse type switch has no effect if there's no power @@ -1920,6 +2020,8 @@ void TTrain::OnCommand_compressortoggle( TTrain *Train, command_data const &Comm } else { //turn off + if( Command.hint == command_hint::on ) { return; } // caller wants the other state + if( true == Train->mvControlled->CompressorSwitch( false ) ) { // NOTE: we don't have switch type definition for the compresor switch // so for the time being we have hard coded "impulse" switches for all EMUs @@ -1991,16 +2093,26 @@ void TTrain::OnCommand_motorconnectorsopen( TTrain *Train, command_data const &C } return; } + + command_data command = Command; + if( Train->mvControlled->StLinSwitchType == "toggle" ) { + if( ( Command.hint == command_hint::on ) && ( true == Train->mvControlled->StLinSwitchOff ) ) { return; } + if( ( Command.hint == command_hint::off ) && ( false == Train->mvControlled->StLinSwitchOff ) ) { return; } + } + else if( Command.hint == command_hint::off ) { + command.action = GLFW_RELEASE; + } + // NOTE: because we don't have modeled actual circuits this is a simplification of the real mechanics // namely, pressing the button will flip it in the entire unit, which isn't exactly physically possible - if( Command.action == GLFW_PRESS ) { + if( command.action == GLFW_PRESS ) { // button works while it's held down but we can only pay attention to initial press if( false == Train->mvControlled->StLinSwitchOff ) { // open the connectors Train->mvControlled->StLinSwitchOff = true; if( ( Train->mvControlled->TrainType == dt_ET41 ) || ( Train->mvControlled->TrainType == dt_ET42 ) ) { - // crude implementation of the butto affecting entire unit for multi-unit engines + // crude implementation of the button affecting entire unit for multi-unit engines // TODO: rework it into part of standard command propagation system if( ( Train->mvControlled->Couplers[ 0 ].Connected != nullptr ) && ( true == TestFlag( Train->mvControlled->Couplers[ 0 ].CouplingFlag, coupling::permanent ) ) ) { @@ -2057,10 +2169,10 @@ void TTrain::OnCommand_motorconnectorsopen( TTrain *Train, command_data const &C } } } - else if( Command.action == GLFW_RELEASE ) { + else if( command.action == GLFW_RELEASE ) { // button released if( Train->mvControlled->StLinSwitchType != "toggle" ) { - // default button type (impulse) works on button release + // default button type (impulse) ceases its work on button release Train->mvControlled->StLinSwitchOff = false; if( ( Train->mvControlled->TrainType == dt_ET41 ) || ( Train->mvControlled->TrainType == dt_ET42 ) ) { @@ -2105,6 +2217,8 @@ void TTrain::OnCommand_motoroverloadrelaythresholdtoggle( TTrain *Train, command ( false == Train->mvControlled->ShuntMode ) : ( Train->mvControlled->Imax < Train->mvControlled->ImaxHi ) ) ) { // turn on + if( Command.hint == command_hint::off ) { return; } // caller wants the other state + if( true == Train->mvControlled->CurrentSwitch( true ) ) { // visual feedback Train->ggMaxCurrentCtrl.UpdateValue( 1.0, Train->dsbSwitch ); @@ -2112,6 +2226,8 @@ void TTrain::OnCommand_motoroverloadrelaythresholdtoggle( TTrain *Train, command } else { //turn off + if( Command.hint == command_hint::on ) { return; } // caller wants the other state + if( true == Train->mvControlled->CurrentSwitch( false ) ) { // visual feedback Train->ggMaxCurrentCtrl.UpdateValue( 0.0, Train->dsbSwitch ); @@ -2212,6 +2328,8 @@ void TTrain::OnCommand_headlighttoggleleft( TTrain *Train, command_data const &C // only reacting to press, so the switch doesn't flip back and forth if key is held down if( ( Train->DynamicObject->iLights[ vehicleside ] & light::headlight_left ) == 0 ) { // turn on + if( Command.hint == command_hint::off ) { return; } // caller wants the other state + Train->DynamicObject->iLights[ vehicleside ] ^= light::headlight_left; // visual feedback Train->ggLeftLightButton.UpdateValue( 1.0, Train->dsbSwitch ); @@ -2222,6 +2340,8 @@ void TTrain::OnCommand_headlighttoggleleft( TTrain *Train, command_data const &C } else { //turn off + if( Command.hint == command_hint::on ) { return; } // caller wants the other state + Train->DynamicObject->iLights[ vehicleside ] ^= light::headlight_left; // visual feedback Train->ggLeftLightButton.UpdateValue( 0.0, Train->dsbSwitch ); @@ -2245,6 +2365,8 @@ void TTrain::OnCommand_headlighttoggleright( TTrain *Train, command_data const & // only reacting to press, so the switch doesn't flip back and forth if key is held down if( ( Train->DynamicObject->iLights[ vehicleside ] & light::headlight_right ) == 0 ) { // turn on + if( Command.hint == command_hint::off ) { return; } // caller wants the other state + Train->DynamicObject->iLights[ vehicleside ] ^= light::headlight_right; // visual feedback Train->ggRightLightButton.UpdateValue( 1.0, Train->dsbSwitch ); @@ -2255,6 +2377,8 @@ void TTrain::OnCommand_headlighttoggleright( TTrain *Train, command_data const & } else { //turn off + if( Command.hint == command_hint::on ) { return; } // caller wants the other state + Train->DynamicObject->iLights[ vehicleside ] ^= light::headlight_right; // visual feedback Train->ggRightLightButton.UpdateValue( 0.0, Train->dsbSwitch ); @@ -2278,12 +2402,16 @@ void TTrain::OnCommand_headlighttoggleupper( TTrain *Train, command_data const & // only reacting to press, so the switch doesn't flip back and forth if key is held down if( ( Train->DynamicObject->iLights[ vehicleside ] & light::headlight_upper ) == 0 ) { // turn on + if( Command.hint == command_hint::off ) { return; } // caller wants the other state + Train->DynamicObject->iLights[ vehicleside ] ^= light::headlight_upper; // visual feedback Train->ggUpperLightButton.UpdateValue( 1.0, Train->dsbSwitch ); } else { //turn off + if( Command.hint == command_hint::on ) { return; } // caller wants the other state + Train->DynamicObject->iLights[ vehicleside ] ^= light::headlight_upper; // visual feedback Train->ggUpperLightButton.UpdateValue( 0.0, Train->dsbSwitch ); @@ -2597,12 +2725,16 @@ void TTrain::OnCommand_headlightsdimtoggle( TTrain *Train, command_data const &C // only reacting to press, so the switch doesn't flip back and forth if key is held down if( false == Train->DynamicObject->DimHeadlights ) { // turn on + if( Command.hint == command_hint::off ) { return; } // caller wants the other state + Train->DynamicObject->DimHeadlights = true; // visual feedback Train->ggDimHeadlightsButton.UpdateValue( 1.0, Train->dsbSwitch ); } else { //turn off + if( Command.hint == command_hint::on ) { return; } // caller wants the other state + Train->DynamicObject->DimHeadlights = false; // visual feedback Train->ggDimHeadlightsButton.UpdateValue( 0.0, Train->dsbSwitch ); @@ -2654,12 +2786,16 @@ void TTrain::OnCommand_interiorlightdimtoggle( TTrain *Train, command_data const // only reacting to press, so the switch doesn't flip back and forth if key is held down if( false == Train->bCabLightDim ) { // turn on + if( Command.hint == command_hint::off ) { return; } // caller wants the other state + Train->bCabLightDim = true; // visual feedback Train->ggCabLightDimButton.UpdateValue( 1.0, Train->dsbSwitch ); } else { //turn off + if( Command.hint == command_hint::on ) { return; } // caller wants the other state + Train->bCabLightDim = false; // visual feedback Train->ggCabLightDimButton.UpdateValue( 0.0, Train->dsbSwitch ); @@ -2709,12 +2845,16 @@ void TTrain::OnCommand_heatingtoggle( TTrain *Train, command_data const &Command // only reacting to press, so the switch doesn't flip back and forth if key is held down if( false == Train->mvControlled->Heating ) { // turn on + if( Command.hint == command_hint::off ) { return; } // caller wants the other state + Train->mvControlled->Heating = true; // visual feedback Train->ggTrainHeatingButton.UpdateValue( 1.0, Train->dsbSwitch ); } else { //turn off + if( Command.hint == command_hint::on ) { return; } // caller wants the other state + Train->mvControlled->Heating = false; // visual feedback Train->ggTrainHeatingButton.UpdateValue( 0.0, Train->dsbSwitch ); @@ -2863,8 +3003,9 @@ void TTrain::OnCommand_doortoggleright( TTrain *Train, command_data const &Comma void TTrain::OnCommand_carcouplingincrease( TTrain *Train, command_data const &Command ) { - if( true == FreeFlyModeFlag ) { - // tryb freefly + if( ( true == FreeFlyModeFlag ) + && ( Command.action == GLFW_PRESS ) ) { + // tryb freefly, press only auto coupler { -1 }; auto *vehicle { Train->DynamicObject->ABuScanNearestObject( Train->DynamicObject->GetTrack(), 1, 1500, coupler ) }; if( vehicle == nullptr ) @@ -2884,8 +3025,9 @@ void TTrain::OnCommand_carcouplingincrease( TTrain *Train, command_data const &C void TTrain::OnCommand_carcouplingdisconnect( TTrain *Train, command_data const &Command ) { - if( true == FreeFlyModeFlag ) { - // tryb freefly + if( ( true == FreeFlyModeFlag ) + && ( Command.action == GLFW_PRESS ) ) { + // tryb freefly, press only auto coupler { -1 }; auto *vehicle { Train->DynamicObject->ABuScanNearestObject( Train->DynamicObject->GetTrack(), 1, 1500, coupler ) }; if( vehicle == nullptr ) @@ -3451,43 +3593,27 @@ bool TTrain::Update( double const Deltatime ) fEIMParams[1 + i][8] = 0; fEIMParams[1 + i][9] = 0; } - - if (Global.iFeedbackMode == 4) - { // wykonywać tylko gdy wyprowadzone na pulpit - Console::ValueSet(0, - mvOccupied->Compressor); // Ra: sterowanie miernikiem: zbiornik główny - Console::ValueSet(1, - mvOccupied->PipePress); // Ra: sterowanie miernikiem: przewód główny - Console::ValueSet(2, mvOccupied->BrakePress); // Ra: sterowanie miernikiem: cylinder hamulcowy - Console::ValueSet(3, fHVoltage); // woltomierz wysokiego napięcia - Console::ValueSet(4, fHCurrent[2]); // Ra: sterowanie miernikiem: drugi amperomierz - Console::ValueSet(5, - fHCurrent[(mvControlled->TrainType & dt_EZT) ? 0 : 1]); // pierwszy amperomierz; dla - // EZT prąd całkowity - Console::ValueSet(6, fTachoVelocity); ////Ra: prędkość na pin 43 - wyjście - /// analogowe (to nie jest PWM); - /// skakanie zapewnia mechanika - /// napędu +#ifdef _WIN32 + if (Global.iFeedbackMode == 4) { + // wykonywać tylko gdy wyprowadzone na pulpit + // Ra: sterowanie miernikiem: zbiornik główny + Console::ValueSet(0, mvOccupied->Compressor); + // Ra: sterowanie miernikiem: przewód główny + Console::ValueSet(1, mvOccupied->PipePress); + // Ra: sterowanie miernikiem: cylinder hamulcowy + Console::ValueSet(2, mvOccupied->BrakePress); + // woltomierz wysokiego napięcia + Console::ValueSet(3, fHVoltage); + // Ra: sterowanie miernikiem: drugi amperomierz + Console::ValueSet(4, fHCurrent[2]); + // pierwszy amperomierz; dla EZT prąd całkowity + Console::ValueSet(5, fHCurrent[(mvControlled->TrainType & dt_EZT) ? 0 : 1]); + // Ra: prędkość na pin 43 - wyjście analogowe (to nie jest PWM); skakanie zapewnia mechanika napędu + Console::ValueSet(6, fTachoVelocity); } - - if (Global.bMWDmasterEnable) // pobieranie danych dla pulpitu port (COM) - { - Console::ValueSet(0, mvOccupied->Compressor); // zbiornik główny - Console::ValueSet(1, mvOccupied->PipePress); // przewód główny - Console::ValueSet(2, mvOccupied->BrakePress); // cylinder hamulcowy - Console::ValueSet(3, fHVoltage); // woltomierz wysokiego napięcia - Console::ValueSet(4, fHCurrent[(mvControlled->TrainType & dt_EZT) ? 0 : 1]); - // pierwszy amperomierz; dla EZT prąd całkowity - Console::ValueSet(5, fHCurrent[2]); // drugi amperomierz 2 - Console::ValueSet(6, fHCurrent[3]); // drugi amperomierz 3 - Console::ValueSet(7, fTachoVelocity); - //Console::ValueSet(8, mvControlled->BatteryVoltage); // jeszcze nie pora ;) - } - - // hunter-080812: wyrzucanie szybkiego na elektrykach gdy nie ma napiecia - // przy dowolnym ustawieniu kierunkowego - // Ra: to już jest w T_MoverParameters::TractionForce(), ale zależy od - // kierunku +#endif + // hunter-080812: wyrzucanie szybkiego na elektrykach gdy nie ma napiecia przy dowolnym ustawieniu kierunkowego + // Ra: to już jest w T_MoverParameters::TractionForce(), ale zależy od kierunku if( ( mvControlled->Mains ) && ( mvControlled->EngineType == ElectricSeriesMotor ) ) { if( std::max( mvControlled->GetTrainsetVoltage(), std::fabs( mvControlled->RunningTraction.TractionVoltage ) ) < 0.5 * mvControlled->EnginePowerSource.MaxVoltage ) { @@ -4026,9 +4152,10 @@ bool TTrain::Update( double const Deltatime ) } if (ggBrakeCtrl.SubModel) { +#ifdef _WIN32 if (DynamicObject->Mechanik ? (DynamicObject->Mechanik->AIControllFlag ? false : - (Global.iFeedbackMode == 4 || (Global.bMWDmasterEnable && Global.bMWDBreakEnable))) : + (Global.iFeedbackMode == 4 /*|| (Global.bMWDmasterEnable && Global.bMWDBreakEnable)*/)) : false) // nie blokujemy AI { // Ra: nie najlepsze miejsce, ale na początek gdzieś to dać trzeba // Firleju: dlatego kasujemy i zastepujemy funkcją w Console @@ -4037,7 +4164,6 @@ bool TTrain::Update( double const Deltatime ) double b = Console::AnalogCalibrateGet(0); b = b * 8.0 - 2.0; b = clamp( b, -2.0, mvOccupied->BrakeCtrlPosNo ); // przycięcie zmiennej do granic - if (Global.bMWDdebugEnable && Global.iMWDDebugMode & 4) WriteLog("FV4a break position = " + to_string(b)); ggBrakeCtrl.UpdateValue(b); // przesów bez zaokrąglenia mvOccupied->BrakeLevelSet(b); } @@ -4046,13 +4172,13 @@ bool TTrain::Update( double const Deltatime ) double b = Console::AnalogCalibrateGet(0); b = b * 7.0 - 1.0; b = clamp( b, -1.0, mvOccupied->BrakeCtrlPosNo ); // przycięcie zmiennej do granic - if (Global.bMWDdebugEnable && Global.iMWDDebugMode & 4) WriteLog("FVel6 break position = " + to_string(b)); ggBrakeCtrl.UpdateValue(b); // przesów bez zaokrąglenia mvOccupied->BrakeLevelSet(b); } // else //standardowa prodedura z kranem powiązanym z klawiaturą // ggBrakeCtrl.UpdateValue(double(mvOccupied->BrakeCtrlPos)); } +#endif // else //standardowa prodedura z kranem powiązanym z klawiaturą // ggBrakeCtrl.UpdateValue(double(mvOccupied->BrakeCtrlPos)); ggBrakeCtrl.UpdateValue(mvOccupied->fBrakeCtrlPos); @@ -4060,12 +4186,12 @@ bool TTrain::Update( double const Deltatime ) } if( ggLocalBrake.SubModel ) { - +#ifdef _WIN32 if( ( DynamicObject->Mechanik != nullptr ) && ( false == DynamicObject->Mechanik->AIControllFlag ) // nie blokujemy AI && ( mvOccupied->BrakeLocHandle == FD1 ) && ( ( Global.iFeedbackMode == 4 ) - || ( Global.bMWDmasterEnable && Global.bMWDBreakEnable ) ) ) { + /*|| ( Global.bMWDmasterEnable && Global.bMWDBreakEnable )*/ ) ) { // Ra: nie najlepsze miejsce, ale na początek gdzieś to dać trzeba // Firleju: dlatego kasujemy i zastepujemy funkcją w Console auto const b = clamp( @@ -4074,12 +4200,10 @@ bool TTrain::Update( double const Deltatime ) ManualBrakePosNo ); ggLocalBrake.UpdateValue( b ); // przesów bez zaokrąglenia mvOccupied->LocalBrakePos = int( 1.09 * b ); // sposób zaokrąglania jest do ustalenia - if( ( true == Global.bMWDdebugEnable ) - && ( ( Global.iMWDDebugMode & 4 ) != 0 ) ) { - WriteLog( "FD1 break position = " + to_string( b ) ); - } } - else { + else +#endif + { // standardowa prodedura z kranem powiązanym z klawiaturą ggLocalBrake.UpdateValue( double( mvOccupied->LocalBrakePos ) ); } @@ -5146,6 +5270,27 @@ void TTrain::SetLights() // clears state of all cabin controls void TTrain::clear_cab_controls() { + // indicators exposed to custom control devices + btLampkaSHP.Clear(0); + btLampkaCzuwaka.Clear(1); + btLampkaOpory.Clear(2); + btLampkaWylSzybki.Clear(3); + btLampkaNadmSil.Clear(4); + btLampkaStyczn.Clear(5); + btLampkaPoslizg.Clear(6); + btLampkaNadmPrzetw.Clear(((mvControlled->TrainType & dt_EZT) != 0) ? -1 : 7); // EN57 nie ma tej lampki + btLampkaPrzetwOff.Clear(((mvControlled->TrainType & dt_EZT) != 0) ? 7 : -1 ); // za to ma tę + btLampkaNadmSpr.Clear(8); + btLampkaNadmWent.Clear(9); + btLampkaWysRozr.Clear(((mvControlled->TrainType & dt_ET22) != 0) ? -1 : 10); // ET22 nie ma tej lampki + btLampkaOgrzewanieSkladu.Clear(11); + btHaslerBrakes.Clear(12); // ciśnienie w cylindrach do odbijania na haslerze + btHaslerCurrent.Clear(13); // prąd na silnikach do odbijania na haslerze + // Jeśli ustawiamy nową wartość dla PoKeys wolna jest 15 + // Numer 14 jest używany dla buczka SHP w update_sounds() + + // other cab controls + // TODO: arrange in more readable manner, and eventually refactor ggMainCtrl.Clear(); ggMainCtrlAct.Clear(); ggScndCtrl.Clear(); @@ -5168,11 +5313,6 @@ void TTrain::clear_cab_controls() ggHornLowButton.Clear(); ggHornHighButton.Clear(); ggNextCurrentButton.Clear(); -/* - ggUniversal1Button.Clear(); - ggUniversal2Button.Clear(); - ggUniversal4Button.Clear(); -*/ for( auto &universal : ggUniversals ) { universal.Clear(); } @@ -5215,35 +5355,19 @@ void TTrain::clear_cab_controls() ggClockHInd.Clear(); ggEngineVoltage.Clear(); ggLVoltage.Clear(); - // ggLVoltage.Output(0); //Ra: sterowanie miernikiem: niskie napięcie - // ggEnrot1m.Clear(); - // ggEnrot2m.Clear(); - // ggEnrot3m.Clear(); - // ggEngageRatio.Clear(); ggMainGearStatus.Clear(); ggIgnitionKey.Clear(); - // Jeśli ustawiamy nową wartość dla PoKeys wolna jest 15 - // Numer 14 jest używany dla buczka SHP w innym miejscu - btLampkaPoslizg.Clear(6); - btLampkaStyczn.Clear(5); - btLampkaNadmPrzetw.Clear(((mvControlled->TrainType & dt_EZT) != 0) ? -1 : 7); // EN57 nie ma tej lampki + btLampkaPrzetw.Clear(); - btLampkaPrzetwOff.Clear(((mvControlled->TrainType & dt_EZT) != 0) ? 7 : -1 ); // za to ma tę btLampkaPrzetwB.Clear(); btLampkaPrzetwBOff.Clear(); btLampkaPrzekRozn.Clear(); btLampkaPrzekRoznPom.Clear(); - btLampkaNadmSil.Clear(4); btLampkaUkrotnienie.Clear(); btLampkaHamPosp.Clear(); - btLampkaWylSzybki.Clear(3); btLampkaWylSzybkiOff.Clear(); btLampkaWylSzybkiB.Clear(); btLampkaWylSzybkiBOff.Clear(); - btLampkaNadmWent.Clear(9); - btLampkaNadmSpr.Clear(8); - btLampkaOpory.Clear(2); - btLampkaWysRozr.Clear(((mvControlled->TrainType & dt_ET22) != 0) ? -1 : 10); // ET22 nie ma tej lampki btLampkaBezoporowa.Clear(); btLampkaBezoporowaB.Clear(); btLampkaMaxSila.Clear(); @@ -5254,9 +5378,6 @@ void TTrain::clear_cab_controls() btLampkaBlokadaDrzwi.Clear(); btInstrumentLight.Clear(); btLampkaWentZaluzje.Clear(); - btLampkaOgrzewanieSkladu.Clear(11); - btLampkaSHP.Clear(0); - btLampkaCzuwaka.Clear(1); btLampkaDoorLeft.Clear(); btLampkaDoorRight.Clear(); btLampkaDepartureSignal.Clear(); @@ -5308,8 +5429,6 @@ void TTrain::clear_cab_controls() ggRearUpperLightButton.Clear(); ggRearLeftEndLightButton.Clear(); ggRearRightEndLightButton.Clear(); - btHaslerBrakes.Clear(12); // ciśnienie w cylindrach do odbijania na haslerze - btHaslerCurrent.Clear(13); // prąd na silnikach do odbijania na haslerze } // NOTE: we can get rid of this function once we have per-cab persistent state diff --git a/Train.h b/Train.h index 9b7d6807..db392353 100644 --- a/Train.h +++ b/Train.h @@ -65,9 +65,34 @@ public: class TTrain { - friend class TWorld; // temporary due to use of play_sound TODO: refactor this - public: +// types + struct state_t { + std::uint8_t shp; + std::uint8_t alerter; + std::uint8_t motor_resistors; + std::uint8_t line_breaker; + std::uint8_t motor_overload; + std::uint8_t motor_connectors; + std::uint8_t wheelslip; + std::uint8_t converter_overload; + std::uint8_t converter_off; + std::uint8_t compressor_overload; + std::uint8_t ventilator_overload; + std::uint8_t motor_overload_threshold; + std::uint8_t train_heating; + std::uint8_t recorder_braking; + std::uint8_t recorder_power; + std::uint8_t alerter_sound; + float velocity; + float reservoir_pressure; + float pipe_pressure; + float brake_pressure; + float hv_voltage; + std::array hv_current; + }; + +// methods bool CabChange(int iDirection); bool ShowNextCurrent; // pokaz przd w podlaczonej lokomotywie (ET41) bool InitializeCab(int NewCabNo, std::string const &asFileName); @@ -86,6 +111,7 @@ class TTrain // McZapkie-310302: ladowanie parametrow z pliku bool LoadMMediaFile(std::string const &asFileName); PyObject *GetTrainState(); + state_t get_state() const; private: // types @@ -119,19 +145,23 @@ class TTrain static void OnCommand_mastercontrollerincreasefast( TTrain *Train, command_data const &Command ); static void OnCommand_mastercontrollerdecrease( TTrain *Train, command_data const &Command ); static void OnCommand_mastercontrollerdecreasefast( TTrain *Train, command_data const &Command ); + static void OnCommand_mastercontrollerset( TTrain *Train, command_data const &Command ); static void OnCommand_secondcontrollerincrease( TTrain *Train, command_data const &Command ); static void OnCommand_secondcontrollerincreasefast( TTrain *Train, command_data const &Command ); static void OnCommand_secondcontrollerdecrease( TTrain *Train, command_data const &Command ); static void OnCommand_secondcontrollerdecreasefast( TTrain *Train, command_data const &Command ); + static void OnCommand_secondcontrollerset( TTrain *Train, command_data const &Command ); static void OnCommand_notchingrelaytoggle( TTrain *Train, command_data const &Command ); static void OnCommand_mucurrentindicatorothersourceactivate( TTrain *Train, command_data const &Command ); static void OnCommand_independentbrakeincrease( TTrain *Train, command_data const &Command ); static void OnCommand_independentbrakeincreasefast( TTrain *Train, command_data const &Command ); static void OnCommand_independentbrakedecrease( TTrain *Train, command_data const &Command ); static void OnCommand_independentbrakedecreasefast( TTrain *Train, command_data const &Command ); + static void OnCommand_independentbrakeset( TTrain *Train, command_data const &Command ); static void OnCommand_independentbrakebailoff( TTrain *Train, command_data const &Command ); static void OnCommand_trainbrakeincrease( TTrain *Train, command_data const &Command ); static void OnCommand_trainbrakedecrease( TTrain *Train, command_data const &Command ); + static void OnCommand_trainbrakeset( TTrain *Train, command_data const &Command ); static void OnCommand_trainbrakecharging( TTrain *Train, command_data const &Command ); static void OnCommand_trainbrakerelease( TTrain *Train, command_data const &Command ); static void OnCommand_trainbrakefirstservice( TTrain *Train, command_data const &Command ); diff --git a/command.cpp b/command.cpp index b24c988c..e3ee9cad 100644 --- a/command.cpp +++ b/command.cpp @@ -26,18 +26,22 @@ commanddescription_sequence Commands_descriptions = { { "mastercontrollerincreasefast", command_target::vehicle }, { "mastercontrollerdecrease", command_target::vehicle }, { "mastercontrollerdecreasefast", command_target::vehicle }, + { "mastercontrollerset", command_target::vehicle }, { "secondcontrollerincrease", command_target::vehicle }, { "secondcontrollerincreasefast", command_target::vehicle }, { "secondcontrollerdecrease", command_target::vehicle }, { "secondcontrollerdecreasefast", command_target::vehicle }, + { "secondcontrollerset", command_target::vehicle }, { "mucurrentindicatorothersourceactivate", command_target::vehicle }, { "independentbrakeincrease", command_target::vehicle }, { "independentbrakeincreasefast", command_target::vehicle }, { "independentbrakedecrease", command_target::vehicle }, { "independentbrakedecreasefast", command_target::vehicle }, + { "independentbrakeset", command_target::vehicle }, { "independentbrakebailoff", command_target::vehicle }, { "trainbrakeincrease", command_target::vehicle }, { "trainbrakedecrease", command_target::vehicle }, + { "trainbrakeset", command_target::vehicle }, { "trainbrakecharging", command_target::vehicle }, { "trainbrakerelease", command_target::vehicle }, { "trainbrakefirstservice", command_target::vehicle }, @@ -173,7 +177,7 @@ command_queue::pop( command_data &Command, std::size_t const Recipient ) { } void -command_relay::post( user_command const Command, std::uint64_t const Param1, std::uint64_t const Param2, int const Action, std::uint16_t const Recipient ) const { +command_relay::post( user_command const Command, std::uint64_t const Param1, std::uint64_t const Param2, int const Action, command_hint const Hint, std::uint16_t const Recipient ) const { auto const &command = simulation::Commands_descriptions[ static_cast( Command ) ]; if( ( command.target == command_target::vehicle ) @@ -190,6 +194,7 @@ command_relay::post( user_command const Command, std::uint64_t const Param1, std Action, Param1, Param2, + Hint, Timer::GetDeltaTime() }, static_cast( command.target ) | Recipient ); /* diff --git a/command.h b/command.h index 98a69caa..ab8e32d1 100644 --- a/command.h +++ b/command.h @@ -20,18 +20,22 @@ enum class user_command { mastercontrollerincreasefast, mastercontrollerdecrease, mastercontrollerdecreasefast, + mastercontrollerset, secondcontrollerincrease, secondcontrollerincreasefast, secondcontrollerdecrease, secondcontrollerdecreasefast, + secondcontrollerset, mucurrentindicatorothersourceactivate, independentbrakeincrease, independentbrakeincreasefast, independentbrakedecrease, independentbrakedecreasefast, + independentbrakeset, independentbrakebailoff, trainbrakeincrease, trainbrakedecrease, + trainbrakeset, trainbrakecharging, trainbrakerelease, trainbrakefirstservice, @@ -135,6 +139,12 @@ enum class user_command { none = -1 }; +enum class command_hint { + off, + on, + none = -1 +}; + enum class command_target { userinterface, @@ -163,6 +173,7 @@ struct command_data { int action; // press, repeat or release std::uint64_t param1; std::uint64_t param2; + command_hint hint; double time_delta; }; @@ -212,7 +223,8 @@ public: // posts specified command for the specified recipient // TODO: replace uint16_t with recipient handle, based on item id void - post( user_command const Command, std::uint64_t const Param1, std::uint64_t const Param2, int const Action, std::uint16_t const Recipient ) const; + post( user_command const Command, std::uint64_t const Param1, std::uint64_t const Param2, + int const Action, command_hint const Hint, std::uint16_t const Recipient ) const; private: // types // members diff --git a/gamepadinput.cpp b/gamepadinput.cpp index ec433f1c..e3b7c24b 100644 --- a/gamepadinput.cpp +++ b/gamepadinput.cpp @@ -201,6 +201,7 @@ gamepad_input::process_axes( glm::vec2 Leftstick, glm::vec2 const &Rightstick, g reinterpret_cast( turnx ), reinterpret_cast( turny ), GLFW_PRESS, + command_hint::none, // as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0 // TODO: pass correct entity id once the missing systems are in place 0 ); @@ -218,6 +219,7 @@ gamepad_input::process_axes( glm::vec2 Leftstick, glm::vec2 const &Rightstick, g reinterpret_cast( movex ), reinterpret_cast( movez ), GLFW_PRESS, + command_hint::none, 0 ); } } @@ -247,6 +249,7 @@ gamepad_input::process_mode( float const Value, std::uint16_t const Recipient ) lookup.second, 0, 0, GLFW_RELEASE, + command_hint::none, Recipient ); m_modeaccumulator = 0.0f; } @@ -260,6 +263,7 @@ gamepad_input::process_mode( float const Value, std::uint16_t const Recipient ) lookup.first, 0, 0, GLFW_PRESS, + command_hint::none, Recipient ); m_modeaccumulator -= 1.0f; } @@ -271,6 +275,7 @@ gamepad_input::process_mode( float const Value, std::uint16_t const Recipient ) lookup.first, 0, 0, GLFW_RELEASE, + command_hint::none, Recipient ); m_modeaccumulator = 0.0f; } @@ -284,6 +289,7 @@ gamepad_input::process_mode( float const Value, std::uint16_t const Recipient ) lookup.first, 0, 0, GLFW_RELEASE, + command_hint::none, Recipient ); m_modeaccumulator = 0.0f; } @@ -297,6 +303,7 @@ gamepad_input::process_mode( float const Value, std::uint16_t const Recipient ) lookup.second, 0, 0, GLFW_PRESS, + command_hint::none, Recipient ); m_modeaccumulator += 1.0f; } @@ -308,6 +315,7 @@ gamepad_input::process_mode( float const Value, std::uint16_t const Recipient ) lookup.second, 0, 0, GLFW_RELEASE, + command_hint::none, Recipient ); m_modeaccumulator = 0.0f; } diff --git a/keyboardinput.cpp b/keyboardinput.cpp index c619436c..ee6fac6c 100644 --- a/keyboardinput.cpp +++ b/keyboardinput.cpp @@ -158,7 +158,7 @@ keyboard_input::key( int const Key, int const Action ) { // NOTE: basic keyboard controls don't have any parameters // as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0 // TODO: pass correct entity id once the missing systems are in place - m_relay.post( lookup->second, 0, 0, Action, 0 ); + m_relay.post( lookup->second, 0, 0, Action, command_hint::none, 0 ); return true; } @@ -179,6 +179,8 @@ keyboard_input::default_bindings() { { GLFW_KEY_KP_SUBTRACT }, // mastercontrollerdecreasefast { GLFW_KEY_KP_SUBTRACT | keymodifier::shift }, + // mastercontrollerset + { -1 }, // secondcontrollerincrease { GLFW_KEY_KP_DIVIDE }, // secondcontrollerincreasefast @@ -187,6 +189,8 @@ keyboard_input::default_bindings() { { GLFW_KEY_KP_MULTIPLY }, // secondcontrollerdecreasefast { GLFW_KEY_KP_MULTIPLY | keymodifier::shift }, + // secondcontrollerset + { -1 }, // mucurrentindicatorothersourceactivate { GLFW_KEY_Z | keymodifier::shift }, // independentbrakeincrease @@ -197,12 +201,16 @@ keyboard_input::default_bindings() { { GLFW_KEY_KP_7 }, // independentbrakedecreasefast { GLFW_KEY_KP_7 | keymodifier::shift }, + // independentbrakeset + { -1 }, // independentbrakebailoff { GLFW_KEY_KP_4 }, // trainbrakeincrease { GLFW_KEY_KP_3 }, // trainbrakedecrease { GLFW_KEY_KP_9 }, + // trainbrakeset + { -1 }, // trainbrakecharging { GLFW_KEY_KP_DECIMAL }, // trainbrakerelease @@ -481,6 +489,7 @@ keyboard_input::poll() { reinterpret_cast( movexparam ), reinterpret_cast( movezparam ), GLFW_PRESS, + command_hint::none, 0 ); } @@ -503,6 +512,7 @@ keyboard_input::poll() { reinterpret_cast( moveyparam ), 0, GLFW_PRESS, + command_hint::none, 0 ); } diff --git a/maszyna.vcxproj.filters b/maszyna.vcxproj.filters index b02c522c..755e3ad1 100644 --- a/maszyna.vcxproj.filters +++ b/maszyna.vcxproj.filters @@ -147,9 +147,6 @@ Source Files - - Source Files\input - Source Files @@ -237,6 +234,9 @@ Source Files + + Source Files\input + @@ -368,9 +368,6 @@ Header Files - - Header Files\input - Header Files @@ -461,6 +458,9 @@ Header Files + + Header Files\input + diff --git a/mouseinput.cpp b/mouseinput.cpp index da2c7ee5..8ab848e9 100644 --- a/mouseinput.cpp +++ b/mouseinput.cpp @@ -42,6 +42,7 @@ mouse_input::move( double Mousex, double Mousey ) { reinterpret_cast( Mousex ), reinterpret_cast( Mousey ), GLFW_PRESS, + command_hint::none, // as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0 // TODO: pass correct entity id once the missing systems are in place 0 ); @@ -60,6 +61,7 @@ mouse_input::move( double Mousex, double Mousey ) { reinterpret_cast( viewoffset.x ), reinterpret_cast( viewoffset.y ), GLFW_PRESS, + command_hint::none, // as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0 // TODO: pass correct entity id once the missing systems are in place 0 ); @@ -102,7 +104,7 @@ mouse_input::button( int const Button, int const Action ) { // NOTE: basic keyboard controls don't have any parameters // as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0 // TODO: pass correct entity id once the missing systems are in place - m_relay.post( mousecommand, 0, 0, Action, 0 ); + m_relay.post( mousecommand, 0, 0, Action, command_hint::none, 0 ); mousecommand = user_command::none; } else { @@ -141,7 +143,7 @@ mouse_input::button( int const Button, int const Action ) { // NOTE: basic keyboard controls don't have any parameters // as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0 // TODO: pass correct entity id once the missing systems are in place - m_relay.post( mousecommand, 0, 0, Action, 0 ); + m_relay.post( mousecommand, 0, 0, Action, command_hint::none, 0 ); m_updateaccumulator = -0.25; // prevent potential command repeat right after issuing one switch( mousecommand ) { @@ -192,13 +194,13 @@ mouse_input::poll() { // NOTE: basic keyboard controls don't have any parameters // as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0 // TODO: pass correct entity id once the missing systems are in place - m_relay.post( m_mousecommandleft, 0, 0, GLFW_REPEAT, 0 ); + m_relay.post( m_mousecommandleft, 0, 0, GLFW_REPEAT, command_hint::none, 0 ); } if( m_mousecommandright != user_command::none ) { // NOTE: basic keyboard controls don't have any parameters // as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0 // TODO: pass correct entity id once the missing systems are in place - m_relay.post( m_mousecommandright, 0, 0, GLFW_REPEAT, 0 ); + m_relay.post( m_mousecommandright, 0, 0, GLFW_REPEAT, command_hint::none, 0 ); } m_updateaccumulator -= updaterate; } diff --git a/Console/MWD.cpp b/old/MWD.cpp similarity index 100% rename from Console/MWD.cpp rename to old/MWD.cpp diff --git a/Console/MWD.h b/old/MWD.h similarity index 100% rename from Console/MWD.h rename to old/MWD.h diff --git a/uart.cpp b/uart.cpp new file mode 100644 index 00000000..9ee42629 --- /dev/null +++ b/uart.cpp @@ -0,0 +1,243 @@ +#include "stdafx.h" +#include "uart.h" + +#include "Globals.h" +#include "World.h" +#include "Train.h" +#include "Logs.h" + +uart_input::uart_input() +{ + conf = Global.uart_conf; + + if (sp_get_port_by_name(conf.port.c_str(), &port) != SP_OK) + throw std::runtime_error("uart: cannot find specified port"); + + if (sp_open(port, SP_MODE_READ_WRITE) != SP_OK) + throw std::runtime_error("uart: cannot open port"); + + sp_port_config *config; + + if (sp_new_config(&config) != SP_OK || + sp_set_config_baudrate(config, conf.baud) != SP_OK || + sp_set_config_flowcontrol(config, SP_FLOWCONTROL_NONE) != SP_OK || + sp_set_config_bits(config, 8) != SP_OK || + sp_set_config_stopbits(config, 1) != SP_OK || + sp_set_config_parity(config, SP_PARITY_NONE) != SP_OK || + sp_set_config(port, config) != SP_OK) + throw std::runtime_error("uart: cannot set config"); + + sp_free_config(config); + + if (sp_flush(port, SP_BUF_BOTH) != SP_OK) + throw std::runtime_error("uart: cannot flush"); + + old_packet.fill(0); + last_update = std::chrono::high_resolution_clock::now(); +} + +uart_input::~uart_input() +{ + std::array buffer = { 0 }; + sp_blocking_write(port, (void*)buffer.data(), buffer.size(), 0); + sp_drain(port); + + sp_close(port); + sp_free_port(port); +} + +#define SPLIT_INT16(x) (uint8_t)x, (uint8_t)(x >> 8) + +void uart_input::poll() +{ + auto now = std::chrono::high_resolution_clock::now(); + if (std::chrono::duration(now - last_update).count() < conf.updatetime) + return; + last_update = now; + + auto *t = Global.pWorld->train(); + if (!t) + return; + + sp_return ret; + + if ((ret = sp_input_waiting(port)) >= 16) + { + std::array buffer; + ret = sp_blocking_read(port, (void*)buffer.data(), buffer.size(), 0); + if (ret < 0) + throw std::runtime_error("uart: failed to read from port"); + + if (conf.debug) + { + char buf[buffer.size() * 3 + 1]; + size_t pos = 0; + for (uint8_t b : buffer) + pos += sprintf(&buf[pos], "%02X ", b); + WriteLog("uart: rx: " + std::string(buf)); + } + + data_pending = false; + + for (auto entry : input_bits) + { + input_type_t type = std::get<2>(entry); + + size_t byte = std::get<0>(entry) / 8; + size_t bit = std::get<0>(entry) % 8; + + bool state = ( (buffer[byte] & (1 << bit)) != 0 ); + + bool repeat = (type == impulse_r || + type == impulse_r_off || + type == impulse_r_on); + + bool changed = ( (buffer[ byte ] & (1 << bit)) != (old_packet[ byte ] & (1 << bit)) ); + + if (!changed && !(repeat && state)) + continue; + + int action; + command_hint desired_state; + + if (type == toggle) + { + action = GLFW_PRESS; + desired_state = ( state ? command_hint::on : command_hint::off ); + } + else if (type == impulse_r_on) + { + action = ( state ? (changed ? GLFW_PRESS : GLFW_REPEAT) : GLFW_RELEASE ); + desired_state = command_hint::on; + } + else if (type == impulse_r_off) + { + action = ( state ? (changed ? GLFW_PRESS : GLFW_REPEAT) : GLFW_RELEASE ); + desired_state = command_hint::off; + } + else if (type == impulse || type == impulse_r) + { + action = ( state ? (changed ? GLFW_PRESS : GLFW_REPEAT) : GLFW_RELEASE ); + desired_state = command_hint::none; + } + + relay.post( std::get<1>(entry), 0, 0, action, desired_state, 0 ); + } + + if( true == conf.mainenable ) { + // master controller + relay.post( + user_command::mastercontrollerset, + buffer[ 6 ], + 0, + GLFW_PRESS, + command_hint::none, + // TODO: pass correct entity id once the missing systems are in place + 0 ); + } + if( true == conf.scndenable ) { + // second controller + relay.post( + user_command::secondcontrollerset, + buffer[ 7 ], + 0, + GLFW_PRESS, + command_hint::none, + // TODO: pass correct entity id once the missing systems are in place + 0 ); + } + if( true == conf.trainenable ) { + // train brake + double const position { (float)( ( (uint16_t)buffer[ 8 ] | ( (uint16_t)buffer[ 9 ] << 8 ) ) - conf.mainbrakemin ) / ( conf.mainbrakemax - conf.mainbrakemin ) }; + relay.post( + user_command::trainbrakeset, + reinterpret_cast( position ), + 0, + GLFW_PRESS, + command_hint::none, + // TODO: pass correct entity id once the missing systems are in place + 0 ); + } + if( true == conf.localenable ) { + // independent brake + double const position { (float)( ( (uint16_t)buffer[ 10 ] | ( (uint16_t)buffer[ 11 ] << 8 ) ) - conf.localbrakemin ) / ( conf.localbrakemax - conf.localbrakemin ) }; + relay.post( + user_command::independentbrakeset, + reinterpret_cast( position ), + 0, + GLFW_PRESS, + command_hint::none, + // TODO: pass correct entity id once the missing systems are in place + 0 ); + } + + old_packet = buffer; + } + + if (!data_pending && sp_output_waiting(port) == 0) + { + // TODO: ugly! move it into structure like input_bits + auto const trainstate = t->get_state(); + + uint8_t tacho = Global.iPause ? 0 : trainstate.velocity; + uint16_t tank_press = (uint16_t)std::min(conf.tankuart, trainstate.reservoir_pressure * 0.1f / conf.tankmax * conf.tankuart); + uint16_t pipe_press = (uint16_t)std::min(conf.pipeuart, trainstate.pipe_pressure * 0.1f / conf.pipemax * conf.pipeuart); + uint16_t brake_press = (uint16_t)std::min(conf.brakeuart, trainstate.brake_pressure * 0.1f / conf.brakemax * conf.brakeuart); + uint16_t hv_voltage = (uint16_t)std::min(conf.hvuart, trainstate.hv_voltage / conf.hvmax * conf.hvuart); + uint16_t current1 = (uint16_t)std::min(conf.currentuart, trainstate.hv_current[0]) / conf.currentmax * conf.currentuart; + uint16_t current2 = (uint16_t)std::min(conf.currentuart, trainstate.hv_current[1]) / conf.currentmax * conf.currentuart; + uint16_t current3 = (uint16_t)std::min(conf.currentuart, trainstate.hv_current[2]) / conf.currentmax * conf.currentuart; + + std::array buffer { + //byte 0 + tacho, + //byte 1 + 0, + //byte 2 + (uint8_t)( + trainstate.motor_resistors << 1 + | trainstate.motor_overload_threshold << 2), + //byte 3 + 0, + //byte 4 + (uint8_t)( + trainstate.train_heating << 0 + | trainstate.motor_resistors << 1 + | trainstate.wheelslip << 2 + | trainstate.alerter << 6 + | trainstate.shp << 7), + //byte 5 + (uint8_t)( + trainstate.motor_connectors << 0 + | trainstate.converter_overload << 2 + | trainstate.motor_overload << 4 + | trainstate.line_breaker << 5 + | trainstate.compressor_overload << 6), + //byte 6 + (uint8_t)( trainstate.alerter_sound << 7), + SPLIT_INT16(brake_press), //byte 7-8 + SPLIT_INT16(pipe_press), //byte 9-10 + SPLIT_INT16(tank_press), //byte 11-12 + SPLIT_INT16(hv_voltage), //byte 13-14 + SPLIT_INT16(current1), //byte 15-16 + SPLIT_INT16(current2), //byte 17-18 + SPLIT_INT16(current3), //byte 19-20 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 //byte 21-30 + }; + + if (conf.debug) + { + char buf[buffer.size() * 3 + 1]; + size_t pos = 0; + for (uint8_t b : buffer) + pos += sprintf(&buf[pos], "%02X ", b); + WriteLog("uart: tx: " + std::string(buf)); + } + + ret = sp_blocking_write(port, (void*)buffer.data(), buffer.size(), 0); + if (ret != buffer.size()) + throw std::runtime_error("uart: failed to write to port"); + + data_pending = true; + } +} diff --git a/uart.h b/uart.h new file mode 100644 index 00000000..4ab96f8f --- /dev/null +++ b/uart.h @@ -0,0 +1,92 @@ +#pragma once + +#include +#include "command.h" + +class uart_input +{ +public: +// types + struct conf_t { + bool enable = false; + std::string port; + int baud; + float updatetime; + + float mainbrakemin = 0.0f; + float mainbrakemax = 65535.0f; + float localbrakemin = 0.0f; + float localbrakemax = 65535.0f; + float tankmax = 10.0f; + float tankuart = 65535.0f; + float pipemax = 10.0f; + float pipeuart = 65535.0f; + float brakemax = 10.0f; + float brakeuart = 65535.0f; + float hvmax = 100000.0f; + float hvuart = 65535.0f; + float currentmax = 10000.0f; + float currentuart = 65535.0f; + + bool mainenable = true; + bool scndenable = true; + bool trainenable = true; + bool localenable = true; + + bool debug = false; + }; + +// methods + uart_input(); + ~uart_input(); + void poll(); + +private: +// types + enum input_type_t + { + toggle, + impulse, + impulse_r, + impulse_r_on, + impulse_r_off + }; + + std::array, 23> input_bits = + { + std::make_tuple(1, user_command::linebreakertoggle, impulse_r_off), + std::make_tuple(2, user_command::linebreakertoggle, impulse_r_on), + std::make_tuple(3, user_command::motoroverloadrelayreset, impulse), + std::make_tuple(5, user_command::converteroverloadrelayreset, impulse), + std::make_tuple(6, user_command::motorconnectorsopen, toggle), + std::make_tuple(7, user_command::alerteracknowledge, impulse_r), + + std::make_tuple(9, user_command::convertertoggle, toggle), + std::make_tuple(10, user_command::compressortoggle, toggle), + std::make_tuple(11, user_command::sandboxactivate, impulse), + std::make_tuple(12, user_command::heatingtoggle, toggle), + + std::make_tuple(15, user_command::motoroverloadrelaythresholdtoggle, toggle), + std::make_tuple(16, user_command::pantographtogglefront, toggle), + std::make_tuple(17, user_command::pantographtogglerear, toggle), + std::make_tuple(18, user_command::wheelspinbrakeactivate, impulse), + std::make_tuple(19, user_command::headlightsdimtoggle, toggle), + std::make_tuple(20, user_command::interiorlightdimtoggle, toggle), + std::make_tuple(21, user_command::independentbrakebailoff, impulse), + std::make_tuple(22, user_command::hornhighactivate, impulse), + std::make_tuple(23, user_command::hornlowactivate, impulse), + + std::make_tuple(24, user_command::batterytoggle, toggle), + std::make_tuple(25, user_command::headlighttoggleleft, toggle), + std::make_tuple(26, user_command::headlighttoggleupper, toggle), + std::make_tuple(27, user_command::headlighttoggleright, toggle) + }; + +// members + sp_port *port = nullptr; + command_relay relay; + std::array old_packet; + std::chrono::time_point last_update; + conf_t conf; + bool data_pending = false; +};