Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP [#30] - Add a simple text based protocol to the project to display continuous measurement results #54

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@ RDB_Diplomaterv_Monitor.pro.user*
RDB_Monitor.pro.user*
tests/test_config.json
tests/protocol_emulator/emulators/__pycache__/*
.idea
cmake-build-debug

50 changes: 38 additions & 12 deletions application/sources/backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@ Backend::Backend() : QObject(), gui_signal_interface(nullptr)
available_connection_handlers.append(QString::fromStdString(serial_port_connection_name));

available_protocol_handlers.append(QString::fromStdString(measurement_data_protocol_name));
// Deactivate the CMDP before merging as this Protocol is not fully implemented yet!
//available_protocol_handlers.append(QString::fromStdString(continous_measurement_data_protocol_name));
available_protocol_handlers.append(QString::fromStdString(continous_measurement_data_protocol_name));

file_handlers.push_back(std::make_shared<MeasurementDataProtocol>());
}
Expand Down Expand Up @@ -105,22 +104,36 @@ void Backend::ReportStatus(const std::string& message)
}
}

void Backend::StoreNetworkDiagrams(const QString& connection_name, std::vector<DefaultDiagram>& new_diagrams)
std::vector<QModelIndex> Backend::StoreNetworkDiagrams(const QString& connection_name, std::vector<DefaultDiagram>& new_diagrams)
{
StoreDiagrams(new_diagrams,
auto result = StoreDiagrams(new_diagrams,
[&](const DefaultDiagram& diagram_to_add) -> QModelIndex
{
return diagram_container.AddDiagramFromNetwork(connection_name.toStdString(), diagram_to_add);
});

return result;
}

void Backend::StoreFileDiagrams(const std::string& file_name, const std::string& file_path, std::vector<DefaultDiagram>& new_diagrams)
std::vector<QModelIndex> Backend::StoreFileDiagrams(const std::string& file_name, const std::string& file_path, std::vector<DefaultDiagram>& new_diagrams)
{
StoreDiagrams(new_diagrams,
auto result = StoreDiagrams(new_diagrams,
[&](const DefaultDiagram& diagram_to_add) -> QModelIndex
{
return diagram_container.AddDiagramFromFile(file_name, file_path, diagram_to_add);
});

return result;
}

void Backend::UpdateNetworkDiagram(const QModelIndex& model_index, const DefaultDiagram& updated_diagram)
{
auto diagram_ptr = diagram_container.GetDiagram(model_index);
if(diagram_ptr)
{
// TODO This should be optimized because now for every update (even if that is only just a new point) the whole diagram will be overwritten. See Issue #53
*diagram_ptr = updated_diagram;
}
}

std::vector<std::string> Backend::GetSupportedFileExtensions(void)
Expand Down Expand Up @@ -165,10 +178,19 @@ void Backend::OpenNetworkConnection(const ConnectionRequestData& request_data)
connection,
connection_settings,
protocol,
std::bind(&Backend::StoreNetworkDiagrams, this, std::placeholders::_1, std::placeholders::_2),
std::bind(&Backend::StoreNetworkDiagrams, this, unique_user_defined_name, std::placeholders::_1),
std::bind(&Backend::UpdateNetworkDiagram, this, std::placeholders::_1, std::placeholders::_2),
std::bind(&Backend::ReportStatus, this, std::placeholders::_1));

std::string status_message = "The connection \"" + unique_user_defined_name.toStdString() + "\" was successfully opened!";
std::string status_message = "The connection \"" + unique_user_defined_name.toStdString() + "\" ";
if(network_handlers[unique_user_defined_name]->Run())
{
status_message = + "was successfully opened!";
}
else
{
status_message = "could not be opened! Please delete it andwas successfully opened!";
}
ReportStatus(status_message);

auto active_connections = getActiveConnections();
Expand Down Expand Up @@ -207,10 +229,10 @@ void Backend::ImportFile(const std::string& path_to_file)
bool the_file_was_processed = false;
for(auto const& file_handler : file_handlers)
{
if(file_handler->CanThisFileBeProcessed(path_to_file))
if(file_handler->CanThisFileBeImportedFrom(path_to_file))
{
std::ifstream file_stream(path_to_file);
auto diagrams_from_file = file_handler->ProcessData(file_stream);
auto diagrams_from_file = file_handler->ImportFromFile(file_stream);
StoreFileDiagrams(file_name, path_to_file, diagrams_from_file);

// Updating the configuration with the folder of the file that was imported
Expand Down Expand Up @@ -258,7 +280,7 @@ void Backend::ExportFileStoreCheckedDiagrams(const std::string& path_to_file)
auto checked_diagrams = diagram_container.GetCheckedDiagrams();
if(checked_diagrams.size())
{
auto exported_data = protocol_handler->ExportData(checked_diagrams);
auto exported_data = protocol_handler->ExportToFile(checked_diagrams);

std::ofstream output_file_stream(path_to_file, (std::ofstream::out | std::ofstream::trunc));
output_file_stream << exported_data.rdbuf();
Expand All @@ -282,15 +304,17 @@ void Backend::ExportFileStoreCheckedDiagrams(const std::string& path_to_file)
}
}

void Backend::StoreDiagrams(std::vector<DefaultDiagram>& new_diagrams, const std::function<QModelIndex(const DefaultDiagram&)> storage_logic)
std::vector<QModelIndex> Backend::StoreDiagrams(std::vector<DefaultDiagram>& new_diagrams, const std::function<QModelIndex(const DefaultDiagram&)> storage_logic)
{
std::vector<QModelIndex> result;
auto container_is_empty = (0 == diagram_container.GetNumberOfDiagrams());

// Adding the diagrams to the diagram_container
for(const auto& i : new_diagrams)
{
// Calling the logic that does the storage for a single diagram, this is provided by the caller
auto recently_added_diagram = storage_logic(i);
result.push_back(recently_added_diagram);

// Displaying the diagram if this was the first
if(container_is_empty)
Expand All @@ -306,6 +330,8 @@ void Backend::StoreDiagrams(std::vector<DefaultDiagram>& new_diagrams, const std
}

ReportStatus(std::to_string(new_diagrams.size()) + " new diagram was added to the list.");

return result;
}

QStringList Backend::getActiveConnections(void)
Expand Down
7 changes: 4 additions & 3 deletions application/sources/backend.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,9 @@ class Backend : public QObject, public I_BackendSignal

void ReportStatus(const std::string& message);

void StoreNetworkDiagrams(const QString& connection_name, std::vector<DefaultDiagram>& new_diagrams);
void StoreFileDiagrams(const std::string& file_name, const std::string& file_path, std::vector<DefaultDiagram>& new_diagrams);
std::vector<QModelIndex> StoreNetworkDiagrams(const QString& connection_name, std::vector<DefaultDiagram>& new_diagrams);
std::vector<QModelIndex> StoreFileDiagrams(const std::string& file_name, const std::string& file_path, std::vector<DefaultDiagram>& new_diagrams);
void UpdateNetworkDiagram(const QModelIndex& model_index, const DefaultDiagram& updated_diagram);

QAbstractItemModel* GetDiagramContainerModel(void) override {return &diagram_container;}
std::string GetFileImportDefaultFolder(void) override {return configuration.ImportFolder();}
Expand All @@ -86,7 +87,7 @@ private slots:
void ExportFileStoreCheckedDiagrams(const std::string& path_to_file);

private:
void StoreDiagrams(std::vector<DefaultDiagram>& new_diagrams, const std::function<QModelIndex(const DefaultDiagram&)> storage_logic);
std::vector<QModelIndex> StoreDiagrams(std::vector<DefaultDiagram>& new_diagrams, const std::function<QModelIndex(const DefaultDiagram&)> storage_logic);
QStringList getActiveConnections(void);
QString makeUserDefinedConnectionNameUnique(const QString& user_defined_name);

Expand Down
75 changes: 61 additions & 14 deletions application/sources/continous_measurement_data_protocol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ std::string ContinousMeasurementDataProtocol::GetProtocolName(void)
return continous_measurement_data_protocol_name;
}

std::vector<DefaultDiagram> ContinousMeasurementDataProtocol::ProcessData(std::istream& input_data)
void ContinousMeasurementDataProtocol::ProcessNetworkData(std::istream& input_data)
{
std::vector<DefaultDiagram> assembled_diagrams;
std::string actual_line_std_string;
Expand All @@ -56,6 +56,7 @@ std::vector<DefaultDiagram> ContinousMeasurementDataProtocol::ProcessData(std::i
state = Constants::States::ProcessingHeaderDiagramTitle;
}
break;

case Constants::States::ProcessingHeaderDiagramTitle:
state = Constants::States::ProcessingHeaderDataLines;
// If a header message diagram title line was found
Expand All @@ -78,8 +79,11 @@ std::vector<DefaultDiagram> ContinousMeasurementDataProtocol::ProcessData(std::i
actual_diagram = DefaultDiagram(current_date_and_time_string);
// Switching to the next state without a break --> a new line will NOT be fetched, because this line is the headline
}
// In both cases the actual model index needs to be invalidated as we are starting a new diagram
actual_model_index = QModelIndex();
// The falltrough is not an error in this case, this behaviour needed because there was no diagram title found, the actual_line contains the headline
[[fallthrough]];

[[fallthrough]];
case Constants::States::ProcessingHeaderDataLines:
match = regex_patterns.header_datalines.match(actual_line);
if(match.hasMatch())
Expand All @@ -93,7 +97,7 @@ std::vector<DefaultDiagram> ContinousMeasurementDataProtocol::ProcessData(std::i
QRegularExpressionMatchIterator regex_iterator = regex_patterns.header_dataline_y_titles.globalMatch(y_titles);
while(regex_iterator.hasNext())
{
auto match = regex_iterator.next();
match = regex_iterator.next();
auto y_id = match.captured("id");
auto y_title = match.captured("title");

Expand All @@ -103,14 +107,14 @@ std::vector<DefaultDiagram> ContinousMeasurementDataProtocol::ProcessData(std::i
state = Constants::States::WaitingForHeaderMessageStart;
}
}

state = Constants::States::WaitingForHeaderMessageEnd;
}
else
{
state = Constants::States::WaitingForHeaderMessageStart;
}
break;

case Constants::States::WaitingForHeaderMessageEnd:
// If a header message end line was found
match = regex_patterns.header_end.match(actual_line);
Expand All @@ -123,6 +127,7 @@ std::vector<DefaultDiagram> ContinousMeasurementDataProtocol::ProcessData(std::i
state = Constants::States::WaitingForHeaderMessageStart;
}
break;

case Constants::States::WaitingForDataMessageStart:
// If a header message end line was found
match = regex_patterns.data_start.match(actual_line);
Expand All @@ -137,6 +142,7 @@ std::vector<DefaultDiagram> ContinousMeasurementDataProtocol::ProcessData(std::i
state = Constants::States::WaitingForHeaderMessageStart;
}
break;

case Constants::States::ProcessingDataMessageContent:
match = regex_patterns.data_content.match(actual_line);
if(match.hasMatch())
Expand All @@ -147,7 +153,7 @@ std::vector<DefaultDiagram> ContinousMeasurementDataProtocol::ProcessData(std::i
QRegularExpressionMatchIterator regex_iterator = regex_patterns.data_y_content.globalMatch(y_values);
while(regex_iterator.hasNext())
{
auto match = regex_iterator.next();
match = regex_iterator.next();
auto y_id = match.captured("id");
auto y_value = match.captured("value");

Expand Down Expand Up @@ -175,38 +181,79 @@ std::vector<DefaultDiagram> ContinousMeasurementDataProtocol::ProcessData(std::i
}
}
break;

default:
state = Constants::States::WaitingForHeaderMessageStart;
throw("The DataProcessor::ProcessData's statemachine switched to an unexpected state: " + std::to_string(static_cast<std::underlying_type<Constants::States>::type>(state)));
throw("The ContinousMeasurementDataProtocol::ProcessNetworkData's statemachine switched to an unexpected state: "
+ std::to_string(static_cast<std::underlying_type<Constants::States>::type>(state)));
break;
}
}

return assembled_diagrams;
// If the actual model index is valid then this is an update and not a new diagram
if(actual_model_index.isValid())
{
// We should not have assembled diagrams here, only an update to the actual diagram
if(!assembled_diagrams.empty())
{
throw("The ContinousMeasurementDataProtocol::ProcessNetworkData detected an error: the actual_model_index was valid but the assembled_diagrams was not empty!");
}

// Sending the updated diagram
if(m_diagram_updater)
{
m_diagram_updater(actual_model_index, actual_diagram);
}
}
else
{
// If the model index is not valid then we are sending new diagrams
if(m_diagram_collector)
{
auto model_indexes = m_diagram_collector(assembled_diagrams);

// If we have the waiting for header start state here then we either had a message error
// or a tail message was received. In both cases the last diagram is finished. This means that the
// model index does not need to be stored as no update will be sent anymore.
if(state != Constants::States::WaitingForHeaderMessageStart)
{
// We need to only store the last model index,
// because we are only going to be able to send updates to the last diagram.
actual_model_index = model_indexes.back();
}
}
}
}

std::stringstream ContinousMeasurementDataProtocol::ExportData(const std::vector<DefaultDiagram>& diagrams_to_export)
std::string ContinousMeasurementDataProtocol::GetSupportedFileType(void)
{
(void) diagrams_to_export;
throw("The Continous Measurement Protocol does not support exporting into files!");
// The CMDP protocol does not support any file types
return std::string();
}

bool ContinousMeasurementDataProtocol::CanThisFileBeProcessed(const std::string path_to_file)
bool ContinousMeasurementDataProtocol::CanThisFileBeImportedFrom(const std::string path_to_file)
{
(void) path_to_file;
// The CMDP protocol does not support file processing
return false;
}

std::vector<DefaultDiagram> ContinousMeasurementDataProtocol::ImportFromFile(std::ifstream& file_stream)
{
(void) file_stream;
// The CMDP protocol does not support file processing
return std::vector<DefaultDiagram>();
}

bool ContinousMeasurementDataProtocol::CanThisFileBeExportedInto(const std::string path_to_file)
{
(void) path_to_file;
// The CMDP protocol does not support storing into files
return false;
}

std::string ContinousMeasurementDataProtocol::GetSupportedFileType(void)
std::stringstream ContinousMeasurementDataProtocol::ExportToFile(const std::vector<DefaultDiagram>& diagrams_to_export)
{
// The CMDP protocol does not support any file types
return std::string();
(void) diagrams_to_export;
throw("The Continous Measurement Protocol does not support exporting into files!");
}
10 changes: 6 additions & 4 deletions application/sources/continous_measurement_data_protocol.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,12 @@ class ContinousMeasurementDataProtocol : public I_Protocol
ContinousMeasurementDataProtocol& operator=(ContinousMeasurementDataProtocol&&) = delete;

virtual std::string GetProtocolName(void) override;
virtual std::vector<DefaultDiagram> ProcessData(std::istream& input_data) override;
virtual std::stringstream ExportData(const std::vector<DefaultDiagram>& diagrams_to_export) override;
virtual bool CanThisFileBeProcessed(const std::string path_to_file) override;
virtual bool CanThisFileBeExportedInto(const std::string path_to_file) override;
virtual void ProcessNetworkData(std::istream& input_data) override;
virtual std::string GetSupportedFileType(void) override;
virtual bool CanThisFileBeImportedFrom(const std::string path_to_file) override;
virtual std::vector<DefaultDiagram> ImportFromFile(std::ifstream& file_tream) override;
virtual std::stringstream ExportToFile(const std::vector<DefaultDiagram>& diagrams_to_export) override;
virtual bool CanThisFileBeExportedInto(const std::string path_to_file) override;

private:
struct Constants
Expand Down Expand Up @@ -94,6 +95,7 @@ class ContinousMeasurementDataProtocol : public I_Protocol

Constants::States state;
DefaultDiagram actual_diagram;
QModelIndex actual_model_index;
RegexPatterns regex_patterns;
};

Expand Down
23 changes: 15 additions & 8 deletions application/sources/i_connection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,28 +26,35 @@
#include <istream>
#include <memory>
#include <string>

#include <QtPlugin>
#include <functional>


class I_ConnectionSettings;

class I_Connection
{
public:
using data_collector_t = std::function<void(std::istream& received_data)>;
using error_reporter_t = std::function<void(const std::string&)>;

virtual ~I_Connection() = default;

virtual std::string getName(void) = 0;
virtual void RegisterCallbacks(const data_collector_t& data_collector,
const error_reporter_t& error_reporter)
{
m_data_collector = data_collector;
m_error_reporter = error_reporter;
}

virtual std::string GetName(void) = 0;
virtual bool Open(const std::shared_ptr<I_ConnectionSettings> settings) = 0;
virtual void Close(void) = 0;
virtual bool IsOpen(void) = 0;

signals:
virtual void DataReceived(std::istream& received_data) = 0;
virtual void ErrorReport(const std::string& error_message) = 0;
protected:
data_collector_t m_data_collector;
error_reporter_t m_error_reporter;
};

Q_DECLARE_INTERFACE(I_Connection, "ConnectionInterface")


#endif // I_CONNECTION_HPP
Loading