Merge remote-tracking branch 'Milek7/lua' into mover_in_c++

This commit is contained in:
firleju
2017-09-25 15:33:18 +02:00
38 changed files with 2471 additions and 1281 deletions

View File

@@ -156,5 +156,6 @@ TButton::play( sound* Sound ) {
Sound->stop();
Sound->play();
return;
}

View File

@@ -49,6 +49,7 @@ class TButton
Turn( !m_state ); };
inline bool Active() {
return (pModelOn) || (pModelOff); };
inline uint8_t b() { return m_state ? 1 : 0; };
void Update();
void Init(std::string const &asName, TModel3d *pModel, bool bNewOn = false);
void Load(cParser &Parser, TModel3d *pModel1, TModel3d *pModel2 = NULL);

View File

@@ -5,6 +5,7 @@ include(PrecompiledHeader)
set(DEPS_DIR ${DEPS_DIR} "${CMAKE_SOURCE_DIR}/ref")
project("eu07")
set(CMAKE_CXX_STANDARD 14)
include_directories("." "Console" "McZapkie")
file(GLOB HEADERS "*.h" "Console/*.h" "McZapkie/*.h")
@@ -70,6 +71,7 @@ set(SOURCES
"material.cpp"
"lua.cpp"
"stdafx.cpp"
"uart.cpp"
)
set (ARCH "x86")
@@ -78,7 +80,7 @@ if (WIN32)
add_definitions(-DHAVE_ROUND) # to make pymath to not redefine round
add_definitions(-DEU07_BUILD_STATIC) # to make pymath to not redefine round
set(SOURCES ${SOURCES} "windows.cpp" "Console.cpp" "Console/LPT.cpp" "Console/MWD.cpp" "Console/PoKeys55.cpp" "wavread.cpp")
set(SOURCES ${SOURCES} "windows.cpp" "Console.cpp" "Console/LPT.cpp" "Console/PoKeys55.cpp" "wavread.cpp")
set(GLEW_INCLUDE_DIR ${GLEW_INCLUDE_DIR} "${DEPS_DIR}/glew/include/")
set(GLFW3_INCLUDE_DIR ${GLFW3_INCLUDE_DIR} "${DEPS_DIR}/glfw/include/")
set(GLUT_INCLUDE_DIR ${GLUT_INCLUDE_DIR} "${DEPS_DIR}/freeglut/include/")
@@ -193,8 +195,12 @@ find_package(LuaJIT REQUIRED)
include_directories(${LUAJIT_INCLUDE_DIR})
target_link_libraries(${PROJECT_NAME} ${LUAJIT_LIBRARIES})
find_package(libserialport REQUIRED)
include_directories(${libserialport_INCLUDE_DIR})
target_link_libraries(${PROJECT_NAME} ${libserialport_LIBRARY})
if (UNIX)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined -g")
endif()
#cotire(${PROJECT_NAME})

View File

@@ -0,0 +1,9 @@
find_path(libserialport_INCLUDE_DIR libserialport.h)
find_library(libserialport_LIBRARY serialport)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(libserialport DEFAULT_MSG libserialport_LIBRARY libserialport_INCLUDE_DIR)
if(libserialport_FOUND)
set(libserialport_LIBRARIES ${libserialport_LIBRARY})
set(libserialport_INCLUDE_DIRS ${libserialport_INCLUDE_DIR})
endif()

View File

@@ -13,7 +13,6 @@ http://mozilla.org/MPL/2.0/.
#include "McZapkie/mctools.h"
#include "LPT.h"
#include "Logs.h"
#include "MWD.h" // maciek001: obsluga portu COM
#include "PoKeys55.h"
//---------------------------------------------------------------------------
@@ -118,7 +117,6 @@ Console::~Console()
{
delete PoKeys55[0];
delete PoKeys55[1];
delete MWDComm;
};
void Console::ModeSet(int m, int h)
@@ -166,18 +164,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;
};
@@ -196,8 +182,6 @@ void Console::Off()
PoKeys55[1] = NULL;
delete LPT;
LPT = NULL;
delete MWDComm;
MWDComm = NULL;
};
void Console::BitsSet(int mask, int entry)
@@ -289,56 +273,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);
}
};
void Console::ValueSet(int x, double y)
@@ -371,57 +305,6 @@ void Console::ValueSet(int x, double y)
WriteLog(" calibrated=" + std::to_string(temp));
PoKeys55[0]->PWM(x, temp);
}
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
}
}
};
void Console::Update()
@@ -439,11 +322,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)
@@ -468,11 +346,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
};

View File

@@ -1,763 +0,0 @@
/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
/*
Program obsługi portu COM i innych na potrzeby sterownika MWDevice
(oraz innych wykorzystujących komunikację przez port COM)
dla Symulatora Pojazdów Szynowych MaSzyna
author: Maciej Witek 2016
Autor nie ponosi odpowiedzialności za niewłaciwe używanie lub działanie programu!
*/
#include "stdafx.h"
#include "MWD.h"
#include "Globals.h"
#include "Logs.h"
#include "World.h"
#include <windows.h>
HANDLE hComm;
TMWDComm::TMWDComm() // konstruktor
{
MWDTime = 0;
bSHPstate = false;
bPrzejazdSHP = false;
bKabina1 = true; // pasuje wyciągnąć dane na temat kabiny
bKabina2 = false; // i ustawiać te dwa parametry!
bHamowanie = false;
bCzuwak = false;
bRysik1H = false;
bRysik1L = false;
bRysik2H = false;
bRysik2L = false;
bocznik = 0;
nastawnik = 0;
kierunek = 0;
bnkMask = 0;
int i = 6;
while (i)
{
i--;
lastStateData[i] = 0;
maskData[i] = 0;
maskSwitch[i] = 0;
bitSwitch[i] = 0;
}
i = 0;
while (i<BYTETOWRITE)
{
if (i<BYTETOREAD)ReadDataBuff[i] = 0;
WriteDataBuff[i] = 0;
i++;
}
i = 0;
while (i<6)
{
lastStateData[i] = 0;
maskSwitch[i] = 0;
bitSwitch[i] = 0;
i++;
}
}
TMWDComm::~TMWDComm() // destruktor
{
Close();
}
bool TMWDComm::Open() // otwieranie portu COM
{
LPCSTR portId = Global::sMWDPortId.c_str();
hComm = CreateFile(portId, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
if (hComm == INVALID_HANDLE_VALUE)
{
if (GetLastError() == ERROR_FILE_NOT_FOUND)
{
WriteLog("PortCOM ERROR: serial port does not exist"); // serial port does not exist.
// Inform user.
}
WriteLog("PortCOM ERROR! not open!");
// some other error occurred. Inform user.
return FALSE;
}
DCB CommDCB;
CommDCB.DCBlength = sizeof(DCB);
GetCommState(hComm, &CommDCB);
CommDCB.BaudRate = Global::iMWDBaudrate;
CommDCB.fBinary = TRUE;
CommDCB.fParity = FALSE;
CommDCB.fOutxCtsFlow = FALSE; // No CTS output flow control
CommDCB.fOutxDsrFlow = FALSE; // No DSR output flow control
CommDCB.fDtrControl = FALSE; // DTR flow control type
CommDCB.fDsrSensitivity = FALSE; // DSR sensitivity
CommDCB.fTXContinueOnXoff = FALSE; // XOFF continues Tx
CommDCB.fOutX = FALSE; // No XON/XOFF out flow control
CommDCB.fInX = FALSE; // No XON/XOFF in flow control
CommDCB.fErrorChar = FALSE; // Disable error replacement
CommDCB.fNull = FALSE; // Disable null stripping
CommDCB.fRtsControl = RTS_CONTROL_DISABLE;
CommDCB.fAbortOnError = FALSE;
CommDCB.ByteSize = 8;
CommDCB.Parity = NOPARITY;
CommDCB.StopBits = ONESTOPBIT;
// konfiguracja portu
if (!SetCommState(hComm, &CommDCB))
{
// dwError = GetLastError ();
WriteLog("Unable to configure the serial port!");
return FALSE;
}
WriteLog("PortCOM OPEN and CONFIG!");
return TRUE;
}
bool TMWDComm::Close() // zamykanie portu COM
{
Global::bMWDmasterEnable = false; // główne włączenie portu!
Global::bMWDInputEnable = false; // włącz wejścia
Global::bMWDBreakEnable = false; // włącz wejścia analogowe
WriteLog("COM Port is closing...");
int i = 0;
while (i < BYTETOWRITE) // zerowanie danych...
{
WriteDataBuff[i] = 0;
i++;
}
Sleep(100);
SendData(); // wysyłanie do pulpitu: zatrzymanie haslera i zgaszenie lampek
Sleep(700);
CloseHandle(hComm);
WriteLog("COM is close!");
return TRUE;
}
bool TMWDComm::GetMWDState() // sprawdzanie otwarcia portu COM
{
if (hComm > 0)
return 1;
else
return 0;
}
bool TMWDComm::ReadData() // odbieranie danych + odczyta danych analogowych i zapis do zmiennych
{
DWORD bytes_read;
ReadFile(hComm, &ReadDataBuff[0], BYTETOREAD, &bytes_read, NULL);
if (Global::bMWDdebugEnable && Global::iMWDDebugMode == 128) WriteLog("Data receive. Checking data...");
if (Global::bMWDBreakEnable)
{
uiAnalog[0] = (ReadDataBuff[9] << 8) + ReadDataBuff[8];
uiAnalog[1] = (ReadDataBuff[11] << 8) + ReadDataBuff[10];
uiAnalog[2] = (ReadDataBuff[13] << 8) + ReadDataBuff[12];
uiAnalog[3] = (ReadDataBuff[15] << 8) + ReadDataBuff[14];
if (Global::bMWDdebugEnable && (Global::iMWDDebugMode & 1))
{
WriteLog("Main Break = " + to_string(uiAnalog[0]));
WriteLog("Locomotiv Break = " + to_string(uiAnalog[1]));
}
if (Global::bMWDdebugEnable && (Global::iMWDDebugMode & 2))
{
WriteLog("Analog input 1 = " + to_string(uiAnalog[2]));
WriteLog("Analog imput 2 = " + to_string(uiAnalog[3]));
}
}
if (Global::bMWDInputEnable) CheckData();
return TRUE;
}
bool TMWDComm::SendData() // wysyłanie danych
{
DWORD bytes_write;
WriteFile(hComm, &WriteDataBuff[0], BYTETOWRITE, &bytes_write, NULL);
return TRUE;
}
bool TMWDComm::Run() // wywoływanie obsługi MWD + generacja większego opóźnienia
{
if (GetMWDState())
{
MWDTime++;
if (!(MWDTime % Global::iMWDdivider))
{
MWDTime = 0;
if (Global::bMWDdebugEnable && Global::iMWDDebugMode == 128) WriteLog("Sending data...");
SendData();
if (Global::bMWDdebugEnable && Global::iMWDDebugMode == 128) WriteLog(" complet!\nReceiving data...");
ReadData();
if (Global::bMWDdebugEnable && Global::iMWDDebugMode == 128) WriteLog(" complet!");
return 1;
}
}
else
{
WriteLog("Port COM: connection ERROR!");
Close();
// może spróbować się połączyć znowu?
return 0;
}
return 1;
}
void TMWDComm::CheckData() // sprawdzanie wejść cyfrowych i odpowiednie sterowanie maszyną
{
int i = 0;
while (i < 6)
{
maskData[i] = ReadDataBuff[i] ^ lastStateData[i];
lastStateData[i] = ReadDataBuff[i];
i++;
}
/*
Rozpiska portów!
Port0: 0 NC odblok. przek. sprężarki i wentyl. oporów
1 M wyłącznik wył. szybkiego
2 Shift+M impuls załączający wył. szybki
3 N odblok. przekaźników nadmiarowych
i różnicowego obwodu głównegoMMm
4 NC rezerwa
5 Ctrl+N odblok. przek. nadmiarowych
przetwornicy, ogrzewania pociągu i różnicowych obw. pomocniczych
6 L wył. styczników liniowych
7 SPACE kasowanie czuwaka
Port1: 0 NC
1 (Shift) X przetwornica
2 (Shift) C sprężarka
3 S piasecznice
4 (Shift) H ogrzewanie składu
5 przel. hamowania Shift+B
pspbpwy Ctrl+B pospieszny B towarowy
6 przel. hamowania
7 (Shift) F rozruch w/n
Port2: 0 (Shift) P pantograf przedni
1 (Shift) O pantograf tylni
2 ENTER przyhamowanie przy poślizgu
3 () przyciemnienie świateł
4 () przyciemnienie świateł
5 NUM6 odluźniacz
6 a syrena lok W
7 A syrena lok N
Port3: 0 Shift+J bateria
1
2
3
4
5
6
7
*/
/* po przełączeniu bistabilnego najpierw wciskamy klawisz i przy następnym
wejściu w pętlę MWD puszczamy bo inaczej nie działa
*/
// wciskanie przycisków klawiatury
/*PORT0*/
if (maskData[0] & 0x02) if (lastStateData[0] & 0x02)
KeyBoard('M', 1); // wyłączenie wyłącznika szybkiego
else KeyBoard('M', 0); // monostabilny
if (maskData[0] & 0x04) if (lastStateData[0] & 0x04) // impuls załączający wyłącznik szybki
{
KeyBoard(0x10, 1); // monostabilny
KeyBoard('M', 1);
}
else
{
KeyBoard('M', 0);
KeyBoard(0x10, 0);
}
if (maskData[0] & 0x08) if (lastStateData[0] & 0x08)
KeyBoard('N', 1); // odblok nadmiarowego silników trakcyjnych
else KeyBoard('N', 0); // monostabilny
if (maskData[0] & 0x20) if (lastStateData[0] & 0x20)
{ // odblok nadmiarowego przetwornicy, ogrzewania poc.
KeyBoard(0x11, 1); // różnicowego obwodów pomocniczych
KeyBoard('N', 1); // monostabilny
}
else
{
KeyBoard('N', 0);
KeyBoard(0x11, 0);
}
if (maskData[0] & 0x40) if (lastStateData[0] & 0x40) KeyBoard('L', 1); // wył. styczników liniowych
else KeyBoard('L', 0); // monostabilny
if (maskData[0] & 0x80) if (lastStateData[0] & 0x80) KeyBoard(0x20, 1); // kasowanie czuwaka/SHP
else KeyBoard(0x20, 0); // kasowanie czuwaka/SHP
/*PORT1*/
// puszczanie przycisku bistabilnego klawiatury
if (maskSwitch[1] & 0x02)
{
if (bitSwitch[1] & 0x02)
{
KeyBoard('X', 0);
KeyBoard(0x10, 0);
}
else KeyBoard('X', 0);
maskSwitch[1] &= ~0x02;
}
if (maskSwitch[1] & 0x04) {
if (bitSwitch[1] & 0x04) {
KeyBoard('C', 0);
KeyBoard(0x10, 0);
}
else KeyBoard('C', 0);
maskSwitch[1] &= ~0x04;
}
if (maskSwitch[1] & 0x10) {
if (bitSwitch[1] & 0x10) {
KeyBoard('H', 0);
KeyBoard(0x10, 0);
}
else KeyBoard('H', 0);
maskSwitch[1] &= ~0x10;
}
if (maskSwitch[1] & 0x20 || maskSwitch[1] & 0x40) {
if (maskSwitch[1] & 0x20) KeyBoard(0x10, 0);
if (maskSwitch[1] & 0x40) KeyBoard(0x11, 0);
KeyBoard('B', 0);
maskSwitch[1] &= ~0x60;
}
if (maskSwitch[1] & 0x80) {
if (bitSwitch[1] & 0x80) {
KeyBoard('F', 0);
KeyBoard(0x10, 0);
}
else KeyBoard('F', 0);
maskSwitch[1] &= ~0x80;
}
// przetwornica
if (maskData[1] & 0x02) if (lastStateData[1] & 0x02)
{
KeyBoard(0x10, 1); // bistabilny
KeyBoard('X', 1);
maskSwitch[1] |= 0x02;
bitSwitch[1] |= 0x02;
}
else
{
maskSwitch[1] |= 0x02;
bitSwitch[1] &= ~0x02;
KeyBoard('X', 1);
}
// sprężarka
if (maskData[1] & 0x04) if (lastStateData[1] & 0x04)
{
KeyBoard(0x10, 1); // bistabilny
KeyBoard('C', 1);
maskSwitch[1] |= 0x04;
bitSwitch[1] |= 0x04;
}
else
{
maskSwitch[1] |= 0x04;
bitSwitch[1] &= ~0x04;
KeyBoard('C', 1);
}
// piasecznica
if (maskData[1] & 0x08) if (lastStateData[1] & 0x08)
KeyBoard('S', 1);
else
KeyBoard('S', 0); // monostabilny
// ogrzewanie składu
if (maskData[1] & 0x10) if (lastStateData[1] & 0x10)
{
KeyBoard(0x11, 1); // bistabilny
KeyBoard('H', 1);
maskSwitch[1] |= 0x10;
bitSwitch[1] |= 0x10;
}
else
{
maskSwitch[1] |= 0x10;
bitSwitch[1] &= ~0x10;
KeyBoard('H', 1);
}
// przełącznik hamowania
if (maskData[1] & 0x20 || maskData[1] & 0x40)
{
if (lastStateData[1] & 0x20)
{ // Shift+B
KeyBoard(0x10, 1);
maskSwitch[1] |= 0x20;
}
else if (lastStateData[1] & 0x40)
{ // Ctrl+B
KeyBoard(0x11, 1);
maskSwitch[1] |= 0x40;
}
KeyBoard('B', 1);
}
// rozruch wysoki/niski
if (maskData[1] & 0x80) if (lastStateData[1] & 0x80)
{
KeyBoard(0x10, 1); // bistabilny
KeyBoard('F', 1);
maskSwitch[1] |= 0x80;
bitSwitch[1] |= 0x80;
}
else
{
maskSwitch[1] |= 0x80;
bitSwitch[1] &= ~0x80;
KeyBoard('F', 1);
}
//PORT2
if (maskSwitch[2] & 0x01)
{
if (bitSwitch[2] & 0x01)
{
KeyBoard('P', 0);
KeyBoard(0x10, 0);
}
else KeyBoard('P', 0);
maskSwitch[2] &= ~0x01;
}
if (maskSwitch[2] & 0x02)
{
if (bitSwitch[2] & 0x02)
{
KeyBoard('O', 0);
KeyBoard(0x10, 0);
}
else KeyBoard('O', 0);
maskSwitch[2] &= ~0x02;
}
// pantograf przedni
if (maskData[2] & 0x01) if (lastStateData[2] & 0x01)
{
KeyBoard(0x10, 1); // bistabilny
KeyBoard('P', 1);
maskSwitch[2] |= 0x01;
bitSwitch[2] |= 0x01;
}
else
{
maskSwitch[2] |= 0x01;
bitSwitch[2] &= ~0x01;
KeyBoard('P', 1);
}
// pantograf tylni
if (maskData[2] & 0x02) if (lastStateData[2] & 0x02)
{
KeyBoard(0x10, 1); // bistabilny
KeyBoard('O', 1);
maskSwitch[2] |= 0x02;
bitSwitch[2] |= 0x02;
}
else
{
maskSwitch[2] |= 0x02;
bitSwitch[2] &= ~0x02;
KeyBoard('O', 1);
}
// przyhamowanie przy poślizgu
if (maskData[2] & 0x04) if (lastStateData[2] & 0x04) {
KeyBoard(0x10, 1); // monostabilny
KeyBoard(0x0D, 1);
}
else
{
KeyBoard(0x0D, 0);
KeyBoard(0x10, 0);
}
/*if(maskData[2] & 0x08) if (lastStateData[2] & 0x08){ // przyciemnienie świateł
KeyBoard(' ',0); // bistabilny
KeyBoard(0x10,1);
KeyBoard(' ',1);
}else{
KeyBoard(' ',0);
KeyBoard(0x10,0);
KeyBoard(' ',1);
}
if(maskData[2] & 0x10) if (lastStateData[2] & 0x10) { // przyciemnienie świateł
KeyBoard(' ',0); // bistabilny
KeyBoard(0x11,1);
KeyBoard(' ',1);
}else{
KeyBoard(' ',0);
KeyBoard(0x11,0);
KeyBoard(' ',1);
}*/
// odluźniacz
if (maskData[2] & 0x20) if (lastStateData[2] & 0x20)
KeyBoard(0x66, 1);
else
KeyBoard(0x66, 0); // monostabilny
// syrena wysoka
if (maskData[2] & 0x40) if (lastStateData[2] & 0x40)
{
KeyBoard(0x10, 1); // monostabilny
KeyBoard('A', 1);
}
else
{
KeyBoard('A', 0);
KeyBoard(0x10, 0);
}
if (maskData[2] & 0x80) if (lastStateData[2] & 0x80)
KeyBoard('A', 1); // syrena niska
else
KeyBoard('A', 0); // monostabilny
//PORT3
if (maskSwitch[3] & 0x01)
{
if (bitSwitch[3] & 0x01)
{
KeyBoard('J', 0);
KeyBoard(0x10, 0);
}
else KeyBoard('J', 0);
maskSwitch[3] &= ~0x01;
}
if (maskSwitch[3] & 0x02)
{
if (bitSwitch[3] & 0x02)
{
KeyBoard('Y', 0);
KeyBoard(0x10, 0);
}
else KeyBoard('Y', 0);
maskSwitch[3] &= ~0x02;
}
if (maskSwitch[3] & 0x04)
{
if (bitSwitch[3] & 0x04)
{
KeyBoard('U', 0);
KeyBoard(0x10, 0);
}
else KeyBoard('U', 0);
maskSwitch[3] &= ~0x04;
}
if (maskSwitch[3] & 0x08)
{
if (bitSwitch[3] & 0x08)
{
KeyBoard('I', 0);
KeyBoard(0x10, 0);
}
else KeyBoard('I', 0);
maskSwitch[3] &= ~0x08;
}
// bateria
if (maskData[3] & 0x01) if (lastStateData[3] & 0x01)
{
KeyBoard(0x10, 1); // bistabilny
KeyBoard('J', 1);
maskSwitch[3] |= 0x01;
bitSwitch[3] |= 0x01;
}
else
{
maskSwitch[3] |= 0x01;
bitSwitch[3] &= ~0x01;
KeyBoard('J', 1);
}
//Światło lewe
if (maskData[3] & 0x02) if (lastStateData[3] & 0x02)
{
KeyBoard(0x10, 1); // bistabilny
KeyBoard('Y', 1);
maskSwitch[3] |= 0x02;
bitSwitch[3] |= 0x02;
}else
{
maskSwitch[3] |= 0x02;
bitSwitch[3] &= ~0x02;
KeyBoard('Y', 1);
}
//światło górne
if (maskData[3] & 0x04) if (lastStateData[3] & 0x04)
{
KeyBoard(0x10, 1); // bistabilny
KeyBoard('U', 1);
maskSwitch[3] |= 0x04;
bitSwitch[3] |= 0x04;
}
else
{
maskSwitch[3] |= 0x04;
bitSwitch[3] &= ~0x04;
KeyBoard('U', 1);
}
//światło prawe
if (maskData[3] & 0x08) if (lastStateData[3] & 0x08)
{
KeyBoard(0x10, 1); // bistabilny
KeyBoard('I', 1);
maskSwitch[3] |= 0x08;
bitSwitch[3] |= 0x08;
}
else
{
maskSwitch[3] |= 0x08;
bitSwitch[3] &= ~0x08;
KeyBoard('I', 1);
}
/* NASTAWNIK, BOCZNIK i KIERUNEK */
if (bnkMask & 1)
{ // puszczanie klawiszy
KeyBoard(0x6B, 0);
bnkMask &= ~1;
}
if (bnkMask & 2)
{
KeyBoard(0x6D, 0);
bnkMask &= ~2;
}
if (bnkMask & 4)
{
KeyBoard(0x6F, 0);
bnkMask &= ~4;
}
if (bnkMask & 8)
{
KeyBoard(0x6A, 0);
bnkMask &= ~8;
}
if (nastawnik < ReadDataBuff[6])
{
bnkMask |= 1;
nastawnik++;
KeyBoard(0x6B, 1); // wciśnij + i dodaj 1 do nastawnika
}
if (nastawnik > ReadDataBuff[6])
{
bnkMask |= 2;
nastawnik--;
KeyBoard(0x6D, 1); // wciśnij - i odejmij 1 do nastawnika
}
if (bocznik < ReadDataBuff[7])
{
bnkMask |= 4;
bocznik++;
KeyBoard(0x6F, 1); // wciśnij / i dodaj 1 do bocznika
}
if (bocznik > ReadDataBuff[7])
{
bnkMask |= 8;
bocznik--;
KeyBoard(0x6A, 1); // wciśnij * i odejmij 1 do bocznika
}
/* Obsługa HASLERA */
if (ReadDataBuff[0] & 0x80)
bCzuwak = true;
if (bKabina1)
{ // logika rysika 1
bRysik1H = true;
bRysik1L = false;
if (bPrzejazdSHP)
bRysik1H = false;
}
else if (bKabina2)
{
bRysik1L = true;
bRysik1H = false;
if (bPrzejazdSHP)
bRysik1L = false;
}
else
{
bRysik1H = false;
bRysik1L = false;
}
if (bHamowanie)
{ // logika rysika 2
bRysik2H = false;
bRysik2L = true;
}
else
{
if (bCzuwak)
bRysik2H = true;
else
bRysik2H = false;
bRysik2L = false;
}
bCzuwak = false;
if (bRysik1H)
WriteDataBuff[6] |= 1 << 0;
else
WriteDataBuff[6] &= ~(1 << 0);
if (bRysik1L)
WriteDataBuff[6] |= 1 << 1;
else
WriteDataBuff[6] &= ~(1 << 1);
if (bRysik2H)
WriteDataBuff[6] |= 1 << 2;
else
WriteDataBuff[6] &= ~(1 << 2);
if (bRysik2L)
WriteDataBuff[6] |= 1 << 3;
else
WriteDataBuff[6] &= ~(1 << 3);
}
void TMWDComm::KeyBoard(int key, bool s) // emulacja klawiatury
{
INPUT ip;
// Set up a generic keyboard event.
ip.type = INPUT_KEYBOARD;
ip.ki.wScan = 0; // hardware scan code for key
ip.ki.time = 0;
ip.ki.dwExtraInfo = 0;
ip.ki.wVk = key; // virtual-key code for the "a" key
if (s)
{ // Press the "A" key
ip.ki.dwFlags = 0; // 0 for key press
SendInput(1, &ip, sizeof(INPUT));
}
else
{
ip.ki.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP for key release
SendInput(1, &ip, sizeof(INPUT));
}
// return 1;
}

View File

@@ -1,98 +0,0 @@
/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
/*
Program obsługi portu COM i innych na potrzeby sterownika MWDevice
(oraz innych wykorzystujących komunikację przez port COM)
dla Symulatora Pojazdów Szynowych MaSzyna
author: Maciej Witek 2016
Autor nie ponosi odpowiedzialności za niewłaciwe używanie lub działanie programu!
*/
#ifndef MWDH
#define MWDH
//---------------------------------------------------------------------------
#define BYTETOWRITE 31 // ilość bajtów przesyłanych z MaSzyny
#define BYTETOREAD 16 // ilość bajtów przesyłanych do MaSzyny
typedef unsigned char BYTE;
typedef unsigned long DWORD;
class TMWDComm
{
private:
int MWDTime; //
char lastStateData[6], maskData[6], maskSwitch[6], bitSwitch[6];
int bocznik, nastawnik, kierunek;
char bnkMask;
bool ReadData(); //BYTE *pReadDataBuff);
bool SendData(); //BYTE *pWriteDataBuff);
void CheckData(); //sprawdzanie zmian wejść i kontrola mazaków HASLERA
void KeyBoard(int key, bool s);
//void CheckData2();
bool bRysik1H;
bool bRysik1L;
bool bRysik2H;
bool bRysik2L;
public:
bool Open(); // Otwarcie portu
bool Close(); // Zamknięcie portu
bool Run(); // Obsługa portu
bool GetMWDState(); // sprawdź czy port jest otwarty, 0 zamknięty, 1 otwarty
// zmienne do rysików HASLERA
bool bSHPstate;
bool bPrzejazdSHP;
bool bKabina1;
bool bKabina2;
bool bHamowanie;
bool bCzuwak;
unsigned int uiAnalog[4]; // trzymanie danych z wejść analogowych
BYTE ReadDataBuff[BYTETOREAD+2]; //17]; // bufory danych
BYTE WriteDataBuff[BYTETOWRITE+2]; //31];
TMWDComm(); // konstruktor
~TMWDComm(); // destruktor
};
#endif
/*
INFO - wpisy do eu07.ini:
mwdmasterenable yes // włącz MWD (master MWD Enable)
mwddebugenable yes // włącz logowanie
mwddebugmode 4 // tryb debugowania (które logi)
mwdcomportname COM3 // nazwa portu
mwdbaudrate 500000 // prędkość transmisji
mwdinputenable yes // włącz wejścia (przyciski, przełączniki)
mwdbreakenable yes // włącz hamulce (wejścia analogowe)
mwdmainbreakconfig 0 1023 // konfiguracja kranu zespolonego -> min, max (położenie kranu - odczyt z ADC)
mwdlocbreakconfig 0 1023 // konfiguracja kranu maszynisty -> min, max (położenie kranu - odczyt z ADC)
mwdanalogin2config 0 1023
mwdanalogin2config 0 1023
mwdmaintankpress 0.9 1023 // max ciśnienie w zbiorniku głownym i rozdzielczość
mwdmainpipepress 0.7 1023 // max ciśnienie w przewodzie głównym i rozdzielczość
mwdbreakpress 0.5 1023 // max ciśnienie w cylindrach hamulcowych i rozdzielczość
mwdhivoltmeter 4000 1023 // max napięcie na woltomierzu WN
mwdhiampmeter 800 1023 // max prąd amperomierza WN
mwddivider 5 // dzielnik - czym większy tym rzadziej czyta diwajs
*/

View File

@@ -1422,11 +1422,15 @@ void TController::TablePurger()
iLast = sSpeedTable.size() - 1;
};
void TController::TableSort()
{
void TController::TableSort() {
if( sSpeedTable.size() < 3 ) {
// we skip last slot and no point in checking if there's only one other entry
return;
}
TSpeedPos sp_temp = TSpeedPos(); // uzywany do przenoszenia
for (std::size_t i = 0; i < (iLast - 1) && iLast > 0; ++i)
{ // pętla tylko do dwóch pozycji od końca bo ostatniej nie modyfikujemy
for( std::size_t i = 0; i < ( iLast - 1 ); ++i ) {
// pętla tylko do dwóch pozycji od końca bo ostatniej nie modyfikujemy
if (sSpeedTable[i].fDist > sSpeedTable[i + 1].fDist)
{ // jesli pozycja wcześniejsza jest dalej to źle
sp_temp = sSpeedTable[i + 1];
@@ -4574,24 +4578,52 @@ TController::UpdateSituation(double dt) {
}
// koniec predkosci nastepnej
if( vel > VelDesired ) {
// jesli jedzie za szybko do AKTUALNEGO
if( VelDesired == 0.0 ) {
// jesli stoj, to hamuj, ale i tak juz za pozno :)
AccDesired = std::min( AccDesired, -0.85 ); // hamuj solidnie
}
else {
// try to estimate increase of current velocity before engaged brakes start working
// if it looks like we'll exceed maximum allowed speed start thinking about slight slowing down
if( ( vel + vel * ( 1.0 - fBrake_a0[ 0 ] ) * AbsAccS ) > ( VelDesired + fVelPlus ) ) {
// hamuj tak średnio
AccDesired = std::min( AccDesired, -0.25 );
// decisions based on current speed
if( mvOccupied->CategoryFlag == 1 ) {
// try to estimate increase of current velocity before engaged brakes start working
auto const speedestimate = vel + vel * ( 1.0 - fBrake_a0[ 0 ] ) * AbsAccS;
if( speedestimate > VelDesired ) {
// jesli jedzie za szybko do AKTUALNEGO
if( VelDesired == 0.0 ) {
// jesli stoj, to hamuj, ale i tak juz za pozno :)
AccDesired = std::min( AccDesired, -0.85 ); // hamuj solidnie
}
else {
// o 5 km/h to olej (zacznij luzować)
AccDesired = std::min(
AccDesired, // but don't override decceleration for VelNext
std::max( 0.0, AccPreferred ) );
if( speedestimate > ( VelDesired + fVelPlus ) ) {
// if it looks like we'll exceed maximum allowed speed start thinking about slight slowing down
AccDesired = std::min( AccDesired, -0.25 );
}
else {
// close enough to target to stop accelerating
AccDesired = std::min(
AccDesired, // but don't override decceleration for VelNext
interpolate( // ease off as you close to the target velocity
-0.06, AccPreferred,
clamp( speedestimate - vel, 0.0, fVelPlus ) / fVelPlus ) );
}
}
}
}
else {
// for cars the older version works better
if( vel > VelDesired ) {
// jesli jedzie za szybko do AKTUALNEGO
if( VelDesired == 0.0 ) {
// jesli stoj, to hamuj, ale i tak juz za pozno :)
AccDesired = std::min( AccDesired, -0.9 ); // hamuj solidnie
}
else {
// slow down, not full stop
if( vel > ( VelDesired + fVelPlus ) ) {
// hamuj tak średnio
AccDesired = std::min( AccDesired, -fBrake_a0[ 0 ] * 0.5 );
}
else {
// o 5 km/h to olej (zacznij luzować)
AccDesired = std::min(
AccDesired, // but don't override decceleration for VelNext
std::max( 0.0, AccPreferred ) );
}
}
}
}
@@ -4599,8 +4631,10 @@ TController::UpdateSituation(double dt) {
// last step sanity check, until the whole calculation is straightened out
AccDesired = std::min( AccDesired, AccPreferred );
// also take into account impact of gravity
AccDesired = clamp( AccDesired - fAccGravity, -0.9, 0.9 );
if( mvOccupied->CategoryFlag == 1 ) {
// also take into account impact of gravity
AccDesired = clamp( AccDesired - fAccGravity, -0.9, 0.9 );
}

View File

@@ -171,8 +171,8 @@ extern bool WriteLogFlag; // logowanie parametrów fizycznych
static const int BrakeAccTableSize = 20;
//----------------------------------------------------------------------------
class TController
{
class TController {
private: // obsługa tabelki prędkości (musi mieć możliwość odhaczania stacji w rozkładzie)
int iLast{ 0 }; // ostatnia wypełniona pozycja w tabeli <iFirst (modulo iSpeedTableSize)
int iTableDirection{ 0 }; // kierunek zapełnienia tabelki względem pojazdu z AI
@@ -183,7 +183,7 @@ class TController
std::size_t SemNextIndex{ std::size_t(-1) };
std::size_t SemNextStopIndex{ std::size_t( -1 ) };
double dMoveLen = 0.0; // odległość przejechana od ostatniego sprawdzenia tabelki
private: // parametry aktualnego składu
// parametry aktualnego składu
double fLength = 0.0; // długość składu (do wyciągania z ograniczeń)
double fMass = 0.0; // całkowita masa do liczenia stycznej składowej grawitacji
public:
@@ -191,11 +191,11 @@ public:
TEvent *eSignNext = nullptr; // sygnał zmieniający prędkość, do pokazania na [F2]
std::string asNextStop; // nazwa następnego punktu zatrzymania wg rozkładu
int iStationStart = 0; // numer pierwszej stacji pokazywanej na podglądzie rozkładu
private: // parametry sterowania pojazdem (stan, hamowanie)
// parametry sterowania pojazdem (stan, hamowanie)
private:
double fShuntVelocity = 40.0; // maksymalna prędkość manewrowania, zależy m.in. od składu // domyślna prędkość manewrowa
int iVehicles = 0; // ilość pojazdów w składzie
int iEngineActive = 0; // ABu: Czy silnik byl juz zalaczony; Ra: postęp w załączaniu
// vector3 vMechLoc; //pozycja pojazdu do liczenia odległości od semafora (?)
bool Psyche = false;
int iDrivigFlags = // flagi bitowe ruchu
moveStopPoint | // podjedź do W4 możliwie blisko

View File

@@ -33,6 +33,7 @@ Stele, firleju, szociu, hunter, ZiomalCl, OLI_EU and others
#include "Timer.h"
#include "resource.h"
#include "uilayer.h"
#include "uart.h"
#pragma comment (lib, "glu32.lib")
#pragma comment (lib, "dsound.lib")
@@ -54,7 +55,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_input> uart;
}
void screenshot_save_thread( char *img )
@@ -354,9 +355,13 @@ int main(int argc, char *argv[])
sound_man = std::make_unique<sound_manager>();
Global::pWorld = &World;
input::Keyboard.init();
input::Mouse.init();
input::Gamepad.init();
if (Global::uart_conf.enable)
input::uart = std::make_unique<uart_input>();
Global::pWorld = &World;
if( false == World.Init( window ) ) {
@@ -398,6 +403,8 @@ int main(int argc, char *argv[])
&& ( true == GfxRenderer.Render() ) ) {
glfwPollEvents();
input::Keyboard.poll();
if (input::uart)
input::uart->poll();
if( true == Global::InputMouse ) { input::Mouse.poll(); }
if( true == Global::InputGamepad ) { input::Gamepad.poll(); }
}

View File

@@ -25,6 +25,11 @@ class float3
};
float Length() const;
float LengthSquared() const;
operator glm::vec3() const
{
return glm::vec3(x, y, z);
}
};
inline bool operator==(const float3 &v1, const float3 &v2)

View File

@@ -19,6 +19,8 @@ http://mozilla.org/MPL/2.0/.
#include "Model3d.h"
#include "Timer.h"
#include "Logs.h"
#include "World.h"
#include "Train.h"
void TGauge::Init(TSubModel *NewSubModel, TGaugeType eNewType, double fNewScale, double fNewOffset, double fNewFriction, double fNewValue)
{ // ustawienie parametrów animacji submodelu
@@ -315,14 +317,33 @@ void TGauge::UpdateValue()
}
};
void
TGauge::play( sound *Sound ) {
// todo: ugly approach to getting train translation
// maybe cache gauge position
if( Sound == nullptr ) { return; }
extern TWorld World;
void TGauge::play( sound *Sound )
{
if (!Sound)
return;
Sound->stop();
if (SubModel && World.train())
{
float4x4 mat;
SubModel->ParentMatrix(&mat);
glm::vec3 pos = *mat.TranslationGet();
if (glm::length(pos) > 1.0f)
{
pos = glm::vec3(glm::vec4(pos, 1.0f) * glm::inverse((glm::mat4)World.train()->Dynamic()->mMatrix));
pos = pos + (glm::vec3)World.train()->Dynamic()->GetPosition();
Sound->set_mode(sound::anchored).dist(1.5f).position(pos);
}
}
Sound->play();
return;
}
//---------------------------------------------------------------------------

View File

@@ -68,7 +68,7 @@ class TGauge {
void AssignDouble(double *dValue);
void AssignInt(int *iValue);
void UpdateValue();
TSubModel *SubModel; // McZapkie-310302: zeby mozna bylo sprawdzac czy zainicjowany poprawnie
TSubModel *SubModel = nullptr; // McZapkie-310302: zeby mozna bylo sprawdzac czy zainicjowany poprawnie
};
//---------------------------------------------------------------------------

View File

@@ -166,24 +166,11 @@ int Global::iPoKeysPWM[7] = {0, 1, 2, 3, 4, 5, 6};
bool Global::bnewAirCouplers = true;
double Global::fTimeSpeed = 1.0; // przyspieszenie czasu, zmienna do testów
bool Global::bHideConsole = false; // hunter-271211: ukrywanie konsoli
Global::uart_conf_t Global::uart_conf;
//randomizacja
std::mt19937 Global::random_engine = std::mt19937(std::time(NULL));
// maciek001: konfiguracja wstępna portu COM
bool Global::bMWDmasterEnable = false; // główne włączenie portu!
bool Global::bMWDdebugEnable = false; // włącz dodawanie do logu
int Global::iMWDDebugMode = 0; // co ma wyświetlać w logu
std::string Global::sMWDPortId = "COM1"; // nazwa portu z którego korzystamy
unsigned long int Global::iMWDBaudrate = 9600; // prędkość transmisji danych
bool Global::bMWDInputEnable = false; // włącz wejścia
bool Global::bMWDBreakEnable = false; // włącz wejścia analogowe
double Global::fMWDAnalogInCalib[4][2] = { { 0, 1023 },{ 0, 1023 },{ 0, 1023 },{ 0, 1023 } }; // wartość max potencjometru, wartość min potencjometru, rozdzielczość (max. wartość jaka może być)
double Global::fMWDzg[2] = { 0.9, 1023 };
double Global::fMWDpg[2] = { 0.8, 1023 };
double Global::fMWDph[2] = { 0.6, 1023 };
double Global::fMWDvolt[2] = { 4000, 1023 };
double Global::fMWDamp[2] = { 800, 1023 };
double Global::fMWDlowVolt[2] = { 150, 1023 };
int Global::iMWDdivider = 5;
opengl_light Global::DayLight;
Global::soundmode_t Global::soundpitchmode = Global::linear;
@@ -756,102 +743,33 @@ void Global::ConfigParse(cParser &Parser)
Parser.getTokens();
Parser >> Global::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")
{
Parser.getTokens(3, false);
Global::uart_conf.enable = true;
Parser >> Global::uart_conf.port;
Parser >> Global::uart_conf.baud;
Parser >> Global::uart_conf.interval;
Parser >> Global::uart_conf.updatetime;
}
else if (token == "uarttune")
{
Parser.getTokens(14);
Parser >> Global::uart_conf.mainbrakemin
>> Global::uart_conf.mainbrakemax
>> Global::uart_conf.localbrakemin
>> Global::uart_conf.localbrakemax
>> Global::uart_conf.tankmax
>> Global::uart_conf.tankuart
>> Global::uart_conf.pipemax
>> Global::uart_conf.pipeuart
>> Global::uart_conf.brakemax
>> Global::uart_conf.brakeuart
>> Global::uart_conf.hvmax
>> Global::uart_conf.hvuart
>> Global::uart_conf.currentmax
>> Global::uart_conf.currentuart;
}
} while ((token != "") && (token != "endconfig")); //(!Parser->EndOfFile)
// na koniec trochę zależności
if (!bLoadTraction) // wczytywanie drutów i słupów

View File

@@ -293,6 +293,31 @@ class Global
//randomizacja
static std::mt19937 random_engine;
struct uart_conf_t
{
bool enable = false;
std::string port;
int baud;
int interval;
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;
};
static uart_conf_t uart_conf;
// metody
static void TrainDelete(TDynamicObject *d);
static void ConfigParse(cParser &parser);
@@ -303,23 +328,6 @@ class Global
static std::string Bezogonkow(std::string str, bool _ = false);
static double Min0RSpeed(double vel1, double vel2);
// maciek001: zmienne dla MWD
static bool bMWDmasterEnable; // główne włączenie portu COM
static bool bMWDdebugEnable; // logowanie pracy
static int iMWDDebugMode;
static std::string sMWDPortId; // nazwa portu COM
static unsigned long int iMWDBaudrate; // prędkość transmisji
static bool bMWDInputEnable; // włącz wejścia
static bool bMWDBreakEnable; // włącz wejścia analogowe (hamulce)
static double fMWDAnalogInCalib[4][2]; // ustawienia kranów hamulca zespolonego i dodatkowego - min i max
static double fMWDzg[2]; // max wartość wskazywana i max wartość generowana (rozdzielczość)
static double fMWDpg[2];
static double fMWDph[2];
static double fMWDvolt[2];
static double fMWDamp[2];
static double fMWDlowVolt[2];
static int iMWDdivider;
static opengl_light DayLight;
enum soundmode_t

View File

@@ -3593,6 +3593,45 @@ TGround::Update_Lights() {
m_lights.update();
}
void
TGround::Update_Hidden() {
// rednerowanie globalnych (nie za często?)
for( TGroundNode *node = srGlobal.nRenderHidden; node; node = node->nNext3 ) {
node->RenderHidden();
}
// render events and sounds from sectors near enough to the viewer
auto const range = 2750.0; // audible range of 100 db sound
int const camerax = static_cast<int>( std::floor( Global::pCameraPosition.x / 1000.0 ) + iNumRects / 2 );
int const cameraz = static_cast<int>( std::floor( Global::pCameraPosition.z / 1000.0 ) + iNumRects / 2 );
int const segmentcount = 2 * static_cast<int>( std::ceil( range / 1000.0 ) );
int const originx = std::max( 0, camerax - segmentcount / 2 );
int const originz = std::max( 0, cameraz - segmentcount / 2 );
for( int column = originx; column <= originx + segmentcount; ++column ) {
for( int row = originz; row <= originz + segmentcount; ++row ) {
auto &cell = Rects[ column ][ row ];
for( int subcellcolumn = 0; subcellcolumn < iNumSubRects; ++subcellcolumn ) {
for( int subcellrow = 0; subcellrow < iNumSubRects; ++subcellrow ) {
auto subcell = cell.FastGetSubRect( subcellcolumn, subcellrow );
if( subcell == nullptr ) { continue; }
// renderowanie obiektów aktywnych a niewidocznych
for( auto node = subcell->nRenderHidden; node; node = node->nNext3 ) {
node->RenderHidden();
}
// jeszcze dźwięki pojazdów by się przydały, również niewidocznych
// TODO: move to sound renderer
subcell->RenderSounds();
}
}
}
}
}
// Winger 170204 - szukanie trakcji nad pantografami
bool TGround::GetTraction(TDynamicObject *model)
{ // aktualizacja drutu zasilającego dla każdego pantografu, żeby odczytać napięcie

View File

@@ -228,7 +228,7 @@ public:
return pSubRects + iRow * iNumSubRects + iCol; // zwrócenie właściwego
};
// pobranie wskaźnika do małego kwadratu, bez tworzenia jeśli nie ma
TSubRect * FastGetSubRect(int iCol, int iRow) {
TSubRect *FastGetSubRect(int iCol, int iRow) const {
return (
pSubRects ?
pSubRects + iRow * iNumSubRects + iCol :
@@ -289,6 +289,7 @@ class TGround
void UpdatePhys(double dt, int iter); // aktualizacja fizyki stałym krokiem
bool Update(double dt, int iter); // aktualizacja przesunięć zgodna z FPS
void Update_Lights(); // updates scene lights array
void Update_Hidden(); // updates invisible elements of the scene
bool AddToQuery(TEvent *Event, TDynamicObject *Node);
bool GetTraction(TDynamicObject *model);
bool CheckQuery();

View File

@@ -1090,7 +1090,9 @@ void TSubModel::ParentMatrix(float4x4 *m)
// jeśli nie zostało wykonane Init() (tzn. zaraz po wczytaniu T3D), to
// dodatkowy obrót
// obrót T3D jest wymagany np. do policzenia wysokości pantografów
*m = float4x4(*fMatrix); // skopiowanie, bo będziemy mnożyć
m->Identity();
if (fMatrix)
*m = float4x4(*fMatrix); // skopiowanie, bo będziemy mnożyć
// m(3)[1]=m[3][1]+0.054; //w górę o wysokość ślizgu (na razie tak)
TSubModel *sm = this;
while (sm->Parent)

View File

@@ -479,6 +479,7 @@ void TPythonScreens::update()
void TPythonScreens::setLookupPath(std::string const &path)
{
_lookupPath = path;
std::replace(_lookupPath.begin(), _lookupPath.end(), '\\', '/');
}
TPythonScreens::TPythonScreens()

255
Train.cpp
View File

@@ -824,8 +824,7 @@ void TTrain::OnCommand_trainbrakedecrease( TTrain *Train, command_data const &Co
if( ( Train->mvOccupied->BrakeCtrlPos == -1 )
&& ( Train->mvOccupied->BrakeHandle == FVel6 )
&& ( Train->DynamicObject->Controller != AIdriver )
&& ( Global::iFeedbackMode != 4 )
&& ( !( Global::bMWDmasterEnable && Global::bMWDBreakEnable ) ) ) {
&& ( Global::iFeedbackMode != 4 ) ) {
// Odskakiwanie hamulce EP
Train->mvOccupied->BrakeLevelSet( Train->mvOccupied->BrakeCtrlPos + 1 );
Train->keybrakecount = 0;
@@ -856,8 +855,7 @@ void TTrain::OnCommand_trainbrakecharging( TTrain *Train, command_data const &Co
if( ( Train->mvOccupied->BrakeCtrlPos == -1 )
&& ( Train->mvOccupied->BrakeHandle == FVel6 )
&& ( Train->DynamicObject->Controller != AIdriver )
&& ( Global::iFeedbackMode != 4 )
&& ( !( Global::bMWDmasterEnable && Global::bMWDBreakEnable ) ) ) {
&& ( Global::iFeedbackMode != 4 ) ) {
// Odskakiwanie hamulce EP
Train->mvOccupied->BrakeLevelSet( Train->mvOccupied->BrakeCtrlPos + 1 );
Train->keybrakecount = 0;
@@ -1248,7 +1246,12 @@ void TTrain::OnCommand_alerteracknowledge( TTrain *Train, command_data const &Co
}
}
void TTrain::OnCommand_batterytoggle( TTrain *Train, command_data const &Command ) {
void TTrain::OnCommand_batterytoggle( TTrain *Train, command_data const &Command )
{
if (Command.desired_state == command_data::ON && Train->mvOccupied->Battery)
return;
if (Command.desired_state == command_data::OFF && !Train->mvOccupied->Battery)
return;
if( Command.action == GLFW_PRESS ) {
// only reacting to press, so the switch doesn't flip back and forth if key is held down
@@ -1289,7 +1292,19 @@ void TTrain::OnCommand_batterytoggle( TTrain *Train, command_data const &Command
}
}
void TTrain::OnCommand_pantographtogglefront( TTrain *Train, command_data const &Command ) {
void TTrain::OnCommand_pantographtogglefront( TTrain *Train, command_data const &cmd )
{
command_data Command = cmd;
if (Train->mvOccupied->PantSwitchType != "impulse")
{
if (Command.desired_state == Command.ON && Train->mvControlled->PantFrontUp)
return;
if (Command.desired_state == Command.OFF && !Train->mvControlled->PantFrontUp)
return;
}
else if (Command.desired_state == Command.OFF)
Command.action = GLFW_RELEASE;
if( Command.action == GLFW_PRESS ) {
// only reacting to press, so the switch doesn't flip back and forth if key is held down
@@ -1369,7 +1384,18 @@ void TTrain::OnCommand_pantographtogglefront( TTrain *Train, command_data const
}
}
void TTrain::OnCommand_pantographtogglerear( TTrain *Train, command_data const &Command ) {
void TTrain::OnCommand_pantographtogglerear( TTrain *Train, command_data const &cmd ) {
command_data Command = cmd;
if (Train->mvOccupied->PantSwitchType != "impulse")
{
if (Command.desired_state == Command.ON && Train->mvControlled->PantRearUp)
return;
if (Command.desired_state == Command.OFF && !Train->mvControlled->PantRearUp)
return;
}
else if (Command.desired_state == Command.OFF)
Command.action = GLFW_RELEASE;
if( Command.action == GLFW_PRESS ) {
// only reacting to press, so the switch doesn't flip back and forth if key is held down
@@ -1562,7 +1588,8 @@ void TTrain::OnCommand_linebreakertoggle( TTrain *Train, command_data const &Com
if( Command.action != GLFW_RELEASE ) {
// press or hold...
if( Train->m_linebreakerstate == 0 ) {
if ((Command.desired_state == command_data::TOGGLE && Train->m_linebreakerstate == 0)
|| Command.desired_state == command_data::ON) {
// ...to close the circuit
if( Command.action == GLFW_PRESS ) {
// fresh press, start fresh closing delay calculation
@@ -1609,39 +1636,26 @@ void TTrain::OnCommand_linebreakertoggle( TTrain *Train, command_data const &Com
}
}
}
else if( Train->m_linebreakerstate == 1 ) {
else if ((Command.desired_state == command_data::TOGGLE && Train->m_linebreakerstate == 1)
|| Command.desired_state == command_data::OFF) {
// ...to open the circuit
if( true == Train->mvControlled->MainSwitch( false ) ) {
Train->mvControlled->MainSwitch( false );
Train->m_linebreakerstate = -1;
Train->m_linebreakerstate = -1;
if( Train->ggMainOffButton.SubModel != nullptr ) {
// two separate switches to close and break the circuit
if( Train->ggMainOffButton.SubModel != nullptr ) {
// two separate switches to close and break the circuit
// visual feedback
Train->ggMainOffButton.UpdateValue( 1.0, Train->dsbSwitch );
}
else if( Train->ggMainButton.SubModel != nullptr ) {
// single two-state switch
{
// visual feedback
Train->ggMainOffButton.UpdateValue( 1.0, Train->dsbSwitch );
}
else if( Train->ggMainButton.SubModel != nullptr ) {
// single two-state switch
/*
// NOTE: we don't have switch type definition for the line breaker switch
// so for the time being we have hard coded "impulse" switches for all EMUs
// TODO: have proper switch type config for all switches, and put it in the cab switch descriptions, not in the .fiz
if( Train->mvControlled->TrainType == dt_EZT ) {
// audio feedback
if( Command.action == GLFW_PRESS ) {
Train->play_sound( Train->dsbSwitch );
}
// visual feedback
Train->ggMainButton.UpdateValue( 1.0 );
}
else
*/
{
// visual feedback
Train->ggMainButton.UpdateValue( 0.0, Train->dsbSwitch );
}
Train->ggMainButton.UpdateValue( 0.0, Train->dsbSwitch );
}
}
// play sound immediately when the switch is hit, not after release
if( Train->fMainRelayTimer > 0.0f ) {
Train->play_sound( Train->dsbRelay );
@@ -1713,6 +1727,11 @@ void TTrain::OnCommand_convertertoggle( TTrain *Train, command_data const &Comma
return;
}
if (Train->mvControlled->ConverterAllow && Command.desired_state == command_data::ON)
return;
if (!Train->mvControlled->ConverterAllow && Command.desired_state == command_data::OFF)
return;
if( Command.action == GLFW_PRESS ) {
// only reacting to press, so the switch doesn't flip back and forth if key is held down
if( ( false == Train->mvControlled->ConverterAllow )
@@ -1866,6 +1885,11 @@ void TTrain::OnCommand_compressortoggle( TTrain *Train, command_data const &Comm
return;
}
if (Train->mvControlled->CompressorAllow && Command.desired_state == command_data::ON)
return;
if (!Train->mvControlled->CompressorAllow && Command.desired_state == command_data::OFF)
return;
if( Command.action == GLFW_PRESS ) {
// only reacting to press, so the switch doesn't flip back and forth if key is held down
if( false == Train->mvControlled->CompressorAllow ) {
@@ -1945,8 +1969,8 @@ void TTrain::OnCommand_compressortogglelocal( TTrain *Train, command_data const
}
}
void TTrain::OnCommand_motorconnectorsopen( TTrain *Train, command_data const &Command ) {
void TTrain::OnCommand_motorconnectorsopen( TTrain *Train, command_data const &cmd ) {
command_data Command = cmd;
// TODO: don't rely on presense of 3d model to determine presence of the switch
if( Train->ggStLinOffButton.SubModel == nullptr ) {
if( Command.action == GLFW_PRESS ) {
@@ -1954,6 +1978,17 @@ void TTrain::OnCommand_motorconnectorsopen( TTrain *Train, command_data const &C
}
return;
}
if (Train->mvControlled->StLinSwitchType == "toggle")
{
if (Command.desired_state == Command.ON && Train->mvControlled->StLinSwitchOff)
return;
if (Command.desired_state == Command.OFF && !Train->mvControlled->StLinSwitchOff)
return;
}
else if (Command.desired_state == Command.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 ) {
@@ -2064,7 +2099,12 @@ void TTrain::OnCommand_motordisconnect( TTrain *Train, command_data const &Comma
}
}
void TTrain::OnCommand_motoroverloadrelaythresholdtoggle( TTrain *Train, command_data const &Command ) {
void TTrain::OnCommand_motoroverloadrelaythresholdtoggle( TTrain *Train, command_data const &Command )
{
if (Train->mvControlled->Imax < Train->mvControlled->ImaxHi && Command.desired_state == command_data::OFF)
return;
if (!(Train->mvControlled->Imax < Train->mvControlled->ImaxHi) && Command.desired_state == command_data::ON)
return;
if( Command.action == GLFW_PRESS ) {
// only reacting to press, so the switch doesn't flip back and forth if key is held down
@@ -2119,9 +2159,16 @@ void TTrain::OnCommand_headlighttoggleleft( TTrain *Train, command_data const &C
0 :
1 );
bool current_state = (bool)(Train->DynamicObject->iLights[ lightsindex ] & TMoverParameters::light::headlight_left);
if (Command.desired_state == command_data::ON && current_state)
return;
if (Command.desired_state == command_data::OFF && !current_state)
return;
if( Command.action == GLFW_PRESS ) {
// only reacting to press, so the switch doesn't flip back and forth if key is held down
if( ( Train->DynamicObject->iLights[ lightsindex ] & TMoverParameters::light::headlight_left ) == 0 ) {
if( !current_state ) {
// turn on
Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::headlight_left;
// visual feedback
@@ -2152,9 +2199,16 @@ void TTrain::OnCommand_headlighttoggleright( TTrain *Train, command_data const &
0 :
1 );
bool current_state = (bool)(Train->DynamicObject->iLights[ lightsindex ] & TMoverParameters::light::headlight_right);
if (Command.desired_state == command_data::ON && current_state)
return;
if (Command.desired_state == command_data::OFF && !current_state)
return;
if( Command.action == GLFW_PRESS ) {
// only reacting to press, so the switch doesn't flip back and forth if key is held down
if( ( Train->DynamicObject->iLights[ lightsindex ] & TMoverParameters::light::headlight_right ) == 0 ) {
if( !current_state ) {
// turn on
Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::headlight_right;
// visual feedback
@@ -2185,9 +2239,16 @@ void TTrain::OnCommand_headlighttoggleupper( TTrain *Train, command_data const &
0 :
1 );
bool current_state = (bool)(Train->DynamicObject->iLights[ lightsindex ] & TMoverParameters::light::headlight_upper);
if (Command.desired_state == command_data::ON && current_state)
return;
if (Command.desired_state == command_data::OFF && !current_state)
return;
if( Command.action == GLFW_PRESS ) {
// only reacting to press, so the switch doesn't flip back and forth if key is held down
if( ( Train->DynamicObject->iLights[ lightsindex ] & TMoverParameters::light::headlight_upper ) == 0 ) {
if( !current_state ) {
// turn on
Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::headlight_upper;
// visual feedback
@@ -2452,6 +2513,11 @@ void TTrain::OnCommand_headlightsdimtoggle( TTrain *Train, command_data const &C
return;
}
if (Train->DynamicObject->DimHeadlights && Command.desired_state == command_data::ON)
return;
if (!Train->DynamicObject->DimHeadlights && Command.desired_state == command_data::OFF)
return;
if( Command.action == GLFW_PRESS ) {
// only reacting to press, so the switch doesn't flip back and forth if key is held down
if( false == Train->DynamicObject->DimHeadlights ) {
@@ -2509,6 +2575,11 @@ void TTrain::OnCommand_interiorlightdimtoggle( TTrain *Train, command_data const
return;
}
if (Train->bCabLightDim && Command.desired_state == command_data::ON)
return;
if (!Train->bCabLightDim && Command.desired_state == command_data::OFF)
return;
if( Command.action == GLFW_PRESS ) {
// only reacting to press, so the switch doesn't flip back and forth if key is held down
if( false == Train->bCabLightDim ) {
@@ -2564,6 +2635,11 @@ void TTrain::OnCommand_heatingtoggle( TTrain *Train, command_data const &Command
return;
}
if (Train->mvControlled->Heating && Command.desired_state == command_data::ON)
return;
if (!Train->mvControlled->Heating && Command.desired_state == command_data::OFF)
return;
if( Command.action == GLFW_PRESS ) {
// only reacting to press, so the switch doesn't flip back and forth if key is held down
if( false == Train->mvControlled->Heating ) {
@@ -3719,20 +3795,6 @@ bool TTrain::Update( double const Deltatime )
/// skakanie zapewnia mechanika
/// napędu
}
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 ;)
}
#endif
// hunter-080812: wyrzucanie szybkiego na elektrykach gdy nie ma napiecia
@@ -4654,7 +4716,7 @@ bool TTrain::Update( double const Deltatime )
#ifdef _WIN32
if (DynamicObject->Mechanik ?
(DynamicObject->Mechanik->AIControllFlag ? false :
(Global::iFeedbackMode == 4 || (Global::bMWDmasterEnable && Global::bMWDBreakEnable))) :
(Global::iFeedbackMode == 4)) :
false) // nie blokujemy AI
{ // Ra: nie najlepsze miejsce, ale na początek gdzieś to dać trzeba
// Firleju: dlatego kasujemy i zastepujemy funkcją w Console
@@ -4663,7 +4725,6 @@ bool TTrain::Update( double const Deltatime )
double b = Console::AnalogCalibrateGet(0);
b = b * 8.0 - 2.0;
b = clamp<double>( 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);
}
@@ -4672,7 +4733,6 @@ bool TTrain::Update( double const Deltatime )
double b = Console::AnalogCalibrateGet(0);
b = b * 7.0 - 1.0;
b = clamp<double>( 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);
}
@@ -4690,8 +4750,7 @@ bool TTrain::Update( double const Deltatime )
if( ( DynamicObject->Mechanik != nullptr )
&& ( false == DynamicObject->Mechanik->AIControllFlag ) // nie blokujemy AI
&& ( mvOccupied->BrakeLocHandle == FD1 )
&& ( ( Global::iFeedbackMode == 4 )
|| ( Global::bMWDmasterEnable && Global::bMWDBreakEnable ) ) ) {
&& ( ( Global::iFeedbackMode == 4 ) ) ) {
// Ra: nie najlepsze miejsce, ale na początek gdzieś to dać trzeba
// Firleju: dlatego kasujemy i zastepujemy funkcją w Console
auto const b = clamp<double>(
@@ -4700,10 +4759,6 @@ 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 // standardowa prodedura z kranem powiązanym z klawiaturą
#endif
@@ -7419,3 +7474,75 @@ TTrain::play_sound( sound* Sound, sound* Fallbacksound, float gain ) {
play_sound( Fallbacksound, gain );
}
float TTrain::get_tacho()
{
return fTachoVelocity;
}
float TTrain::get_tank_pressure()
{
return mvOccupied->Compressor;
}
float TTrain::get_pipe_pressure()
{
return mvOccupied->PipePress;
}
float TTrain::get_brake_pressure()
{
return mvOccupied->BrakePress;
}
float TTrain::get_hv_voltage()
{
return fHVoltage;
}
std::array<float, 3> TTrain::get_current()
{
return { fHCurrent[(mvControlled->TrainType & dt_EZT) ? 0 : 1], fHCurrent[2], fHCurrent[3] };
}
bool TTrain::get_alarm()
{
return (TestFlag(mvOccupied->SecuritySystem.Status, s_CAalarm) ||
TestFlag(mvOccupied->SecuritySystem.Status, s_SHPalarm));
}
void TTrain::set_mainctrl(int pos)
{
if (pos < mvControlled->MainCtrlPos)
mvControlled->DecMainCtrl(1);
else if (pos > mvControlled->MainCtrlPos)
mvControlled->IncMainCtrl(1);
}
void TTrain::set_scndctrl(int pos)
{
if (pos < mvControlled->ScndCtrlPos)
mvControlled->DecScndCtrl(1);
else if (pos > mvControlled->ScndCtrlPos)
mvControlled->IncScndCtrl(1);
}
void TTrain::set_trainbrake(float val)
{
val = std::min(1.0f, std::max(0.0f, val));
float min = mvControlled->Handle->GetPos(bh_MIN);
float max = mvControlled->Handle->GetPos(bh_MAX);
mvControlled->BrakeLevelSet(min + val * (max - min));
}
void TTrain::set_localbrake(float val)
{
val = std::min(1.0f, std::max(0.0f, val));
float min = 0.0f;
float max = (float)LocalBrakePosNo;
mvControlled->LocalBrakePos = std::round(min + val * (max - min));
}
int TTrain::get_drive_direction()
{
return mvOccupied->ActiveDir * mvOccupied->CabNo;
}

14
Train.h
View File

@@ -493,5 +493,19 @@ public: // reszta może by?publiczna
inline TMoverParameters *Controlled() { return mvControlled; };
void DynamicSet(TDynamicObject *d);
void Silence();
float get_tacho();
float get_tank_pressure();
float get_pipe_pressure();
float get_brake_pressure();
float get_hv_voltage();
std::array<float, 3> get_current();
bool get_alarm();
int get_drive_direction();
void set_mainctrl(int);
void set_scndctrl(int);
void set_trainbrake(float);
void set_localbrake(float);
};
//---------------------------------------------------------------------------

View File

@@ -1052,6 +1052,7 @@ bool TWorld::Update()
Ground.CheckQuery();
Ground.Update_Hidden();
Ground.Update_Lights();
{
@@ -1059,10 +1060,7 @@ bool TWorld::Update()
Camera.SetMatrix(cam_matrix);
glm::vec3 pos(Camera.Pos.x, Camera.Pos.y, Camera.Pos.z);
glm::vec3 at = glm::vec3(0.0, 0.0, -1.0) * glm::mat3(cam_matrix);
glm::vec3 up = glm::vec3(0.0, 1.0, 0.0) * glm::mat3(cam_matrix);
sound_man->set_listener(pos, at, up);
sound_man->set_listener(pos, glm::mat3(cam_matrix));
sound_man->update(dt);
}

View File

@@ -108,8 +108,7 @@ TWorld();
void OnCommandGet(DaneRozkaz *pRozkaz);
bool Update();
void TrainDelete(TDynamicObject *d = NULL);
TTrain const *
train() const { return Train; }
TTrain* train() { return Train; }
// switches between static and dynamic daylight calculation
void ToggleDaylight();

View File

@@ -17,5 +17,7 @@ cmake ../.. -T v140_xp ^
-DLIBSNDFILE_INCLUDE_DIR=%DEPS_DIR%/libsndfile/include ^
-DLIBSNDFILE_LIBRARY=%DEPS_DIR%/libsndfile/lib/win32/libsndfile-1.lib ^
-DLUAJIT_INCLUDE_DIR=%DEPS_DIR%/luajit/include ^
-DLUAJIT_LIBRARIES=%DEPS_DIR%/luajit/lib/win32/lua51.lib
-DLUAJIT_LIBRARIES=%DEPS_DIR%/luajit/lib/win32/lua51.lib ^
-Dlibserialport_INCLUDE_DIR=%DEPS_DIR%/libserialport/include ^
-Dlibserialport_LIBRARY=%DEPS_DIR%/libserialport/lib/win32/libserialport-0.lib
popd

23
builds/cmake_win64.bat Normal file
View File

@@ -0,0 +1,23 @@
if not exist deps_win call %~dp0download_windeps.bat
set DEPS_DIR="%cd%/deps_win"
if not exist build_win64 mkdir build_win64
pushd build_win64
cmake ../.. -A x64 ^
-DGLEW_INCLUDE_DIR=%DEPS_DIR%/glew-2.0.0/include ^
-DGLEW_LIBRARY=%DEPS_DIR%/glew-2.0.0/lib/Release/x64/glew32.lib ^
-DGLFW3_ROOT_PATH=%DEPS_DIR%/glfw-3.2.1.bin.WIN64 ^
-DGLUT_INCLUDE_DIR=%DEPS_DIR%/freeglut/include ^
-DGLUT_glut_LIBRARY=%DEPS_DIR%/freeglut/lib/x64/freeglut.lib ^
-DPNG_PNG_INCLUDE_DIR=%DEPS_DIR%/libpng/include ^
-DPNG_LIBRARY=%DEPS_DIR%/libpng/lib/win64/libpng16.lib ^
-DZLIB_INCLUDE_DIR=%DEPS_DIR%/zlib-1.2.11 ^
-DGLM_ROOT_DIR=%DEPS_DIR%/glm-0.9.8.4 ^
-DOPENAL_INCLUDE_DIR=%DEPS_DIR%/openal/include ^
-DOPENAL_LIBRARY=%DEPS_DIR%/openal/lib/win64/OpenAL32.lib ^
-DLIBSNDFILE_INCLUDE_DIR=%DEPS_DIR%/libsndfile/include ^
-DLIBSNDFILE_LIBRARY=%DEPS_DIR%/libsndfile/lib/win64/libsndfile-1.lib ^
-DLUAJIT_INCLUDE_DIR=%DEPS_DIR%/luajit/include ^
-DLUAJIT_LIBRARIES=%DEPS_DIR%/luajit/lib/win64/lua51.lib ^
-Dlibserialport_INCLUDE_DIR=%DEPS_DIR%/libserialport/include ^
-Dlibserialport_LIBRARY=%DEPS_DIR%/libserialport/lib/win64/libserialport-0.lib
popd

View File

@@ -0,0 +1,2 @@
powershell "$wc = New-Object System.Net.WebClient; $wc.DownloadFile(\"https://milek7.pl/.stuff/eu07exe/builddep4.zip\", \"%cd%\deps_win.zip\")"
powershell "$s = New-Object -ComObject shell.application; $z = $s.Namespace(\"%cd%\deps_win.zip\"); foreach ($i in $z.items()) { $s.Namespace(\"%cd%\").CopyHere($i) }"

View File

@@ -174,7 +174,9 @@ 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, std::uint16_t const Recipient,
command_data::desired_state_t state) const {
auto const &command = simulation::Commands_descriptions[ static_cast<std::size_t>( Command ) ];
if( ( command.target == command_target::vehicle )
@@ -191,7 +193,7 @@ command_relay::post( user_command const Command, std::uint64_t const Param1, std
Action,
Param1,
Param2,
Timer::GetDeltaTime() },
state, Timer::GetDeltaTime() },
static_cast<std::size_t>( command.target ) | Recipient );
/*
#ifdef _DEBUG

View File

@@ -169,6 +169,13 @@ struct command_data {
int action; // press, repeat or release
std::uint64_t param1;
std::uint64_t param2;
enum desired_state_t
{
TOGGLE,
OFF,
ON
};
desired_state_t desired_state;
double time_delta;
};
@@ -218,7 +225,9 @@ 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, std::uint16_t const Recipient,
command_data::desired_state_t state = command_data::TOGGLE ) const;
private:
// types
// members

View File

@@ -118,6 +118,10 @@ class vector3
return true;
};
operator glm::vec3() const
{
return glm::vec3(x, y, z);
}
private:
};
@@ -208,6 +212,11 @@ class matrix4x4
return true;
}
operator glm::mat4() const
{
return glm::make_mat4(e);
}
private:
scalar_t e[16];
};

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

View File

@@ -1345,19 +1345,6 @@ opengl_renderer::Render( TGround *Ground ) {
m_drawqueue.clear();
switch( m_renderpass.draw_mode ) {
case rendermode::color: {
// rednerowanie globalnych (nie za często?)
for( TGroundNode *node = Ground->srGlobal.nRenderHidden; node; node = node->nNext3 ) {
node->RenderHidden();
}
break;
}
default: {
break;
}
}
glm::vec3 const cameraposition { m_renderpass.camera.position() };
int const camerax = static_cast<int>( std::floor( cameraposition.x / 1000.0f ) + iNumRects / 2 );
int const cameraz = static_cast<int>( std::floor( cameraposition.z / 1000.0f ) + iNumRects / 2 );
@@ -1374,20 +1361,6 @@ opengl_renderer::Render( TGround *Ground ) {
for( int row = originz; row <= originz + segmentcount; ++row ) {
auto *cell = &Ground->Rects[ column ][ row ];
for( int subcellcolumn = 0; subcellcolumn < iNumSubRects; ++subcellcolumn ) {
for( int subcellrow = 0; subcellrow < iNumSubRects; ++subcellrow ) {
auto subcell = cell->FastGetSubRect( subcellcolumn, subcellrow );
if( subcell == nullptr ) { continue; }
// renderowanie obiektów aktywnych a niewidocznych
for( auto node = subcell->nRenderHidden; node; node = node->nNext3 ) {
node->RenderHidden();
}
// jeszcze dźwięki pojazdów by się przydały, również niewidocznych
subcell->RenderSounds();
}
}
if( m_renderpass.camera.visible( cell->m_area ) ) {
Render( cell );
}

View File

@@ -259,28 +259,26 @@ void sound_manager::update(float dt)
}
}
void sound_manager::set_listener(glm::vec3 const &p, glm::vec3 const &at, glm::vec3 const &up)
void sound_manager::set_listener(glm::vec3 const &p, glm::mat3 const &r)
{
pos = p;
alListenerfv(AL_POSITION, glm::value_ptr(p));
rot = r;
glm::vec3 at = glm::vec3(0.0, 0.0, -1.0) * r;
glm::vec3 up = glm::vec3(0.0, 1.0, 0.0) * r;
alListenerfv(AL_POSITION, glm::value_ptr(pos));
glm::vec3 ori[] = { at, up };
alListenerfv(AL_ORIENTATION, (ALfloat*)ori);
}
void sound_manager::set_listener(Math3D::vector3 const &p, Math3D::vector3 const &at, Math3D::vector3 const &up)
{
set_listener((glm::vec3)glm::make_vec3(&p.x), (glm::vec3)glm::make_vec3(&at.x), (glm::vec3)glm::make_vec3(&up.x));
}
sound::sound()
{
id = 0;
alGenSources(1, &id);
if (!id)
throw std::runtime_error("sound: cannot generate source");
alSourcei(id, AL_SOURCE_RELATIVE, AL_TRUE);
dist(5.0f * 3.82f);
spatial = false;
set_mode(global);
gain_off = 0.0f;
gain_mul = 1.0f;
pitch_off = 0.0f;
@@ -288,6 +286,18 @@ sound::sound()
dt_sum = 0.0f;
}
sound& sound::set_mode(mode_t m)
{
mode = m;
if (mode == global || mode == anchored)
alSourcei(id, AL_SOURCE_RELATIVE, AL_TRUE);
else if (mode == spatial)
alSourcei(id, AL_SOURCE_RELATIVE, AL_FALSE);
return *this;
}
simple_sound::simple_sound(sound_buffer *buf) : sound::sound()
{
looping = false;
@@ -308,22 +318,25 @@ simple_sound::~simple_sound()
buffer->unref();
}
sound& sound::position(glm::vec3 const &p)
sound& sound::position(glm::vec3 p)
{
if (!spatial)
if (mode == global)
{
alSourcei(id, AL_SOURCE_RELATIVE, AL_FALSE);
spatial = true;
set_mode(spatial);
last_pos = p;
}
if (p != pos)
if (p != pos || mode == anchored)
{
pos = p;
pos_dirty = true;
if (mode == anchored)
p = (p - sound_man->pos) * glm::inverse(sound_man->rot);
alSourcefv(id, AL_POSITION, glm::value_ptr(p));
}
return *this;
}
@@ -343,7 +356,7 @@ sound& sound::dist(float dist)
void simple_sound::play()
{
if (playing || (spatial && glm::distance(pos, sound_man->pos) > max_dist))
if (playing || (mode != global && glm::distance(pos, sound_man->pos) > max_dist))
return;
alSourcePlay(id);
@@ -361,9 +374,9 @@ void simple_sound::stop()
void sound::update(float dt)
{
if (spatial)
if (mode == spatial)
dt_sum += dt;
if (spatial && pos_dirty)
if (mode == spatial && pos_dirty)
{
glm::vec3 velocity = (pos - last_pos) / dt_sum; // m/s
alSourcefv(id, AL_VELOCITY, glm::value_ptr(velocity));
@@ -383,7 +396,7 @@ void simple_sound::update(float dt)
alGetSourcei(id, AL_SOURCE_STATE, &v);
if (v != AL_PLAYING)
playing = false;
else if (spatial && glm::distance(pos, sound_man->pos) > max_dist)
else if (mode != global && glm::distance(pos, sound_man->pos) > max_dist)
stop();
}
}
@@ -464,7 +477,7 @@ void complex_sound::play()
if (cs != state::post)
return;
if (spatial && glm::distance(pos, sound_man->pos) > max_dist)
if (mode != global && glm::distance(pos, sound_man->pos) > max_dist)
return;
alSourceRewind(id);
@@ -554,7 +567,7 @@ void complex_sound::update(float dt)
}
if (cs == state::main)
if (spatial && glm::distance(pos, sound_man->pos) > max_dist)
if (mode != global && glm::distance(pos, sound_man->pos) > max_dist)
{
shut_by_dist = true;
stop();

17
sound.h
View File

@@ -45,9 +45,17 @@ class sound
glm::vec3 last_pos;
float dt_sum;
public:
enum mode_t
{
global,
spatial,
anchored
};
protected:
float max_dist;
bool spatial;
mode_t mode;
glm::vec3 pos;
int samplerate;
@@ -68,12 +76,13 @@ public:
virtual void stop() = 0;
virtual void update(float dt);
sound& set_mode(mode_t);
sound& dist(float);
sound& gain(float);
sound& pitch(float);
virtual sound& loop(bool loop = true) = 0;
sound& position(glm::vec3 const &);
sound& position(glm::vec3);
sound& position(Math3D::vector3 const &);
};
@@ -155,6 +164,7 @@ class sound_manager
public:
glm::vec3 pos, last_pos;
glm::mat3 rot;
sound_manager();
~sound_manager();
@@ -166,8 +176,7 @@ public:
void destroy_sound(sound**);
void update(float dt);
void set_listener(glm::vec3 const &pos, glm::vec3 const &at, glm::vec3 const &up);
void set_listener(Math3D::vector3 const &pos, Math3D::vector3 const &at, Math3D::vector3 const &up);
void set_listener(glm::vec3 const &pos, glm::mat3 const &rot);
};
extern std::unique_ptr<sound_manager> sound_man;

173
uart.cpp Normal file
View File

@@ -0,0 +1,173 @@
#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");
if (sp_set_baudrate(port, conf.baud) != SP_OK)
throw std::runtime_error("uart: cannot set baudrate");
if (sp_set_flowcontrol(port, SP_FLOWCONTROL_NONE) != SP_OK)
throw std::runtime_error("uart: cannot set flowcontrol");
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()
{
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<float>(now - last_update).count() < conf.updatetime)
return;
last_update = now;
TTrain *t = Global::pWorld->train();
sp_return ret;
if (sp_input_waiting(port) >= 16)
{
std::array<uint8_t, 16> 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");
sp_drain(port);
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 = (bool)(buffer[byte] & (1 << bit));
bool repeat = (type == impulse_r ||
type == impulse_r_off ||
type == impulse_r_on);
bool changed = (state != (bool)(old_packet[byte] & (1 << bit)));
if (!changed && !(repeat && state))
continue;
int action;
command_data::desired_state_t desired_state;
if (type == toggle)
{
action = GLFW_PRESS;
desired_state = state ? command_data::ON : command_data::OFF;
}
else if (type == impulse_r_on)
{
action = state ? (changed ? GLFW_PRESS : GLFW_REPEAT) : GLFW_RELEASE;
desired_state = command_data::ON;
}
else if (type == impulse_r_off)
{
action = state ? (changed ? GLFW_PRESS : GLFW_REPEAT) : GLFW_RELEASE;
desired_state = command_data::OFF;
}
else if (type == impulse || type == impulse_r)
{
action = state ? (changed ? GLFW_PRESS : GLFW_REPEAT) : GLFW_RELEASE;
desired_state = command_data::TOGGLE;
}
relay.post(std::get<1>(entry), 0, 0, action, 0, desired_state);
}
int mainctrl = buffer[6];
int scndctrl = buffer[7];
float trainbrake = (float)(((uint16_t)buffer[8] | ((uint16_t)buffer[9] << 8)) - conf.mainbrakemin) / (conf.mainbrakemax - conf.mainbrakemin);
float localbrake = (float)(((uint16_t)buffer[10] | ((uint16_t)buffer[11] << 8)) - conf.mainbrakemin) / (conf.localbrakemax - conf.localbrakemin);
t->set_mainctrl(mainctrl);
t->set_scndctrl(scndctrl);
t->set_trainbrake(trainbrake);
t->set_localbrake(localbrake);
old_packet = buffer;
}
if (!data_pending && sp_output_waiting(port) == 0)
{
// TODO: ugly! move it into structure like input_bits
uint8_t buzzer = (uint8_t)t->get_alarm();
uint8_t tacho = (uint8_t)t->get_tacho();
uint16_t tank_press = (uint16_t)std::min(conf.tankuart, t->get_tank_pressure() / conf.tankmax * conf.tankuart);
uint16_t pipe_press = (uint16_t)std::min(conf.pipeuart, t->get_pipe_pressure() / conf.pipemax * conf.pipeuart);
uint16_t brake_press = (uint16_t)std::min(conf.brakeuart, t->get_brake_pressure() / conf.brakemax * conf.brakeuart);
uint16_t hv_voltage = (uint16_t)std::min(conf.hvuart, t->get_hv_voltage() / conf.hvmax * conf.hvuart);
auto current = t->get_current();
uint16_t current1 = (uint16_t)std::min(conf.currentuart, current[0]) / conf.currentmax * conf.currentuart;
uint16_t current2 = (uint16_t)std::min(conf.currentuart, current[1]) / conf.currentmax * conf.currentuart;
uint16_t current3 = (uint16_t)std::min(conf.currentuart, current[2]) / conf.currentmax * conf.currentuart;
std::array<uint8_t, 31> buffer =
{
0, 0, //byte 0-1
tacho, //byte 2
0, 0, 0, 0, 0, 0, //byte 3-8
SPLIT_INT16(brake_press), //byte 9-10
SPLIT_INT16(pipe_press), //byte 11-12
SPLIT_INT16(tank_press), //byte 13-14
SPLIT_INT16(hv_voltage), //byte 15-16
SPLIT_INT16(current1), //byte 17-18
SPLIT_INT16(current2), //byte 19-20
SPLIT_INT16(current3), //byte 21-22
0, 0, 0, 0, 0, 0, 0, 0 //byte 23-30
};
buffer[4] |= t->btLampkaOpory.b() << 1;
buffer[4] |= t->btLampkaWysRozr.b() << 2;
buffer[6] |= t->btLampkaOgrzewanieSkladu.b() << 0;
buffer[6] |= t->btLampkaOpory.b() << 1;
buffer[6] |= t->btLampkaPoslizg.b() << 2;
buffer[6] |= t->btLampkaCzuwaka.b() << 6;
buffer[6] |= t->btLampkaSHP.b() << 7;
buffer[7] |= t->btLampkaStyczn.b() << 0;
buffer[7] |= t->btLampkaNadmPrzetw.b() << 2;
buffer[7] |= t->btLampkaNadmSil.b() << 4;
buffer[7] |= t->btLampkaWylSzybki.b() << 5;
buffer[7] |= t->btLampkaNadmSpr.b() << 6;
buffer[8] |= buzzer << 7;
sp_flush(port, SP_BUF_INPUT); // flush input buffer in preparation for reply packet
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;
}
}

58
uart.h Normal file
View File

@@ -0,0 +1,58 @@
#pragma once
#include <libserialport.h>
#include "command.h"
#include "Globals.h"
class uart_input
{
enum input_type_t
{
toggle,
impulse,
impulse_r,
impulse_r_on,
impulse_r_off
};
std::array<std::tuple<size_t, user_command, input_type_t>, 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)
};
sp_port *port = nullptr;
command_relay relay;
std::array<uint8_t, 16> old_packet;
std::chrono::time_point<std::chrono::high_resolution_clock> last_update;
Global::uart_conf_t conf;
bool data_pending = false;
public:
uart_input();
~uart_input();
void poll();
};

View File

@@ -1,5 +1,5 @@
#pragma once
#define VERSION_MAJOR 17
#define VERSION_MINOR 913
#define VERSION_MINOR 914
#define VERSION_REVISION 0