update websocket
updated to use protobuf
not quite finished with the Websocket message parser
This commit is contained in:
2026-09-30 12:33:20 +02:00
parent 022422b63c
commit 08fd5407c3
9 changed files with 220 additions and 220 deletions
+1
View File
@@ -57,6 +57,7 @@ target_sources(server_common
target_link_libraries(server_common target_link_libraries(server_common
PUBLIC PUBLIC
UI UI
proto-ui
spdlog spdlog
cpp_templates cpp_templates
${GPIOD_LIB} ${GPIOD_LIB}
+90 -95
View File
@@ -3,122 +3,122 @@
#include <magic_enum/magic_enum.hpp> #include <magic_enum/magic_enum.hpp>
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
QString Simulators::message_parser(QString message) // TODO: Fix parsing messages
QByteArray Simulators::message_parser(QByteArray message)
{ {
json j = json::parse(message.toStdString()); Event_m event_m;
if (j.contains("command")) bool event = m_serializer.deserialize(&event_m, message);
// if (j.contains("command"))
// {
// return QString::fromStdString(command_parser(j["command"]).dump());
// }
/*else*/ if (event)
{ {
return QString::fromStdString(command_parser(j["command"]).dump()); event_handler(event_m);
} }
else if (j.contains("event")) return QByteArray();
{
event_handler(j["event"]);
}
return "{}";
} }
json Simulators::command_parser(json command) // QByteArray Simulators::command_parser(json command)
{ // {
json j = "{}"_json; // json j = "{}"_json;
try // try
{ // {
std::string type = command.at("type"); // std::string type = command.at("type");
Command cmd = magic_enum::enum_cast<Command>(type).value_or(Command::end); // Command cmd = magic_enum::enum_cast<Command>(type).value_or(Command::end);
switch (cmd) // switch (cmd)
{ // {
case Command::get_UI_element: // case Command::get_UI_element:
SPDLOG_INFO("Command {}: {}", type, (size_t)command.at("id")); // SPDLOG_INFO("Command {}: {}", type, (size_t)command.at("id"));
if (is_not_active()) // if (is_not_active())
{ // {
SPDLOG_ERROR("Command got called but there is no active simulator"); // SPDLOG_ERROR("Command got called but there is no active simulator");
return j; // return j;
} // }
j["response"]["type"] = type; // j["response"]["type"] = type;
j["response"]["UI_item"] = // j["response"]["UI_item"] =
invoke_active_simulator()->get_UI_item(command.at("id"))->to_json(command.at("id")); // invoke_active_simulator()->get_UI_item(command.at("id"))->to_json(command.at("id"));
break; // break;
case Command::get_UI_elements: // case Command::get_UI_elements:
SPDLOG_INFO("Command {}", type); // SPDLOG_INFO("Command {}", type);
if (is_not_active()) // if (is_not_active())
{ // {
SPDLOG_ERROR("Command got called but there is no active simulator"); // SPDLOG_ERROR("Command got called but there is no active simulator");
return j; // return j;
} // }
j["response"]["type"] = type; // j["response"]["type"] = type;
j["response"]["UI_items"] = invoke_active_simulator()->get_UI_items()["UI_items"]; // j["response"]["UI_items"] = invoke_active_simulator()->get_UI_items()["UI_items"];
break; // break;
case Command::switch_simulator: // case Command::switch_simulator:
SPDLOG_INFO("Command {} to {}", type, std::string(command.at("name"))); // SPDLOG_INFO("Command {} to {}", type, std::string(command.at("name")));
switch_simulator(command.at("name")); // switch_simulator(command.at("name"));
j["response"]["type"] = type; // j["response"]["type"] = type;
break; // break;
case Command::get_active_simulator_name: // case Command::get_active_simulator_name:
SPDLOG_INFO("Command {}", type); // SPDLOG_INFO("Command {}", type);
j["response"]["type"] = type; // j["response"]["type"] = type;
j["response"]["name"] = active_simulator_name(); // j["response"]["name"] = active_simulator_name();
break; // break;
case Command::get_simulators: // case Command::get_simulators:
SPDLOG_INFO("Command {}", type); // SPDLOG_INFO("Command {}", type);
j["response"]["type"] = type; // j["response"]["type"] = type;
j["response"]["simulators"] = list_simulators(); // j["response"]["simulators"] = list_simulators();
break; // break;
default: // default:
break; // break;
} // }
} // }
catch (const json::exception &e) // catch (const json::exception &e)
{ // {
SPDLOG_ERROR("{} {}", __FUNCTION__, e.what()); // SPDLOG_ERROR("{} {}", __FUNCTION__, e.what());
} // }
return j; // return j;
} // }
void Simulators::event_handler(json event) void Simulators::event_handler(Event_m event)
{ {
try
{
std::string type = event.at("type");
Event e = magic_enum::enum_cast<Event>(type).value_or(Event::end);
if (invoke_active_simulator() == nullptr) if (invoke_active_simulator() == nullptr)
{ {
SPDLOG_ERROR("Event got called but there is no active simulator"); SPDLOG_ERROR("Event got called but there is no active simulator");
return; return;
} }
switch (e) QString type; // = QString::fromStdString(magic_enum::enum_cast<Event_m::KindFields>(event.kindField()).value_or(Event_m::KindFields::UninitializedField));
switch (event.kindField())
{ {
case Event::clicked: { case Event_m::KindFields::Clicked: {
SPDLOG_DEBUG("Event {}: {}", type, (size_t)event.at("id")); SPDLOG_DEBUG("Event {}: {}", type, (size_t)event.id_proto());
invoke_active_simulator()->get_UI_item(event.at("id"))->click(); invoke_active_simulator()->get_UI_item(event.id_proto())->click();
break; break;
} }
case Event::value_changed: { case Event_m::KindFields::ValueChanged: {
SPDLOG_DEBUG("Event {}: {} {}", type, (size_t)event.at("id"), (double)(event["value"])); SPDLOG_DEBUG("Event {}: {} {}", type, event.id_proto(), event.valueChanged().value());
invoke_active_simulator()->get_UI_item(event.at("id"))->set_value((double)event.at("value")); invoke_active_simulator()->get_UI_item(event.id_proto())->set_value(event.valueChanged().value());
break; break;
} }
case Event::text_changed: { case Event_m::KindFields::TextChanged: {
SPDLOG_DEBUG("Event {}: {} {}", type, (size_t)event.at("id"), std::string(event.at("text"))); SPDLOG_DEBUG("Event {}: {} {}", type, event.id_proto(), event.textChanged().text());
invoke_active_simulator()->get_UI_item(event.at("id"))->set_text(std::string(event.at("text"))); invoke_active_simulator()->get_UI_item(event.id_proto())->set_text(event.textChanged().text());
break; break;
} }
case Event::selected: { case Event_m::KindFields::Selected: {
SPDLOG_DEBUG("Event {}: {} {}", type, (size_t)event.at("id"), std::to_string((size_t)event.at("selected"))); SPDLOG_DEBUG("Event {}: {} {}", type, event.id_proto(), std::to_string(event.selected().selected()));
invoke_active_simulator()->get_UI_item(event.at("id"))->set_selected(event.at("selected")); invoke_active_simulator()->get_UI_item(event.id_proto())->set_selected(event.selected().selected());
break; break;
} }
case Event::can_send: { case Event_m::KindFields::CanSend: {
SPDLOG_DEBUG("Event {}: {}", type, (size_t)event.at("id")); SPDLOG_DEBUG("Event {}: {}", type, event.id_proto());
invoke_active_simulator() invoke_active_simulator()
->get_UI_item(event.at("id")) ->get_UI_item(event.id_proto())
->can_send((uint32_t)event.at("sid"), (uint8_t)event.at("dlc"), ->can_send(event.canSend().frame().sid(), event.canSend().frame().dlc(),
(std::array<uint8_t, 8>)event.at("payload")); event.canSend().frame().payload());
break; break;
} }
case Event::clear: { case Event_m::KindFields::Clear: {
SPDLOG_DEBUG("Event {}: {}", type, (size_t)event.at("id")); SPDLOG_DEBUG("Event {}: {}", type, event.id_proto());
invoke_active_simulator()->get_UI_item(event.at("id"))->clear(); invoke_active_simulator()->get_UI_item(event.id_proto())->clear();
break; break;
} }
default: { default: {
@@ -126,8 +126,3 @@ void Simulators::event_handler(json event)
} }
} }
} }
catch (const json::exception &e)
{
SPDLOG_ERROR("{} {}", __FUNCTION__, e.what());
}
}
+6 -6
View File
@@ -2,7 +2,7 @@
#include "simulator_base.hpp" #include "simulator_base.hpp"
#include "ui_item.hpp" #include "ui_item.hpp"
Simulator_base::Simulator_base(std::string name, Communication *com, std::chrono::milliseconds interval, Simulator_base::Simulator_base(QString name, Communication *com, std::chrono::milliseconds interval,
QObject *parent) QObject *parent)
: QObject(parent), m_name(name), m_timer(new QTimer(this)), m_interval(interval), m_com(com) : QObject(parent), m_name(name), m_timer(new QTimer(this)), m_interval(interval), m_com(com)
{ {
@@ -10,7 +10,7 @@ Simulator_base::Simulator_base(std::string name, Communication *com, std::chrono
m_UI_items.reserve(50); m_UI_items.reserve(50);
} }
std::string Simulator_base::name() const QString Simulator_base::name() const
{ {
// Get the name of the simulator // Get the name of the simulator
return m_name; return m_name;
@@ -20,17 +20,17 @@ void Simulator_base::push_ui_item(UI_item *item)
{ {
// Add a UI item to the simulator // Add a UI item to the simulator
connect(item, &UI_item::ui_changed, this, [this] { emit sim_changed(); }); connect(item, &UI_item::ui_changed, this, [this] { emit sim_changed(); });
item->set_id(m_UI_items.size());
m_UI_items.push_back(item); m_UI_items.push_back(item);
} }
json Simulator_base::get_UI_items() const QList<UI_item_m> Simulator_base::get_UI_items() const
{ {
// Get the UI items // Get the UI items
json items; QList<UI_item_m> items;
items["name"] = m_name;
for (size_t i = 0; i < m_UI_items.size(); i++) for (size_t i = 0; i < m_UI_items.size(); i++)
{ {
items["UI_items"].push_back(m_UI_items[i]->to_json(i)); items.push_back(m_UI_items[i]->to_proto());
} }
return items; return items;
+10 -22
View File
@@ -7,11 +7,8 @@
#ifndef INTERNAL #ifndef INTERNAL
#include "ui.hpp" #include "ui.hpp"
#else #else
#include <nlohmann/json.hpp>
using json = nlohmann::json;
Q_FORWARD_DECLARE_OBJC_CLASS(UI_item); Q_FORWARD_DECLARE_OBJC_CLASS(UI_item);
Q_FORWARD_DECLARE_OBJC_CLASS(UI_item_m);
#endif #endif
#define PUSH_UI_ITEM(item) push_ui_item(&item) #define PUSH_UI_ITEM(item) push_ui_item(&item)
@@ -75,15 +72,15 @@ class Simulator_base : public QObject
* @param interval The interval of the timer (default is 100ms) * @param interval The interval of the timer (default is 100ms)
* @param parent The parent QObject * @param parent The parent QObject
*/ */
Simulator_base(std::string name, Communication *comms, Simulator_base(QString name, Communication *comms,
std::chrono::milliseconds interval = std::chrono::milliseconds(100), QObject *parent = nullptr); std::chrono::milliseconds interval = std::chrono::milliseconds(100), QObject *parent = nullptr);
/** /**
* @brief Returns the name of the simulator * @brief Returns the name of the simulator
* *
* @return std::string The name of the simulator * @return QString The name of the simulator
*/ */
std::string name() const; QString name() const;
/** /**
* @brief This function adds a UI item to the simulator * @brief This function adds a UI item to the simulator
@@ -98,7 +95,7 @@ class Simulator_base : public QObject
* *
* @return json The UI items in json format * @return json The UI items in json format
*/ */
json get_UI_items() const; QList<UI_item_m> get_UI_items() const;
/** /**
* @brief Get the UI item object by id * @brief Get the UI item object by id
@@ -112,20 +109,11 @@ class Simulator_base : public QObject
* @brief Get the id of a UI item by pointer * @brief Get the id of a UI item by pointer
* *
* @param ptr A pointer to the UI item * @param ptr A pointer to the UI item
* @return size_t The id of the UI item, or -1 if not found * @return qsizetype The id of the UI item, or -1 if not found
*/ */
size_t ptr_to_id(UI_item *ptr) const qsizetype ptr_to_id(UI_item *ptr) const
{ {
size_t id = 0; return m_UI_items.indexOf(ptr);
while (id < m_UI_items.size())
{
if (m_UI_items[id] == ptr)
{
return id;
}
id++;
}
return (size_t)-1;
} }
/** /**
@@ -196,12 +184,12 @@ class Simulator_base : public QObject
* @brief The name of the simulator * @brief The name of the simulator
* *
*/ */
std::string m_name; QString m_name;
/** /**
* @brief The UI items of the simulator * @brief The UI items of the simulator
* *
*/ */
std::vector<UI_item *> m_UI_items; QList<UI_item *> m_UI_items;
/** /**
* @brief The timer for the simulator * @brief The timer for the simulator
* *
+41 -50
View File
@@ -7,7 +7,6 @@
#include <QDirIterator> #include <QDirIterator>
#include <QLibrary> #include <QLibrary>
#include <QThread> #include <QThread>
#include <unordered_set>
typedef Simulator_base *(*Get_Sim)(Communication *, QObject *); typedef Simulator_base *(*Get_Sim)(Communication *, QObject *);
@@ -71,17 +70,17 @@ Simulators::Simulators(uint16_t port, QStringList can_devs, QStringList uart_dev
lib.unload(); lib.unload();
continue; continue;
} }
m_simulators.insert(std::make_pair(widget->name(), widget)); m_simulators.insert(widget->name(), widget);
} }
// Insert Debug sims here // Insert Debug sims here
// INSERT_SIMULATOR(TEST_SIM); // INSERT_SIMULATOR(TEST_SIM);
connect(m_server, &Websocket::on_message, this, [this](QWebSocket *conn, QString message) { connect(m_server, &Websocket::on_binary_message, this, [this](QWebSocket *conn, QByteArray message) {
QString response = message_parser(message); QByteArray response = message_parser(message);
if (response == "{}") if (response.isEmpty())
return; return;
m_server->send(conn, response); m_server->send_binary(conn, response);
}); });
} }
@@ -89,7 +88,7 @@ Simulators::~Simulators()
{ {
} }
std::string Simulators::active_simulator_name() const QString Simulators::active_simulator_name() const
{ {
return this->m_current_simulator; return this->m_current_simulator;
} }
@@ -101,14 +100,14 @@ void Simulators::start()
SPDLOG_WARN("No simulators found"); SPDLOG_WARN("No simulators found");
return; return;
} }
if (this->m_current_simulator.empty()) if (this->m_current_simulator.isEmpty())
{ {
SPDLOG_WARN("No active simulator"); SPDLOG_WARN("No active simulator");
return; return;
} }
m_before = this->m_simulators.at(m_current_simulator)->get_UI_items(); m_before = this->m_simulators.value(m_current_simulator)->get_UI_items();
this->m_simulators.at(m_current_simulator)->start(); this->m_simulators.value(m_current_simulator)->start();
} }
void Simulators::stop() void Simulators::stop()
@@ -118,16 +117,16 @@ void Simulators::stop()
SPDLOG_WARN("No simulators found"); SPDLOG_WARN("No simulators found");
return; return;
} }
if (this->m_current_simulator.empty()) if (this->m_current_simulator.isEmpty())
{ {
SPDLOG_WARN("No active simulator"); SPDLOG_WARN("No active simulator");
return; return;
} }
this->m_simulators.at(m_current_simulator)->stop(); this->m_simulators.value(m_current_simulator)->stop();
} }
void Simulators::switch_simulator(std::string name) void Simulators::switch_simulator(QString name)
{ {
if (this->m_simulators.empty()) if (this->m_simulators.empty())
{ {
@@ -136,29 +135,31 @@ void Simulators::switch_simulator(std::string name)
} }
if (this->m_simulators.find(name) == this->m_simulators.end()) if (this->m_simulators.find(name) == this->m_simulators.end())
{ {
SPDLOG_WARN("Simulator {} not found", name); SPDLOG_WARN("Simulator {} not found", name.toStdString());
return; return;
} }
if (!this->m_current_simulator.empty()) if (!this->m_current_simulator.isEmpty())
{ {
SPDLOG_INFO("Stopping current simulator {} and switching to {}", m_current_simulator, name); SPDLOG_INFO("Stopping current simulator {} and switching to {}", m_current_simulator.toStdString(), name.toStdString());
this->m_simulators.at(m_current_simulator)->stop(); this->m_simulators.value(m_current_simulator)->stop();
disconnect(m_simulators.at(m_current_simulator).get()); disconnect(m_simulators.value(m_current_simulator));
} }
this->m_current_simulator = name; this->m_current_simulator = name;
connect( connect(
m_simulators.at(m_current_simulator).get(), &Simulator_base::sim_changed, this, m_simulators.value(m_current_simulator), &Simulator_base::sim_changed, this,
[this] { [this] {
auto json = changed_UI_items(); auto changed = changed_UI_items();
if (!json.empty()) UI_items_m items;
items.setItem(changed);
if (!changed.isEmpty())
{ {
m_server->broadcast(QString::fromStdString(json.dump())); m_server->broadcast_binary(m_serializer.serialize(&items));
} }
}, },
Qt::QueuedConnection); Qt::QueuedConnection);
connect(m_simulators.at(m_current_simulator).get(), &Simulator_base::log_signal, this, connect(m_simulators.value(m_current_simulator), &Simulator_base::log_signal, this,
[](const char *filename_in, int line_in, const char *funcname_in, int level, QString msg) { [](const char *filename_in, int line_in, const char *funcname_in, int level, QString msg) {
if (spdlog::default_logger_raw()->should_log((spdlog::level::level_enum)level)) if (spdlog::default_logger_raw()->should_log((spdlog::level::level_enum)level))
spdlog::default_logger_raw()->log(spdlog::source_loc{filename_in, line_in, funcname_in}, spdlog::default_logger_raw()->log(spdlog::source_loc{filename_in, line_in, funcname_in},
@@ -167,19 +168,14 @@ void Simulators::switch_simulator(std::string name)
this->start(); this->start();
} }
std::vector<std::string> Simulators::list_simulators() const QList<QString> Simulators::list_simulators() const
{ {
std::vector<std::string> names; return this->m_simulators.keys();
for (const auto &simulator : this->m_simulators)
{
names.push_back(simulator.first);
}
return names;
} }
bool Simulators::is_not_active() const bool Simulators::is_not_active() const
{ {
return this->m_current_simulator.empty(); return this->m_current_simulator.isEmpty();
} }
Simulator_base *Simulators::invoke_active_simulator() Simulator_base *Simulators::invoke_active_simulator()
@@ -189,45 +185,40 @@ Simulator_base *Simulators::invoke_active_simulator()
{ {
return nullptr; return nullptr;
} }
if (this->m_current_simulator.empty()) if (this->m_current_simulator.isEmpty())
{ {
return nullptr; return nullptr;
} }
m_before = this->m_simulators.at(m_current_simulator)->get_UI_items(); m_before = this->m_simulators.value(m_current_simulator)->get_UI_items();
return this->m_simulators.at(m_current_simulator).get(); return this->m_simulators.value(m_current_simulator);
} }
json Simulators::changed_UI_items() QList<UI_item_m> Simulators::changed_UI_items()
{ {
std::lock_guard<std::mutex> lock(m_mutex); std::lock_guard<std::mutex> lock(m_mutex);
QList<UI_item_m> ret;
if (this->m_simulators.empty() || this->m_current_simulator.empty()) if (this->m_simulators.empty() || this->m_current_simulator.isEmpty())
return "{}"_json; return ret;
json after = this->m_simulators.at(m_current_simulator)->get_UI_items(); auto after = this->m_simulators.value(m_current_simulator)->get_UI_items();
// Fast path: nothing at all changed // Fast path: nothing at all changed
if (after == m_before) if (after == m_before)
return "{}"_json; return ret;
json changed; const qsizetype count = after.size();
changed["event"]["type"] = "ui_changed"; for (qsizetype i = 0; i < count; ++i)
const auto &ui_items = after["UI_items"];
const auto &prev_ui_items = m_before["UI_items"]; // may be null on first call
const size_t count = ui_items.size();
for (size_t i = 0; i < count; ++i)
{ {
// If item is new or any field changed -> send full current item // If item is new or any field changed -> send full current item
if (i >= prev_ui_items.size() || ui_items[i] != prev_ui_items[i]) if (i >= m_before.size() || after[i] != m_before[i])
{ {
changed["event"]["UI_items"].push_back(ui_items[i]); ret.push_back(after[i]);
} }
} }
m_before = std::move(after); m_before = std::move(after);
return changed; return ret;
} }
+17 -16
View File
@@ -1,9 +1,10 @@
#pragma once #pragma once
#include <QObject> #include <QObject>
#include <map> #include <QMap>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include <nlohmann/json.hpp> #include <QProtobufSerializer>
#include <messages.qpb.h>
#define INSERT_SIMULATOR(type) \ #define INSERT_SIMULATOR(type) \
m_simulators.insert(std::make_pair(type(&m_com).name(), std::make_unique<type>(&m_com, this))); m_simulators.insert(std::make_pair(type(&m_com).name(), std::make_unique<type>(&m_com, this)));
@@ -14,8 +15,7 @@ Q_FORWARD_DECLARE_OBJC_CLASS(CAN_Wrapper);
Q_FORWARD_DECLARE_OBJC_CLASS(QSerialPort); Q_FORWARD_DECLARE_OBJC_CLASS(QSerialPort);
Q_FORWARD_DECLARE_OBJC_CLASS(Simulator_base); Q_FORWARD_DECLARE_OBJC_CLASS(Simulator_base);
Q_FORWARD_DECLARE_OBJC_CLASS(Communication); Q_FORWARD_DECLARE_OBJC_CLASS(Communication);
Q_FORWARD_DECLARE_OBJC_CLASS(UI_item_m);
using json = nlohmann::json;
/** /**
* @brief Class managing all simulators * @brief Class managing all simulators
@@ -75,9 +75,9 @@ class Simulators : public QObject
/** /**
* @brief Get the name of the active simulator * @brief Get the name of the active simulator
* *
* @return std::string The name of the active simulator * @return QString The name of the active simulator
*/ */
std::string active_simulator_name() const; QString active_simulator_name() const;
/** /**
* @brief Start the active simulator * @brief Start the active simulator
* *
@@ -93,13 +93,13 @@ class Simulators : public QObject
* *
* @param name The name of the simulator to switch to * @param name The name of the simulator to switch to
*/ */
void switch_simulator(std::string name); void switch_simulator(QString name);
/** /**
* @brief List all available simulators * @brief List all available simulators
* *
* @return std::vector<std::string> A list of simulator names * @return std::vector<QString> A list of simulator names
*/ */
std::vector<std::string> list_simulators() const; QList<QString> list_simulators() const;
/** /**
* @brief Check if no simulator is active * @brief Check if no simulator is active
* *
@@ -120,7 +120,7 @@ class Simulators : public QObject
* *
* @return json The changed UI items * @return json The changed UI items
*/ */
json changed_UI_items(); QList<UI_item_m> changed_UI_items();
// Functions in message_parser.cpp // Functions in message_parser.cpp
/** /**
@@ -129,27 +129,28 @@ class Simulators : public QObject
* @param message The message to parse * @param message The message to parse
* @return QString The parsed message * @return QString The parsed message
*/ */
QString message_parser(QString message); QByteArray message_parser(QByteArray message);
/** /**
* @brief Parse a command in json format * @brief Parse a command in json format
* *
* @param command The command to parse * @param command The command to parse
* @return json The parsed command * @return json The parsed command
*/ */
json command_parser(json command); //json command_parser(json command);
/** /**
* @brief Handle an event in json format * @brief Handle an event in json format
* *
* @param event The event to handle * @param event The event to handle
*/ */
void event_handler(json event); void event_handler(Event_m event);
private: private:
QThread *m_server_thread; QThread *m_server_thread;
Websocket *m_server; Websocket *m_server;
Communication *m_com; Communication *m_com;
std::map<std::string, std::unique_ptr<Simulator_base>> m_simulators; QMap<QString, Simulator_base*> m_simulators;
std::string m_current_simulator = ""; QString m_current_simulator = "";
std::mutex m_mutex; std::mutex m_mutex;
json m_before; QList<UI_item_m> m_before;
QProtobufSerializer m_serializer;
}; };
+6 -6
View File
@@ -5,10 +5,10 @@ EXPORT_SIM(Test_Sim);
Test_Sim::Test_Sim(Communication *com, QObject *parent) Test_Sim::Test_Sim(Communication *com, QObject *parent)
: Simulator_base("Test Sim", com, std::chrono::milliseconds(1000), parent), : Simulator_base("Test Sim", com, std::chrono::milliseconds(1000), parent),
m_button("Off", Color::White, Color::Red), m_button("Off", Color::White, Color::Red),
m_combobox(Color::White, Color::Black, {"Option 1", "Option 2", "Option 3"}, 0), m_combobox({"Option 1", "Option 2", "Option 3"}, 0),
m_label("Label", Color::White, Color::Black), m_checkbox("Option 1", Color::Default, Color::Default), m_label("Label", Color::White, Color::Black), m_checkbox("Option 1", Color::Default, Color::Default),
m_slider("Slider", Color::White, Color::Black, 0, 100, 0), m_dial("Dial", Color::White, Color::Black, 0, 100, 0), m_slider("Slider", 0, 100, 0), m_dial("Dial", 0, 100, 0),
m_thermo("Thermo", "%", Color::White, Color::Black, 0, 100, 0), m_led("Led", Color::White, Color::Red), m_thermo("Thermo", "%", 0, 100, 0), m_led("Led", Color::White, Color::Red),
m_table(4, 4, {"Row 1", "Row 2", "Row 3", "Row 4"}, {"Column 1", "Column 2", "Column 3", "Column 4"}), m_table(4, 4, {"Row 1", "Row 2", "Row 3", "Row 4"}, {"Column 1", "Column 2", "Column 3", "Column 4"}),
m_spinbox(0, 255, 0), m_double_spinbox(0, 255, 0), m_hex_spinbox(0, 255, 0), m_spinbox(0, 255, 0), m_double_spinbox(0, 255, 0), m_hex_spinbox(0, 255, 0),
m_tab_widget({"Tab 1", "Tab 2", "Tab 3"}, 0), m_stacked_widget(3, 0), m_status_bar() m_tab_widget({"Tab 1", "Tab 2", "Tab 3"}, 0), m_stacked_widget(3, 0), m_status_bar()
@@ -39,7 +39,7 @@ Test_Sim::Test_Sim(Communication *com, QObject *parent)
for (size_t i = 0; i < m_table.capacity(); i++) for (size_t i = 0; i < m_table.capacity(); i++)
{ {
m_table.insert_item(i / 4, i % 4, QString("%0 %1").arg(i / 4).arg(i % 4).toStdString()); m_table.insert_item(i / 4, i % 4, QString("%0 %1").arg(i / 4).arg(i % 4));
} }
QObject::connect(&m_button, &UI_button::clicked, this, [=, this] { button_clicked(&m_button); }); QObject::connect(&m_button, &UI_button::clicked, this, [=, this] { button_clicked(&m_button); });
@@ -87,14 +87,14 @@ void Test_Sim::slider_changed(UI_slider *id, double value)
if (id == &m_slider) if (id == &m_slider)
{ {
LOG_INFO(QString("Test slider changed to %0").arg(value)); LOG_INFO(QString("Test slider changed to %0").arg(value));
m_label.set_text(std::to_string(value)); m_label.set_text(QString::number(value));
m_dial.set_value(value); m_dial.set_value(value);
m_thermo.set_value(value); m_thermo.set_value(value);
m_plot.add_value(value); m_plot.add_value(value);
m_spinbox.set_value(value); m_spinbox.set_value(value);
m_double_spinbox.set_value(value); m_double_spinbox.set_value(value);
m_hex_spinbox.set_value(value); m_hex_spinbox.set_value(value);
m_status_bar.show_message("Test slider changed to " + std::to_string(value)); m_status_bar.show_message("Test slider changed to " + QString::number(value));
return; return;
} }
} }
+23 -3
View File
@@ -60,7 +60,15 @@ Websocket::~Websocket()
qDeleteAll(m_clients.begin(), m_clients.end()); qDeleteAll(m_clients.begin(), m_clients.end());
} }
void Websocket::broadcast(QString message) void Websocket::broadcast_binary(QByteArray message)
{
foreach (QWebSocket *conn, m_clients)
{
conn->sendBinaryMessage(message);
}
}
void Websocket::broadcast_text(QString message)
{ {
foreach (QWebSocket *conn, m_clients) foreach (QWebSocket *conn, m_clients)
{ {
@@ -68,7 +76,12 @@ void Websocket::broadcast(QString message)
} }
} }
void Websocket::send(QWebSocket *conn, QString message) void Websocket::send_binary(QWebSocket *conn, QByteArray message)
{
conn->sendBinaryMessage(message);
}
void Websocket::send_text(QWebSocket *conn, QString message)
{ {
conn->sendTextMessage(message); conn->sendTextMessage(message);
} }
@@ -77,16 +90,23 @@ void Websocket::onNewConnection()
{ {
QWebSocket *pSocket = m_pWebSocketServer->nextPendingConnection(); QWebSocket *pSocket = m_pWebSocketServer->nextPendingConnection();
connect(pSocket, &QWebSocket::binaryMessageReceived, this, &Websocket::processBinaryMessage);
connect(pSocket, &QWebSocket::textMessageReceived, this, &Websocket::processTextMessage); connect(pSocket, &QWebSocket::textMessageReceived, this, &Websocket::processTextMessage);
connect(pSocket, &QWebSocket::disconnected, this, &Websocket::socketDisconnected); connect(pSocket, &QWebSocket::disconnected, this, &Websocket::socketDisconnected);
m_clients << pSocket; m_clients << pSocket;
} }
void Websocket::processBinaryMessage(QByteArray message)
{
QWebSocket *pClient = qobject_cast<QWebSocket *>(sender());
emit on_binary_message(pClient, message);
}
void Websocket::processTextMessage(QString message) void Websocket::processTextMessage(QString message)
{ {
QWebSocket *pClient = qobject_cast<QWebSocket *>(sender()); QWebSocket *pClient = qobject_cast<QWebSocket *>(sender());
emit on_message(pClient, message); emit on_text_message(pClient, message);
} }
void Websocket::socketDisconnected() void Websocket::socketDisconnected()
+7 -3
View File
@@ -41,14 +41,16 @@ class Websocket : public QObject
* *
* @param message The message to send * @param message The message to send
*/ */
void broadcast(QString message); void broadcast_binary(QByteArray message);
void broadcast_text(QString message);
/** /**
* @brief Send a message to a specific client * @brief Send a message to a specific client
* *
* @param conn The client connection * @param conn The client connection
* @param message The message to send * @param message The message to send
*/ */
void send(QWebSocket *conn, QString message); void send_binary(QWebSocket *conn, QByteArray message);
void send_text(QWebSocket *conn, QString message);
signals: signals:
/** /**
* @brief Signal emitted when a message is received from a client * @brief Signal emitted when a message is received from a client
@@ -56,7 +58,8 @@ class Websocket : public QObject
* @param conn The client connection * @param conn The client connection
* @param message The received message * @param message The received message
*/ */
void on_message(QWebSocket *conn, QString message); void on_binary_message(QWebSocket *conn, QByteArray message);
void on_text_message(QWebSocket *conn, QString message);
/** /**
* @brief Signal emitted when the server is closed * @brief Signal emitted when the server is closed
* *
@@ -74,6 +77,7 @@ class Websocket : public QObject
* *
* @param message The received message * @param message The received message
*/ */
void processBinaryMessage(QByteArray message);
void processTextMessage(QString message); void processTextMessage(QString message);
/** /**
* @brief Private Slot called when a client disconnects * @brief Private Slot called when a client disconnects