Skip to content
Snippets Groups Projects
Select Git revision
  • lyra-ipv4ll-backport
  • main default protected
  • dev-smart-pointer-refactor-2
  • topics
  • outgoingmessagesviewer
  • qt6
  • dev-smart-pointer-refactor
  • gse-interface-dev
  • crash-report-dev
  • riccardo-dev
  • roccaraso2024
  • euroc2024
  • euroc2023
  • roccaraso2023
  • euroc-2021
15 results

OutgoingMessagesViewerModule.cpp

Blame
  • OutgoingMessagesViewerModule.cpp 6.53 KiB
    /*
     * This file is part of Skyward Hub.
     *
     * Skyward Hub is free software: you can redistribute it and/or modify it under
     * the terms of the GNU General Public License as published by the Free Software
     * Foundation, either version 3 of the License, or (at your option) any later
     * version.
     *
     * Skyward Hub is distributed in the hope that it will be useful, but WITHOUT
     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
     * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
     * details.
     *
     * You should have received a copy of the GNU General Public License along with
     * Skyward Hub. If not, see <https://www.gnu.org/licenses/>.
     *
     */
    
    #include "OutgoingMessagesViewerModule.h"
    
    #include <Core/MessageBroker/MessageBroker.h>
    #include <Modules/SkywardHubStrings.h>
    
    #include <QDebug>
    #include <QTableWidgetItem>
    
    OutgoingMessagesViewerModule::OutgoingMessagesViewerModule(QWidget* parent)
        : DefaultModule(parent)
    {
        setupUi();
        defaultContextMenuSetup();
    
        // Subscribe to commands, ACKs and NACKs
        getCore()->getMessageBroker()->subscribe(
            Filter::fromString(SkywardHubStrings::logCommandsTopic), this,
            [this](const Message& message, const Filter& filter)
            { handleMsg(message); });
        getCore()->getMessageBroker()->subscribe(
            Filter::fromString(SkywardHubStrings::mavlink_received_msg_ACK_topic),
            this, [this](const Message& message, const Filter& filter)
            { handleAck(message); });
        MessageBroker::getInstance().subscribe(
            Filter::fromString(SkywardHubStrings::mavlink_received_msg_NACK_topic),
            this, [this](const Message& message, const Filter& filter)
            { handleNack(message); });
        MessageBroker::getInstance().subscribe(
            Filter::fromString(SkywardHubStrings::mavlink_received_msg_WACK_topic),
            this, [this](const Message& message, const Filter& filter)
            { handleWack(message); });
    }
    
    QWidget* OutgoingMessagesViewerModule::toWidget() { return this; }
    
    XmlObject OutgoingMessagesViewerModule::toXmlObject()
    {
        return XmlObject(getName(ModuleId::OUTCOMINGMESSAGEVIEWER));
    }
    
    void OutgoingMessagesViewerModule::fromXmlObject(const XmlObject& xmlObject)
    {
        Q_UNUSED(xmlObject);
    }
    
    void OutgoingMessagesViewerModule::setupUi()
    {
        QHBoxLayout* outerLayout = new QHBoxLayout;
        outerLayout->setContentsMargins(0, 0, 0, 0);
    
        table = new QTableWidget;
        outerLayout->addWidget(table);
        table->setColumnCount(2);
        table->verticalHeader()->setVisible(false);
        table->horizontalHeader()->setVisible(false);
        table->horizontalHeader()->setSectionResizeMode(
            0, QHeaderView::ResizeToContents);
        table->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch);
        table->verticalScrollBar()->setVisible(false);
        table->setSelectionMode(QAbstractItemView::NoSelection);
    
        setLayout(outerLayout);
    }
    
    void OutgoingMessagesViewerModule::resizeEvent(QResizeEvent* event)
    {
        if (table->rowCount() == 0)
        {
            return;
        }
    
        int totalHeight   = table->viewport()->height();
        int contentHeight = table->rowCount() * table->rowHeight(0);
    
        if (contentHeight <= totalHeight)
        {
            // Calculate how many rows can fit in the available space
            int rowsToAdd = (totalHeight - contentHeight) / table->rowHeight(0);
    
            // Calculate how many messages are available and not shown
            int rowsAvailable = messages.count() - table->rowCount();
    
            // Add rows to fill the available space
            for (int i = 0; i < std::min(rowsToAdd, rowsAvailable); i++)
            {
                addMessageToTable(messages.at(table->rowCount()),
                                  table->rowCount());
            }
        }
        else
        {
            // Calculate how many rows need to be removed
            int rowsToRemove =
                (contentHeight - totalHeight) / table->rowHeight(0) + 1;
    
            // Remove rows that don't fit
            int newRowCount = table->rowCount() - rowsToRemove;
            table->setRowCount(newRowCount);
        }
    }
    
    void OutgoingMessagesViewerModule::handleMsg(const Message& msg)
    {
        // First register the message into the list
        messages.prepend({QDateTime::currentDateTime(), msg});
    
        // Check if the list is overgrowing
        if (messages.count() > maxListSize)
        {
            messages.removeLast();
        }
    
        // Insert the message into the table
        addMessageToTable(messages.first());
    
        // Update the table size
        resizeEvent();
    }
    
    void OutgoingMessagesViewerModule::handleAck(const Message& ack)
    {
        // Color the message the ack is for with green background
        for (int i = 0; i < messages.count(); i++)
        {
            Message msg = messages.at(i).second;
    
            if (msg.getField("message_id") == ack.getField("recv_msgid") &&
                msg.getField("sequence_number") == ack.getField("seq_ack"))
            {
                if (table->rowCount() > i)
                {
                    table->item(i, 1)->setBackground(QBrush(QColor(0, 255, 0)));
                }
            }
        }
    }
    
    void OutgoingMessagesViewerModule::handleNack(const Message& nack)
    {
        // Color the message the nack is for with red background
        for (int i = 0; i < messages.count(); i++)
        {
            Message msg = messages.at(i).second;
    
            if (msg.getField("message_id") == nack.getField("recv_msgid") &&
                msg.getField("sequence_number") == nack.getField("seq_ack"))
            {
                if (table->rowCount() > i)
                {
                    table->item(i, 1)->setBackground(QBrush(QColor(255, 0, 0)));
                }
            }
        }
    }
    
    void OutgoingMessagesViewerModule::handleWack(const Message& nack)
    {
        // Color the message the wack is for with white background
        for (int i = 0; i < messages.count(); i++)
        {
            Message msg = messages.at(i).second;
    
            if (msg.getField("message_id") == nack.getField("recv_msgid") &&
                msg.getField("sequence_number") == nack.getField("seq_ack"))
            {
                if (table->rowCount() > i)
                {
                    table->item(i, 1)->setBackground(QBrush(QColor(255, 255, 255)));
                }
            }
        }
    }
    
    void OutgoingMessagesViewerModule::addMessageToTable(
        const QPair<QDateTime, Message>& msg, int row)
    {
        // Prepare the row items
        auto dateTxt = new QTableWidgetItem(msg.first.toString("hh.mm.ss"));
        auto msgName = new QTableWidgetItem(msg.second.getField("name").toString());
        msgName->setBackground(QBrush(QColor(80, 80, 80)));
        msgName->setForeground(QBrush(QColor(0, 0, 0)));
    
        // Add a new row
        table->insertRow(row);
    
        // Fill the row with data
        table->setItem(row, 0, dateTxt);
        table->setItem(row, 1, msgName);
    }