Skip to content

Commit

Permalink
WIP GRAFCET
Browse files Browse the repository at this point in the history
  • Loading branch information
Lecrapouille committed Jul 3, 2024
1 parent ff98d7b commit 7694636
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 42 deletions.
76 changes: 58 additions & 18 deletions src/Editor/DearImGui/Editor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -911,12 +911,17 @@ void Editor::messagebox()
ImGui::End();
}


//------------------------------------------------------------------------------
void Editor::inspector()
{
// InputText modify callback: modified => net shall be saved ?
static bool modified = false;
// InputText callback: GRAFCET transitivities modified ?
static bool compiled = false;
// Do not allow editing when running simulation
const auto readonly = m_simulation.running ?
ImGuiInputTextFlags_ReadOnly : ImGuiInputTextFlags_None;
ImGuiInputTextFlags_ReadOnly : ImGuiInputTextFlags_None;

// Place captions and tokens
{
Expand All @@ -934,19 +939,27 @@ void Editor::inspector()
{
ImGui::PushID(place.key.c_str());
ImGui::AlignTextToFramePadding();
ImGui::InputText(place.key.c_str(), &place.caption, readonly);
ImGui::InputText(place.key.c_str(), &place.caption,
readonly | ImGuiInputTextFlags_CallbackEdit,
[](ImGuiInputTextCallbackData*)
{
modified = true;
return 0;
});

// Increment/decrement tokens
ImGui::SameLine();
ImGui::PushButtonRepeat(true);
if (ImGui::ArrowButton("##left", ImGuiDir_Left))
{
place.decrement();
modified = true;
}
ImGui::SameLine();
if (ImGui::ArrowButton("##right", ImGuiDir_Right))
{
place.increment();
modified = true;
}
ImGui::PopButtonRepeat();

Expand All @@ -971,34 +984,53 @@ void Editor::inspector()
ImGui::Separator();
ImGui::Text("%s", (m_net.type() == TypeOfNet::GRAFCET) ? "Transitivities:" : "Captions:");

// Show contents of transitivities
// Compile transitivities for GRAFCET the initial time and each time one of transitions
// have been edited (Currently: any InputText invalid the whole sensors. Slow but easier
// to implement).
if ((!compiled) && (m_net.type() == TypeOfNet::GRAFCET))
{
compiled = m_simulation.generateSensors();
}
for (auto& t: m_net.transitions())
{
ImGui::InputText(t.key.c_str(), &t.caption, readonly);
std::vector<Receptivity> const& receptivities = m_simulation.receptivities();
if ((m_net.type() == TypeOfNet::GRAFCET) && (!receptivities.empty()) && (!m_simulation.running))
// Show contents of transition
ImGui::InputText(t.key.c_str(), &t.caption,
readonly | ImGuiInputTextFlags_CallbackEdit,
[](ImGuiInputTextCallbackData*)
{
modified = true;
compiled = false;
return 0;
});

// For GRAFCET and show syntax error on the transitivity
if ((m_net.type() == TypeOfNet::GRAFCET) && (!m_simulation.running))
{
Receptivity const& recp = receptivities[t.id];
// FIXME parse and clear sensors if and only if we modified entrytext
if (!recp.isValid()) // && recp.compiled()
std::vector<Receptivity> const& receptivities = m_simulation.receptivities();
if (!receptivities.empty())
{
ImGui::TextColored(ImVec4(1.0f, 0.0f, 0.0f, 1.0f), "%s", recp.error().c_str());
Receptivity const& recp = receptivities[t.id];
if (!recp.isValid())
{
ImGui::TextColored(ImVec4(1.0f, 0.0f, 0.0f, 1.0f), "%s", recp.error().c_str());
ImGui::TextColored(ImVec4(1.0f, 0.0f, 0.0f, 1.0f), "%s", "See help for the syntax");
}
}
}
}
ImGui::End();

// For GRAFCET show sensor names from transitivities
if (m_net.type() == TypeOfNet::GRAFCET)
{
if (m_simulation.running)
ImGui::Begin("Sensors");
for (auto& it: Sensors::instance().database())
{
ImGui::Begin("Sensors");
for (auto& it: Sensors::instance().database())
{
ImGui::SliderInt(it.first.c_str(), &it.second, 0, 1);
}
ImGui::End();
int prev_value = it.second;
ImGui::SliderInt(it.first.c_str(), &it.second, 0, 1);
modified = (prev_value != it.second) && (!m_simulation.running);
}
ImGui::End();
}
}

Expand All @@ -1012,7 +1044,9 @@ void Editor::inspector()
if (arc.from.type == Node::Type::Transition)
{
std::string text(arc.from.key + " -> " + arc.to.arcsOut[0]->to.key);
float prev_value = arc.duration;
ImGui::InputFloat(text.c_str(), &arc.duration, 0.01f, 1.0f, "%.3f", readonly);
modified = (prev_value != arc.duration);
}
}
ImGui::End();
Expand All @@ -1024,10 +1058,17 @@ void Editor::inspector()
for (auto& arc: m_net.arcs())
{
std::string text(arc.from.key + " -> " + arc.to.key);
float prev_value = arc.duration;
ImGui::InputFloat(text.c_str(), &arc.duration, 0.01f, 1.0f, "%.3f", readonly);
modified = (prev_value != arc.duration);
}
ImGui::End();
}

// Modified net ? If yes, set it as dirty to force its save when the app
// is closed.
m_net.modified |= modified;
modified = false;
}

//------------------------------------------------------------------------------
Expand Down Expand Up @@ -1323,7 +1364,6 @@ std::vector<Messages::TimedMessage> const& Editor::getLogs() const
void Editor::clearLogs()
{
m_messages.clear();

}

//--------------------------------------------------------------------------
Expand Down
23 changes: 16 additions & 7 deletions src/Net/Exports/ExportJSON.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
//=============================================================================

#include "Net/Exports/Exports.hpp"
#include "Net/Receptivities.hpp"
#include "TimedPetriNetEditor/PetriNet.hpp"
#include "nlohmann/json.hpp"
#include <fstream>
Expand All @@ -40,8 +41,6 @@ std::string exportToJSON(Net const& net, std::string const& filename)
return error.str();
}

// TODO sensors

file << "{" << std::endl;
file << " \"revision\": 3," << std::endl;
file << " \"type\": \"" << to_str(net.type()) << "\"," << std::endl;
Expand Down Expand Up @@ -74,17 +73,27 @@ std::string exportToJSON(Net const& net, std::string const& filename)
for (auto const& a: net.arcs())
{
file << separator; separator = ",\n";
file << " { \"from\": \"" << a.from.key << "\", " << "\"to\": \"" << a.to.key
<< "\"";
file << " { \"from\": \"" << a.from.key << "\", " << "\"to\": \"" << a.to.key << "\"";
if (a.from.type == Node::Type::Transition)
file << ", \"duration\": " << a.duration;
file << " }";
}

// GRAFCET sensors
separator = "\n";
file << "\n ],\n \"sensors\": [";
for (auto& it: Sensors::instance().database())
{
file << separator; separator = ",\n";
file << " { \"name\": \"" << it.first.c_str() << "\", "
<< "\"value\": " << it.second << " }";
}
file << "\n ]" << std::endl;
file << " }" << std::endl;
file << " ]" << std::endl;
file << "}" << std::endl;

// TODO GRAFCET actions

file << " }\n ]\n"; // nets
file << "}" << std::endl; // json document
return {};
}

Expand Down
1 change: 1 addition & 0 deletions src/Net/Imports/ImportJSON.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
namespace tpne {

//------------------------------------------------------------------------------
// TODO read sensor values
std::string importFromJSON(Net& net, std::string const& filename)
{
std::stringstream error;
Expand Down
47 changes: 30 additions & 17 deletions src/Net/Simulation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,25 +105,12 @@ void Simulation::stateStarting()
{
a.count = 0u;
}
m_net.resetReceptivies();

// Check for GRAFCET if boolean expressions in transitivities have
// not syntaxical errors.
if (m_net.type() == TypeOfNet::GRAFCET)
// Reset values on transitivities and sensors for GRAFCET
m_net.resetReceptivies();
if (!generateSensors())
{
Sensors::instance().clear();
m_receptivities.clear();
m_receptivities.resize(m_net.transitions().size());
for (auto const& it: m_net.transitions())
{
std::string error = m_receptivities[it.id].compile(it.caption, m_net);
if (!error.empty())
{
m_messages.setWarning(error);
running = false;
return ;
}
}
running = false;
}

//
Expand All @@ -144,6 +131,32 @@ void Simulation::stateStarting()
m_state = Simulation::State::Simulating;
}

//------------------------------------------------------------------------------
// FIXME Sensors::instance().clear(); is violent we loose current sensor values
// => they are reset to false.
// https://github.com/Lecrapouille/TimedPetriNetEditor/issues/29
bool Simulation::generateSensors()
{
// Check for GRAFCET if boolean expressions in transitivities have
// not syntaxical errors.
if (m_net.type() == TypeOfNet::GRAFCET)
{
Sensors::instance().clear();
m_receptivities.clear();
m_receptivities.resize(m_net.transitions().size());
for (auto const& it: m_net.transitions())
{
std::string error = m_receptivities[it.id].compile(it.caption, m_net);
if (!error.empty())
{
m_messages.setWarning(error);
return false;
}
}
}
return true;
}

//------------------------------------------------------------------------------
void Simulation::stateHalting()
{
Expand Down
1 change: 1 addition & 0 deletions src/Net/Simulation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class Simulation

Simulation(Net& net, Messages& m_messages);
void step(float const dt);
bool generateSensors();
inline std::vector<TimedToken> const& timedTokens() const { return m_timed_tokens; }
inline std::vector<Receptivity> const& receptivities() const { return m_receptivities; }

Expand Down

0 comments on commit 7694636

Please sign in to comment.