From 54687bfe3b2d9cada26f867a6d8127543a56a02e Mon Sep 17 00:00:00 2001 From: Bruno Crivelari Sanches Date: Mon, 3 Feb 2025 15:54:49 -0300 Subject: [PATCH] Signal system on scripts --- data/EFMR/Helix.decoders.json | 4 +- data/EFMR/scripts/autoexec.lua | 2 + data/EFMR/scripts/tc_signal_d06.lua | 300 ++++++++++++++++++ src/Broker/main.cpp | 14 +- src/BrokerLib/dcc/DccLiteService_script.cpp | 58 +++- src/BrokerLib/dcc/NetworkDevice.cpp | 4 +- src/BrokerLib/dcc/SignalDecoder.cpp | 20 +- src/BrokerLib/dcc/SignalDecoder.h | 8 +- .../dispatcher/DispatcherService.cpp | 17 + src/BrokerLib/terminal/TerminalClient.cpp | 4 +- src/UnitTest/SignalDecoderTest.cpp | 8 +- todo.txt | 2 - 12 files changed, 414 insertions(+), 27 deletions(-) create mode 100644 data/EFMR/scripts/tc_signal_d06.lua diff --git a/data/EFMR/Helix.decoders.json b/data/EFMR/Helix.decoders.json index 66c53319..509d800c 100644 --- a/data/EFMR/Helix.decoders.json +++ b/data/EFMR/Helix.decoders.json @@ -142,7 +142,7 @@ "address": "1350", "pin": 65, "inverted": true, - "ignoreSavedState": false + "ignoreSavedState": true }, { "name": "TC_SIG_6D_HG", @@ -150,7 +150,7 @@ "address": "1351", "pin": 64, "inverted": true, - "ignoreSavedState": false + "ignoreSavedState": true }, { "name": "INV_HELIX_TC_SOL", diff --git a/data/EFMR/scripts/autoexec.lua b/data/EFMR/scripts/autoexec.lua index 810f6351..ee2764cd 100644 --- a/data/EFMR/scripts/autoexec.lua +++ b/data/EFMR/scripts/autoexec.lua @@ -10,5 +10,7 @@ run_script("st_panel_exitc.lua") run_script("tc_02.lua") +run_script("tc_signal_d06.lua") + log_info("Autoexec finished") diff --git a/data/EFMR/scripts/tc_signal_d06.lua b/data/EFMR/scripts/tc_signal_d06.lua new file mode 100644 index 00000000..a5d7dc26 --- /dev/null +++ b/data/EFMR/scripts/tc_signal_d06.lua @@ -0,0 +1,300 @@ +--[[ + +The Signal D06 has a diagram like this: + + HLX_T03 HLX_T02 HLX_T01 +--------------O----|-------O-----|----------------------------------- -> Staging Exit - Stop + |-O \ HLX_DTC02 HLX_DTC01 / \ + D06 \ / \----------- -> Staging Entrance - Clear + \ ____________________/ + | / + |/ HLX_T04 HLX_T08 + | /---> Coronel FulgĂȘncio (down line - internal - Stop) + | HLX_T07 / + |\ HLX_T05 ---------------------------> Coronel FulgĂȘncio (up line - external - RESTRICTED) + | \ / + | \--------------------/ + | + | +sl_bp_main_d04 O / + | / + |/ HLX_T06 + O sl_bp_main_s03 + | + O sl_bp_main_s02 + | + O sl_bp_main_s01 / sl_bp_main_d01 + | + v Soledade - Aproach + +]]-- + +log_info("TC_SIGNAL_D06 Initializing") + +-- signal +local signal_d06 = dcclite.dcc0.TC_SIG_6D + +-- turnouts +local hlx_t08 = dcclite.dcc0.HLX_T08 +local hlx_t07 = dcclite.dcc0.HLX_T07 +local hlx_t06 = dcclite.dcc0.HLX_T06 +local hlx_t05 = dcclite.dcc0.HLX_T05 +local hlx_t04 = dcclite.dcc0.HLX_T04 +local hlx_t03 = dcclite.dcc0.HLX_T03 +local hlx_t02 = dcclite.dcc0.HLX_T02 +local hlx_t01 = dcclite.dcc0.HLX_T01 + +-- sensors for helix route +local hlx_sensor_dtc02 = dcclite.dcc0.HLX_DTC02 +local hlx_sensor_dtc01 = dcclite.dcc0.HLX_DTC01 + +-- soledade branch sections +-- local sl_bp_main_s03 = dcclite.dcc0.sl_bp_main_s03 +-- local sl_bp_main_s02 = dcclite.dcc0.sl_bp_main_s02 +-- local sl_bp_main_s01 = dcclite.dcc0.sl_bp_main_s01 + +-- soledade branch sensors +local sl_bp_main_d01 = dcclite.dcc0.SL_BP_MAIN_D01 + +SIGNAL_STATES = { + automatic = 0, + helix_path_clear = 1, + helix_path_busy = 2, + helix_path_exiting = 4, + soledade_path_clear = 8, + soledade_path_busy = 16, + soledade_path_exiting = 32 +} + +local signal_state = SIGNAL_STATES.automatic + +function set_stop_aspect(reason) + log_info(reason) + + signal_d06:set_aspect(SignalAspects.Stop) + signal_state = SIGNAL_STATES.automatic +end + +function set_helix_down_aspect() + log_info("TC_SIGNAL_D06 Route to staging CLEAR") + signal_d06:set_aspect(SignalAspects.Clear) + + signal_state = SIGNAL_STATES.helix_path_clear +end + +function set_soledade_branch_aspect() + log_info("TC_SIGNAL_D06 soledade path CLEAR") + signal_d06:set_aspect(SignalAspects.Aproach) + signal_state = SIGNAL_STATES.soledade_path_clear +end + +function on_train_entered_helix_down(device) + + log_info("TC_SIGNAL_D06 on_train_entered_helix_down") + + -- sensor turned off? We do not care... + if not device.active then + log_trace("TC_SIGNAL_D06 on_train_entered_helix_down sensor is off") + + return + end + + -- is train heading to soledade? + if signal_state == SIGNAL_STATES.soledade_path_clear then + + -- now wait for train to reach end sensor + signal_state = SIGNAL_STATES.soledade_path_busy + + signal_d06:set_aspect(SignalAspects.Stop) + + elseif signal_state == SIGNAL_STATES.helix_path_clear then + log_trace("TC_SIGNAL_D06 on_train_entered_helix_down sensor is on, now path is busy, signal is STOP") + + -- now wait for train to reach end sensor + signal_state = SIGNAL_STATES.helix_path_busy + + signal_d06:set_aspect(SignalAspects.Stop) + end +end + +function on_helix_exit_sensor(sensor) + + log_trace("TC_SIGNAL_D06 on_helix_exit_sensor sensor") + + if (signal_state == SIGNAL_STATES.helix_path_busy) and sensor.active then + log_trace("TC_SIGNAL_D06 on_helix_exit_sensor sensor ACTIVE") + + signal_state = SIGNAL_STATES.helix_path_exiting + + elseif (signal_state == SIGNAL_STATES.helix_path_exiting) and sensor.inactive then + log_trace("TC_SIGNAL_D06 on_helix_exit_sensor INACTIVE - resetting") + + --reset signal + signal_state = SIGNAL_STATES.automatic + + -- check state + on_device_change(sensor) + end +end + +function on_soledade_branch_exit_sensor(sensor) + if (signal_state == SIGNAL_STATES.soledade_path_busy) and sensor.active then + signal_state = SIGNAL_STATES.soledade_path_exiting + elseif (signal_state == SIGNAL_STATES.soledade_path_exiting) and sensor.inactive then + + --reset signal + signal_state = SIGNAL_STATES.automatic + + -- check state + on_device_change(sensor) + end +end + +function on_device_change(device) + + log_info("TC_SIGNAL_D06 on_device_change") + + -- Are we going to Soledade or up the helix? + if hlx_t03.thrown then + + log_info("TC_SIGNAL_D06 hlx_t03 thrown") + + -- Is path blocked? + if hlx_t04.thrown then + set_stop_aspect("TC_SIGNAL_D06 hlx_t04 thrown - STOP") + + return + end + + -- Are we going up the helix? + if hlx_t05.thrown then + log_info("TC_SIGNAL_D06 hlx_t05 thrown") + + -- Is path blocked? + if hlx_t07.closed then + set_stop_aspect("TC_SIGNAL_D06 hlx_t07 closed - STOP") + + return + end + + -- Is route set to down line (internal)? + if hlx_t08.thrown then + set_stop_aspect("TC_SIGNAL_D06 hlx_t08 thrown - STOP") + + return + end + + -- Going up... give a restricted, as line is incomplete + log_info("TC_SIGNAL_D06 hlx_t07 thrown - RESTRICTED") + signal_d06:set_aspect(SignalAspects.Restricted) + return + end + + -- ok, we are heading towards to Soledade + + -- Is path blocked? + if hlx_t06.thrown then + set_stop_aspect("TC_SIGNAL_D06 hlx_t06 thrown - STOP") + + return + end + + -- if heading down to SOLEDADE, ignore sensors... + if (signal_state == SIGNAL_STATES.soledade_path_busy) or (signal_state == SIGNAL_STATES.soledade_path_exiting) then + -- do not modify signal, wait for sensors + log_trace("TC_SIGNAL_D06 path is busy by soledade, waiting sensors: " .. signal_state) + return + end + + --[[ + if sl_bp_main_s03.active then + set_stop_aspect("TC_SIGNAL_D06 sl_bp_main_s03 IN USE - STOP") + + return + end + + if sl_bp_main_s02.active then + set_stop_aspect("TC_SIGNAL_D06 sl_bp_main_s02 IN USE - STOP") + + return + end + + if sl_bp_main_s01.active then + set_stop_aspect("TC_SIGNAL_D06 sl_bp_main_s01 IN USE - STOP") + + return + end + ]]-- + + -- ok, soledade path is clear + set_soledade_branch_aspect() + return + + end + + -- We are heading down the helix + + -- is path blocked? + if hlx_t02.thrown then + set_stop_aspect("TC_SIGNAL_D06 hlx_t02 open - stop") + + return + end + + -- is path toward helix exit? + if hlx_t01.closed then + set_stop_aspect("TC_SIGNAL_D06 hlx_t01 closed - stop") + + return + end + + -- path is down to helix entrance, ok, right path... but + + -- if heading down the helix, ignore sensors... + if (signal_state == SIGNAL_STATES.helix_path_busy) or (signal_state == SIGNAL_STATES.helix_path_exiting) then + -- do not modify signal, wait for sensors + log_trace("TC_SIGNAL_D06 path is busy by helix, waiting sensors: " .. signal_state) + return + end + + -- is block ocupied? + if hlx_sensor_dtc02.active then + set_stop_aspect("TC_SIGNAL_D06 DTC02 ACTIVE - stop") + + return + end + + -- is block ocupied? + if hlx_sensor_dtc01.active then + set_stop_aspect("TC_SIGNAL_D06 DTC01 ACTIVE - stop") + + return + end + + -- Finally path clear and no blocks ocupied... + set_helix_down_aspect() +end + +signal_d06:set_aspect(SignalAspects.Stop) + +hlx_t08:on_state_change(on_device_change) +hlx_t07:on_state_change(on_device_change) +hlx_t06:on_state_change(on_device_change) +hlx_t05:on_state_change(on_device_change) +hlx_t04:on_state_change(on_device_change) +hlx_t03:on_state_change(on_device_change) +hlx_t02:on_state_change(on_device_change) +hlx_t01:on_state_change(on_device_change) + +hlx_sensor_dtc02:on_state_change(on_device_change) +hlx_sensor_dtc01:on_state_change(on_device_change) + +hlx_sensor_dtc02:on_state_change(on_train_entered_helix_down) +hlx_sensor_dtc01:on_state_change(on_helix_exit_sensor) + +sl_bp_main_d01:on_state_change(on_soledade_branch_exit_sensor) + +-- set initial state +on_device_change(signal_d06) + +log_info("TC_SIGNAL_D06 - init OK" .. signal_state) \ No newline at end of file diff --git a/src/Broker/main.cpp b/src/Broker/main.cpp index fd286cb0..f9c1a64e 100644 --- a/src/Broker/main.cpp +++ b/src/Broker/main.cpp @@ -55,13 +55,20 @@ QuitEvent::NullEventTarget QuitEvent::g_clTarget; static bool ConsoleCtrlHandler(dcclite::ConsoleEvent event) { - g_fExitRequested.test_and_set(std::memory_order_relaxed); + g_fExitRequested.test_and_set(std::memory_order_relaxed); //wake up main thread if it is sitting waiting for events... dcclite::broker::EventHub::PostEvent(); dcclite::Log::Info("[Main] CTRL+C detected, exiting..."); + //give some time for main thread to finish up... so it can do the cleanup + using namespace std::chrono_literals; + + //if we return befor the main thread, it may not finish cleaning up... + while(g_fExitRequested.test()) + std::this_thread::sleep_for(1000ms); + return true; } @@ -104,8 +111,11 @@ int main(int argc, char **argv) { dcclite::LogGetDefault()->critical("caught {}", ex.what()); } - + dcclite::Log::Info("[Main] Bye"); + //notify console handler that we are done + g_fExitRequested.clear(std::memory_order_relaxed); + return 0; } diff --git a/src/BrokerLib/dcc/DccLiteService_script.cpp b/src/BrokerLib/dcc/DccLiteService_script.cpp index da3ac42a..842e89a7 100644 --- a/src/BrokerLib/dcc/DccLiteService_script.cpp +++ b/src/BrokerLib/dcc/DccLiteService_script.cpp @@ -15,7 +15,9 @@ #include #include +#include "NmraUtil.h" #include "RemoteDecoder.h" +#include "SignalDecoder.h" #include "TurnoutDecoder.h" /****************************************************************************** @@ -63,7 +65,7 @@ class DecoderProxy inline bool IsActive() const { - auto turnout = DynamicDecoderCast(); + auto turnout = DynamicDecoderCast(); return turnout->GetState() == dcclite::DecoderStates::ACTIVE; } @@ -96,6 +98,20 @@ class DecoderProxy this->RegisterStateSyncCallback(); } + void SetAspect(dcclite::SignalAspects aspect) + { + auto decoder = DynamicDecoderCast(); + + decoder->SetAspect(aspect, "LuaScript"); + } + + dcclite::SignalAspects GetAspect() + { + auto decoder = DynamicDecoderCast(); + + return decoder->GetAspect(); + } + private: template inline T *DynamicDecoderCast() @@ -213,7 +229,7 @@ void DecoderProxy::OnDecoderDestroy(dcclite::broker::Decoder &decoder) * * DccLiteProxy * -* We put all the scripting funtionality on a helper class to better code isolation +* We put all the scripting funtionality on a helper class for better code isolation * and to reduce dependencies. * ******************************************************************************/ @@ -323,7 +339,43 @@ namespace dcclite::broker "inactive", sol::property(&DecoderProxy::IsInactive), "state", sol::property(&DecoderProxy::IsActive), "set_state", &DecoderProxy::SetState, - "on_state_change", &DecoderProxy::OnStateChange + "on_state_change", &DecoderProxy::OnStateChange, + "set_aspect", &DecoderProxy::SetAspect, + "aspect", sol::property(&DecoderProxy::GetAspect) + ); + + state.new_enum( + "SignalAspects", + { + {magic_enum::enum_name(SignalAspects::Stop), SignalAspects::Stop}, + {magic_enum::enum_name(SignalAspects::TakeSiding), SignalAspects::TakeSiding}, + {magic_enum::enum_name(SignalAspects::StopOrders), SignalAspects::StopOrders}, + {magic_enum::enum_name(SignalAspects::StopProceed), SignalAspects::StopProceed}, + {magic_enum::enum_name(SignalAspects::Restricted), SignalAspects::Restricted}, + {magic_enum::enum_name(SignalAspects::SlowAproach), SignalAspects::SlowAproach}, + {magic_enum::enum_name(SignalAspects::Slow), SignalAspects::Slow}, + {magic_enum::enum_name(SignalAspects::MediumAproach), SignalAspects::MediumAproach}, + {magic_enum::enum_name(SignalAspects::MediumSlow), SignalAspects::MediumSlow}, + {magic_enum::enum_name(SignalAspects::Medium), SignalAspects::Medium}, + {magic_enum::enum_name(SignalAspects::MediumLimited), SignalAspects::MediumLimited}, + {magic_enum::enum_name(SignalAspects::MediumClear), SignalAspects::MediumClear}, + {magic_enum::enum_name(SignalAspects::LimitedAproach), SignalAspects::LimitedAproach}, + {magic_enum::enum_name(SignalAspects::LimitedSlow), SignalAspects::LimitedSlow}, + {magic_enum::enum_name(SignalAspects::LimitedMedium), SignalAspects::LimitedMedium}, + {magic_enum::enum_name(SignalAspects::Limited), SignalAspects::Limited}, + {magic_enum::enum_name(SignalAspects::LimitedClear), SignalAspects::LimitedClear}, + {magic_enum::enum_name(SignalAspects::Aproach), SignalAspects::Aproach}, + {magic_enum::enum_name(SignalAspects::AdvanceAproach), SignalAspects::AdvanceAproach}, + {magic_enum::enum_name(SignalAspects::AproachSlow), SignalAspects::AproachSlow}, + {magic_enum::enum_name(SignalAspects::AdvanceAproachSlow), SignalAspects::AdvanceAproachSlow}, + {magic_enum::enum_name(SignalAspects::AproachMedium), SignalAspects::AproachMedium}, + {magic_enum::enum_name(SignalAspects::AdvanceAproachMedium), SignalAspects::AdvanceAproachMedium}, + {magic_enum::enum_name(SignalAspects::AproachLimited), SignalAspects::AproachLimited}, + {magic_enum::enum_name(SignalAspects::AdvanceAproachLimited), SignalAspects::AdvanceAproachLimited}, + {magic_enum::enum_name(SignalAspects::Clear), SignalAspects::Clear}, + {magic_enum::enum_name(SignalAspects::CabSpeed), SignalAspects::CabSpeed}, + {magic_enum::enum_name(SignalAspects::Dark), SignalAspects::Dark} + } ); } diff --git a/src/BrokerLib/dcc/NetworkDevice.cpp b/src/BrokerLib/dcc/NetworkDevice.cpp index f43615a3..e4606a02 100644 --- a/src/BrokerLib/dcc/NetworkDevice.cpp +++ b/src/BrokerLib/dcc/NetworkDevice.cpp @@ -402,6 +402,7 @@ namespace dcclite::broker auto remoteDecoder = static_cast(m_rclSelf.m_vecDecoders[i]); remoteDecoder->SyncRemoteState(state); +#if 0 if (remoteDecoder->IsOutputDecoder()) { auto *outputDecoder = static_cast(remoteDecoder); @@ -413,6 +414,8 @@ namespace dcclite::broker outputDecoder->ToggleState("OnPacket_Sync"); } } +#endif + } dcclite::Log::Info("[Device::{}] [SyncState::OnPacket] Sync OK", m_rclSelf.GetName()); @@ -653,7 +656,6 @@ namespace dcclite::broker So if we received any sensor state, we send back to the client our current state so it can ACK our current state */ - sensorStateRefresh = remoteDecoder->IsInputDecoder() || sensorStateRefresh; } diff --git a/src/BrokerLib/dcc/SignalDecoder.cpp b/src/BrokerLib/dcc/SignalDecoder.cpp index 79d10ec4..3f3a7233 100644 --- a/src/BrokerLib/dcc/SignalDecoder.cpp +++ b/src/BrokerLib/dcc/SignalDecoder.cpp @@ -76,14 +76,14 @@ namespace dcclite::broker auto aspectId = dcclite::ConvertNameToAspect(name); - if (std::any_of(m_vecAspects.begin(), m_vecAspects.end(), [aspectId](const Aspect &aspect) { return aspect.m_eAspect == aspectId; })) + if (std::any_of(m_vecAspects.begin(), m_vecAspects.end(), [aspectId](const Aspect &aspect) { return aspect.m_kAspect == aspectId; })) { throw std::invalid_argument(fmt::format("[SignalDecoder::{}] [SignalDecoder] Error: aspect {} already defined", this->GetName(), name)); } Aspect newAspect; - newAspect.m_eAspect = aspectId; + newAspect.m_kAspect = aspectId; auto onLights = aspectElement.FindMember("on"); if (onLights != aspectElement.MemberEnd()) @@ -147,12 +147,12 @@ namespace dcclite::broker std::sort(m_vecAspects.begin(), m_vecAspects.end(), [](const Aspect &a, const Aspect &b) { - return b.m_eAspect < a.m_eAspect; + return b.m_kAspect < a.m_kAspect; }); //start with most restrictive aspect, expected to be Stop const auto aspectIndex = static_cast(m_vecAspects.size() - 1); - this->ApplyAspect(m_vecAspects[aspectIndex].m_eAspect, aspectIndex); + this->ApplyAspect(m_vecAspects[aspectIndex].m_kAspect, aspectIndex); } @@ -161,11 +161,11 @@ namespace dcclite::broker Decoder::Serialize(stream); stream.AddStringValue("requestedAspectName", dcclite::ConvertAspectToName(m_eCurrentAspect)); - stream.AddStringValue("currentAspectName", dcclite::ConvertAspectToName(m_vecAspects[m_uCurrentAspectIndex].m_eAspect)); + stream.AddStringValue("currentAspectName", dcclite::ConvertAspectToName(m_vecAspects[m_uCurrentAspectIndex].m_kAspect)); auto aspectsData = stream.AddArray("aspects"); for (const auto &item : m_vecAspects) - aspectsData.AddString(dcclite::ConvertAspectToName(item.m_eAspect)); + aspectsData.AddString(dcclite::ConvertAspectToName(item.m_kAspect)); } void SignalDecoder::ForEachHead(const std::vector &heads, const dcclite::SignalAspects aspect, std::function proc) const @@ -192,7 +192,7 @@ namespace dcclite::broker int index = 0; for (const auto &it : m_vecAspects) { - if (it.m_eAspect <= aspect) + if (it.m_kAspect <= aspect) { break; } @@ -204,21 +204,21 @@ namespace dcclite::broker --index; //warn user... - if (aspect != m_vecAspects[index].m_eAspect) + if (aspect != m_vecAspects[index].m_kAspect) { Log::Warn( "[SignalDecoder::{}] [SetAspect] Aspect {} requested by {} not found, using {}", this->GetName(), dcclite::ConvertAspectToName(aspect), requester, - dcclite::ConvertAspectToName(m_vecAspects[index].m_eAspect) + dcclite::ConvertAspectToName(m_vecAspects[index].m_kAspect) ); } Log::Info( "[SignalDecoder::{}] [SetAspect] Changed from {} to {}, requested by {}", this->GetName(), - dcclite::ConvertAspectToName(m_vecAspects[m_uCurrentAspectIndex].m_eAspect), + dcclite::ConvertAspectToName(m_vecAspects[m_uCurrentAspectIndex].m_kAspect), dcclite::ConvertAspectToName(aspect), requester ); diff --git a/src/BrokerLib/dcc/SignalDecoder.h b/src/BrokerLib/dcc/SignalDecoder.h index eae088b3..1f277fee 100644 --- a/src/BrokerLib/dcc/SignalDecoder.h +++ b/src/BrokerLib/dcc/SignalDecoder.h @@ -80,7 +80,11 @@ namespace dcclite::broker // // - void SetAspect(const dcclite::SignalAspects aspect, const char *requester); + void SetAspect(const dcclite::SignalAspects aspect, const char *requester); + inline dcclite::SignalAspects GetAspect() const + { + return m_eCurrentAspect; + } private: void ForEachHead(const std::vector &heads, const dcclite::SignalAspects aspect, std::function proc) const; @@ -90,7 +94,7 @@ namespace dcclite::broker private: struct Aspect { - dcclite::SignalAspects m_eAspect; + dcclite::SignalAspects m_kAspect; std::vector m_vecOnHeads; std::vector m_vecOffHeads; diff --git a/src/BrokerLib/dispatcher/DispatcherService.cpp b/src/BrokerLib/dispatcher/DispatcherService.cpp index 3bc3e60c..c482b47e 100644 --- a/src/BrokerLib/dispatcher/DispatcherService.cpp +++ b/src/BrokerLib/dispatcher/DispatcherService.cpp @@ -61,6 +61,11 @@ namespace dcclite::broker m_rclSensor.SetSensorState(clear ? dcclite::DecoderStates::INACTIVE : dcclite::DecoderStates::ACTIVE); } + inline sol::table GetScriptObject() noexcept + { + return m_clObject; + } + protected: sol::table m_clObject; VirtualSensorDecoder &m_rclSensor; @@ -125,6 +130,8 @@ namespace dcclite::broker void RegisterSection(std::string_view name, sol::table obj); void RegisterTSection(std::string_view name, sol::table obj); + sol::table TryGetSection(std::string_view name); + void OnSectionStateChange(sol::table obj, int newState); void IScriptSupport_RegisterProxy(sol::table &table) override; @@ -185,6 +192,7 @@ namespace dcclite::broker "register_section", &DispatcherServiceImpl::RegisterSection, "register_tsection", &DispatcherServiceImpl::RegisterTSection, "on_section_state_change", &DispatcherServiceImpl::OnSectionStateChange, + "get_section", &DispatcherServiceImpl::TryGetSection, "panic", &DispatcherServiceImpl::Panic ); } @@ -219,6 +227,15 @@ namespace dcclite::broker #endif } + sol::table DispatcherServiceImpl::TryGetSection(std::string_view name) + { + auto section = static_cast(m_pSections->TryGetChild(RName{name})); + if (!section) + return sol::nil; + + return section->GetScriptObject(); + } + void DispatcherServiceImpl::RegisterSection(std::string_view name, sol::table obj) { auto &sensor = this->CreateSectionSensor(obj); diff --git a/src/BrokerLib/terminal/TerminalClient.cpp b/src/BrokerLib/terminal/TerminalClient.cpp index a3c6fe45..762d4a35 100644 --- a/src/BrokerLib/terminal/TerminalClient.cpp +++ b/src/BrokerLib/terminal/TerminalClient.cpp @@ -96,7 +96,9 @@ namespace dcclite::broker FolderObject *TerminalClient::TryGetServicesFolder() const { auto item = m_clContext.GetItem(); - if (!item->IsFolder()) + + //item may be null during system shutdown... + if (!item && !item->IsFolder()) { dcclite::Log::Error("[TerminalClient::RegisterListeners] Current location {} is invalid", m_clContext.GetLocation().string()); diff --git a/src/UnitTest/SignalDecoderTest.cpp b/src/UnitTest/SignalDecoderTest.cpp index a540d177..aed29ea3 100644 --- a/src/UnitTest/SignalDecoderTest.cpp +++ b/src/UnitTest/SignalDecoderTest.cpp @@ -116,10 +116,10 @@ TEST(SignalDecoderTest, Basic) auto &aspects = tester.GetAspects(); ASSERT_EQ(aspects.size(), 4); - ASSERT_EQ(aspects[0].m_eAspect, dcclite::SignalAspects::Dark); - ASSERT_EQ(aspects[1].m_eAspect, dcclite::SignalAspects::Clear); - ASSERT_EQ(aspects[2].m_eAspect, dcclite::SignalAspects::Aproach); - ASSERT_EQ(aspects[3].m_eAspect, dcclite::SignalAspects::Stop); + ASSERT_EQ(aspects[0].m_kAspect, dcclite::SignalAspects::Dark); + ASSERT_EQ(aspects[1].m_kAspect, dcclite::SignalAspects::Clear); + ASSERT_EQ(aspects[2].m_kAspect, dcclite::SignalAspects::Aproach); + ASSERT_EQ(aspects[3].m_kAspect, dcclite::SignalAspects::Stop); // // diff --git a/todo.txt b/todo.txt index d8f26102..d0d7036a 100644 --- a/todo.txt +++ b/todo.txt @@ -5,8 +5,6 @@ DCCLite - Scripts does not need to monitor device reload after script has run - states changes when devices are offline will be sent down to the device when it becomes online -- Expose signals to scripts - - Parser: use std::string_view - Better emulator: