From d9235c0b2c76552b5bc844cb92829691bc1ea3ab Mon Sep 17 00:00:00 2001 From: milek7 Date: Wed, 13 Sep 2017 21:41:01 +0200 Subject: [PATCH 1/7] crash fix --- Driver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Driver.cpp b/Driver.cpp index 9bc178a9..d14beaba 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -1425,7 +1425,7 @@ void TController::TablePurger() void TController::TableSort() { TSpeedPos sp_temp = TSpeedPos(); // uzywany do przenoszenia - for (std::size_t i = 0; i < (iLast - 1) && iLast > 0; ++i) + for (std::size_t i = 0; i < (iLast - 1) && iLast > 1 && 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 From 2de1de4999a2dd6ce4d14cc1ffaaa3aebe349b4e Mon Sep 17 00:00:00 2001 From: milek7 Date: Wed, 13 Sep 2017 22:37:27 +0200 Subject: [PATCH 2/7] crash fix --- Driver.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Driver.h b/Driver.h index 40190aa2..9d0ec8f8 100644 --- a/Driver.h +++ b/Driver.h @@ -174,7 +174,7 @@ static const int BrakeAccTableSize = 20; class TController { private: // obsługa tabelki prędkości (musi mieć możliwość odhaczania stacji w rozkładzie) - size_t iLast{ 0 }; // ostatnia wypełniona pozycja w tabeli sSpeedTable; double fLastVel = 0.0; // prędkość na poprzednio sprawdzonym torze From 6c69a5b8f1b13cc516209abb5ce8d8624df1f5c8 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Fri, 15 Sep 2017 04:14:12 +0200 Subject: [PATCH 3/7] build 170914. fix for car braking, sound and event updates refactored out of gfx renderer --- Driver.cpp | 78 +++++++++++++++++++++++++++++++++++++--------------- Driver.h | 10 +++---- Ground.cpp | 39 ++++++++++++++++++++++++++ Ground.h | 3 +- World.cpp | 1 + renderer.cpp | 27 ------------------ version.h | 2 +- 7 files changed, 104 insertions(+), 56 deletions(-) diff --git a/Driver.cpp b/Driver.cpp index 48f71618..f6e6e728 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -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]; @@ -4568,24 +4572,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 ) ); + } } } } @@ -4593,8 +4625,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 ); + } diff --git a/Driver.h b/Driver.h index c552dfa8..17fc2f72 100644 --- a/Driver.h +++ b/Driver.h @@ -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 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( std::floor( Global::pCameraPosition.x / 1000.0 ) + iNumRects / 2 ); + int const cameraz = static_cast( std::floor( Global::pCameraPosition.z / 1000.0 ) + iNumRects / 2 ); + int const segmentcount = 2 * static_cast( 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 diff --git a/Ground.h b/Ground.h index a35f69f5..b79ef633 100644 --- a/Ground.h +++ b/Ground.h @@ -227,7 +227,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 : @@ -287,6 +287,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(); diff --git a/World.cpp b/World.cpp index 658205e1..2559d914 100644 --- a/World.cpp +++ b/World.cpp @@ -1047,6 +1047,7 @@ bool TWorld::Update() Ground.CheckQuery(); + Ground.Update_Hidden(); Ground.Update_Lights(); // render time routines follow: diff --git a/renderer.cpp b/renderer.cpp index 3ca7eadc..bef13681 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -1344,19 +1344,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( std::floor( cameraposition.x / 1000.0f ) + iNumRects / 2 ); int const cameraz = static_cast( std::floor( cameraposition.z / 1000.0f ) + iNumRects / 2 ); @@ -1373,20 +1360,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 ); } diff --git a/version.h b/version.h index b11e1ac6..c063cca4 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 17 -#define VERSION_MINOR 913 +#define VERSION_MINOR 914 #define VERSION_REVISION 0 From e5ad6be8652fa49285e8ae927c32cb1814c2b058 Mon Sep 17 00:00:00 2001 From: milek7 Date: Sat, 16 Sep 2017 20:35:43 +0200 Subject: [PATCH 4/7] cabin sound positioning --- Button.cpp | 1 + CMakeLists.txt | 2 +- Float3d.h | 5 +++++ Gauge.cpp | 28 +++++++++++++++++++++----- Gauge.h | 2 +- World.cpp | 5 +---- World.h | 3 +-- dumb3d.h | 9 +++++++++ sound.cpp | 53 +++++++++++++++++++++++++++++++------------------- sound.h | 17 ++++++++++++---- 10 files changed, 88 insertions(+), 37 deletions(-) diff --git a/Button.cpp b/Button.cpp index 0232af5c..aefcc35a 100644 --- a/Button.cpp +++ b/Button.cpp @@ -156,5 +156,6 @@ TButton::play( sound* Sound ) { Sound->stop(); Sound->play(); + return; } diff --git a/CMakeLists.txt b/CMakeLists.txt index 5ecb7fbb..151cc2d4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -131,5 +131,5 @@ include_directories(${LUAJIT_INCLUDE_DIR}) target_link_libraries(${PROJECT_NAME} ${LUAJIT_LIBRARIES}) if (UNIX) - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined") + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined -g") endif() diff --git a/Float3d.h b/Float3d.h index 0216b000..7efe6ba3 100644 --- a/Float3d.h +++ b/Float3d.h @@ -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) diff --git a/Gauge.cpp b/Gauge.cpp index 0b9c427d..44d2b801 100644 --- a/Gauge.cpp +++ b/Gauge.cpp @@ -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,30 @@ void TGauge::UpdateValue() } }; -void -TGauge::play( sound *Sound ) { +extern TWorld World; - if( Sound == nullptr ) { return; } +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; } - -//--------------------------------------------------------------------------- diff --git a/Gauge.h b/Gauge.h index 02ed3ee0..8dd61959 100644 --- a/Gauge.h +++ b/Gauge.h @@ -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 }; //--------------------------------------------------------------------------- diff --git a/World.cpp b/World.cpp index 6a1e93d5..015db2ae 100644 --- a/World.cpp +++ b/World.cpp @@ -1060,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); } diff --git a/World.h b/World.h index 553c9905..b471dfdc 100644 --- a/World.h +++ b/World.h @@ -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(); diff --git a/dumb3d.h b/dumb3d.h index 176f8c87..1bb4a77d 100644 --- a/dumb3d.h +++ b/dumb3d.h @@ -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]; }; diff --git a/sound.cpp b/sound.cpp index f587239f..95f8c26b 100644 --- a/sound.cpp +++ b/sound.cpp @@ -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(); diff --git a/sound.h b/sound.h index 306dcb07..82f82556 100644 --- a/sound.h +++ b/sound.h @@ -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_man; From 7f97532bba503a3e5252bb979f59be6bd42a107b Mon Sep 17 00:00:00 2001 From: milek7 Date: Sat, 16 Sep 2017 22:07:22 +0200 Subject: [PATCH 5/7] crash fixes --- Gauge.cpp | 3 +++ Model3d.cpp | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Gauge.cpp b/Gauge.cpp index 44d2b801..74f255e0 100644 --- a/Gauge.cpp +++ b/Gauge.cpp @@ -317,6 +317,9 @@ void TGauge::UpdateValue() } }; +// todo: ugly approach to getting train translation +// maybe cache gauge position + extern TWorld World; void TGauge::play( sound *Sound ) diff --git a/Model3d.cpp b/Model3d.cpp index 60d5b6f0..a16c7512 100644 --- a/Model3d.cpp +++ b/Model3d.cpp @@ -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) From 8fa81a1c12233e53e9da6b2b895c1536340b4d17 Mon Sep 17 00:00:00 2001 From: milek7 Date: Sun, 17 Sep 2017 15:21:42 +0200 Subject: [PATCH 6/7] fix python screens on linux --- PyInt.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/PyInt.cpp b/PyInt.cpp index c73fdeab..def8b8ef 100644 --- a/PyInt.cpp +++ b/PyInt.cpp @@ -479,6 +479,7 @@ void TPythonScreens::update() void TPythonScreens::setLookupPath(std::string const &path) { _lookupPath = path; + std::replace(_lookupPath.begin(), _lookupPath.end(), '\\', '/'); } TPythonScreens::TPythonScreens() From f2a57dda638a14f2d41dd634bbe9ef3ebc9a1aac Mon Sep 17 00:00:00 2001 From: milek7 Date: Thu, 21 Sep 2017 19:33:48 +0200 Subject: [PATCH 7/7] uart experiments windows build fix log uart write error uart changes uart changes uart changes uart changes uart changes uart works uart changes verbose uart log uart changes uart changes uart logging uart logging uart changes changes uart changes --- Button.h | 1 + CMakeLists.txt | 8 +- CMake_modules/Findlibserialport.cmake | 9 + Console.cpp | 127 ----- Console/MWD.cpp | 763 -------------------------- Console/MWD.h | 98 ---- EU07.cpp | 9 +- Globals.cpp | 142 +---- Globals.h | 42 +- Train.cpp | 255 ++++++--- Train.h | 14 + builds/cmake_win32.bat | 4 +- builds/cmake_win64.bat | 4 +- builds/download_windeps.bat | 2 +- command.cpp | 6 +- command.h | 11 +- uart.cpp | 173 ++++++ uart.h | 58 ++ 18 files changed, 537 insertions(+), 1189 deletions(-) create mode 100644 CMake_modules/Findlibserialport.cmake delete mode 100644 Console/MWD.cpp delete mode 100644 Console/MWD.h create mode 100644 uart.cpp create mode 100644 uart.h diff --git a/Button.h b/Button.h index c468d7ff..3080aff0 100644 --- a/Button.h +++ b/Button.h @@ -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); diff --git a/CMakeLists.txt b/CMakeLists.txt index 151cc2d4..77d13adc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.0) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/CMake_modules/") project("eu07++ng") +set(CMAKE_CXX_STANDARD 14) include_directories("." "Console" "McZapkie") file(GLOB HEADERS "*.h" "Console/*.h" "McZapkie/*.h") @@ -66,11 +67,12 @@ set(SOURCES "translation.cpp" "material.cpp" "lua.cpp" +"uart.cpp" ) if (WIN32) add_definitions(-DHAVE_ROUND) # 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") endif() if (${CMAKE_CXX_COMPILER_ID} STREQUAL MSVC) @@ -130,6 +132,10 @@ 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 -g") endif() diff --git a/CMake_modules/Findlibserialport.cmake b/CMake_modules/Findlibserialport.cmake new file mode 100644 index 00000000..08548e8a --- /dev/null +++ b/CMake_modules/Findlibserialport.cmake @@ -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() + diff --git a/Console.cpp b/Console.cpp index 0f8775c5..886f2656 100644 --- a/Console.cpp +++ b/Console.cpp @@ -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 }; diff --git a/Console/MWD.cpp b/Console/MWD.cpp deleted file mode 100644 index 67b63bdd..00000000 --- a/Console/MWD.cpp +++ /dev/null @@ -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 - -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 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; -} diff --git a/Console/MWD.h b/Console/MWD.h deleted file mode 100644 index 93f2dab4..00000000 --- a/Console/MWD.h +++ /dev/null @@ -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 -*/ diff --git a/EU07.cpp b/EU07.cpp index be631e0f..ce4cd222 100644 --- a/EU07.cpp +++ b/EU07.cpp @@ -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") @@ -50,7 +51,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; } void screenshot_save_thread( char *img ) @@ -350,9 +351,13 @@ int main(int argc, char *argv[]) sound_man = std::make_unique(); + Global::pWorld = &World; + input::Keyboard.init(); input::Mouse.init(); input::Gamepad.init(); + if (Global::uart_conf.enable) + input::uart = std::make_unique(); if( false == World.Init( window ) ) { ErrorLog( "Simulation setup failed" ); @@ -393,6 +398,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(); } } diff --git a/Globals.cpp b/Globals.cpp index a8de9723..9621a627 100644 --- a/Globals.cpp +++ b/Globals.cpp @@ -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 diff --git a/Globals.h b/Globals.h index 92013019..8848ffc6 100644 --- a/Globals.h +++ b/Globals.h @@ -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 diff --git a/Train.cpp b/Train.cpp index 585466a5..9800f0bc 100644 --- a/Train.cpp +++ b/Train.cpp @@ -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( 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( 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( @@ -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 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; +} diff --git a/Train.h b/Train.h index dc05a1e8..194937d6 100644 --- a/Train.h +++ b/Train.h @@ -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 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); }; //--------------------------------------------------------------------------- diff --git a/builds/cmake_win32.bat b/builds/cmake_win32.bat index 05d0c7b62..fdefe6c4 100644 --- a/builds/cmake_win32.bat +++ b/builds/cmake_win32.bat @@ -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 \ No newline at end of file diff --git a/builds/cmake_win64.bat b/builds/cmake_win64.bat index 4294b1a2..96d2dc6b 100644 --- a/builds/cmake_win64.bat +++ b/builds/cmake_win64.bat @@ -17,5 +17,7 @@ cmake ../.. -A x64 ^ -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 +-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 \ No newline at end of file diff --git a/builds/download_windeps.bat b/builds/download_windeps.bat index ee15b44c..24fd4428 100644 --- a/builds/download_windeps.bat +++ b/builds/download_windeps.bat @@ -1,2 +1,2 @@ -powershell "$wc = New-Object System.Net.WebClient; $wc.DownloadFile(\"https://milek7.pl/.stuff/eu07exe/builddep3.zip\", \"%cd%\deps_win.zip\")" +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) }" diff --git a/command.cpp b/command.cpp index 06e74454..91455a31 100644 --- a/command.cpp +++ b/command.cpp @@ -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( 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( command.target ) | Recipient ); /* #ifdef _DEBUG diff --git a/command.h b/command.h index a06509e5..9b4e23cf 100644 --- a/command.h +++ b/command.h @@ -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 diff --git a/uart.cpp b/uart.cpp new file mode 100644 index 00000000..e3c70c23 --- /dev/null +++ b/uart.cpp @@ -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(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 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 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; + } +} diff --git a/uart.h b/uart.h new file mode 100644 index 00000000..e58faff4 --- /dev/null +++ b/uart.h @@ -0,0 +1,58 @@ +#pragma once +#include +#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, 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 old_packet; + std::chrono::time_point last_update; + Global::uart_conf_t conf; + bool data_pending = false; + +public: + uart_input(); + ~uart_input(); + void poll(); +};