/*
* FeitCSI is the tool for extracting CSI information from supported intel NICs.
* Copyright (C) 2024 Miroslav Hutar.
*
* This program 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.
*
* This program 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 this program. If not, see .
*/
#include "Plot.h"
#include "Arguments.h"
#include "Logger.h"
#include "WiFiCsiController.h"
#include
#include
#include
void Plot::init()
{
signal_draw().connect(sigc::mem_fun(*this, &Plot::on_draw));
}
void Plot::init(Glib::RefPtr box)
{
this->yTicks = this->yTicksMin >= 0 ? this->yTicksMax : this->yTicksMax + (this->yTicksMin * -1);
signal_draw().connect(sigc::mem_fun(*this, &Plot::on_draw));
box->pack_start(*this);
show();
}
void Plot::updateData(Csi *csi, std::vector *data)
{
this->csi = csi;
this->data = data;
queue_draw();
}
bool Plot::on_draw(const Cairo::RefPtr &cr)
{
Gtk::Allocation allocation = get_allocation();
const int width = allocation.get_width();
const int height = allocation.get_height();
const double offset = 50;
const double xTicks = csi ? csi->numSubCarriers : 56;
bool redraw = false;
// Set background color
cr->set_source_rgb(1.0, 1.0, 1.0); // White
cr->paint();
// Draw x and y axis
cr->set_source_rgb(0.0, 0.0, 0.0); // Black
cr->set_line_width(1.0);
cr->move_to(offset, offset);
cr->line_to(offset, height - offset);
cr->line_to(width - offset, height - offset);
cr->stroke();
// Calculate the scaling factor for data points to fit in the drawing area
double xScale = (width - 2 * offset) / (xTicks - 1);
double yScale = (height - 2 * offset) / yTicks;
// Draw tick text
const int perXTick = xTicks / 8;
for (int i = 0; i < xTicks; i = i + perXTick)
{
double x = i * xScale + offset;
cr->set_source_rgb(0, 0, 0);
cr->move_to(x, height - 40);
cr->show_text(std::to_string((i + 1)));
// Draw grid lines
cr->set_source_rgb(0.8, 0.7, 0.7); // Light gray
cr->move_to(x, offset);
cr->line_to(x, height - offset);
cr->stroke();
}
const int perYTick = yTicks > 8 ? yTicks / 8 : 1;
for (int i = 0; i <= yTicks; i = i + perYTick)
{
double y = height - offset - i * (height - 100) / yTicks;
cr->set_source_rgb(0, 0, 0);
cr->move_to(30, y);
cr->show_text(std::to_string((int)(this->yTicksMin < 0 ? i + this->yTicksMin : i)));
// Draw grid lines
cr->set_source_rgb(0.8, 0.8, 0.8); // Light gray
cr->move_to(offset, y);
cr->line_to(width - offset, y);
cr->stroke();
}
if (csi)
{
// Draw the line chart
int colorNumber = 0;
uint32_t index = 0;
for (uint32_t rx = 0; rx < csi->numRx; rx++)
{
for (uint32_t tx = 0; tx < csi->numTx; tx++)
{
cr->set_source_rgb(colors[colorNumber][0], colors[colorNumber][1], colors[colorNumber][2]); // Black color
cr->set_line_width(2.0);
cr->move_to(offset, (height - offset) - (this->yTicksMin < 0 ? ((this->yTicksMin * -1) + (*this->data)[0]) : (*this->data)[0]) * yScale);
for (uint32_t n = 0; n < csi->numSubCarriers; n++)
{
double x = n * xScale + offset;
double y = (height - offset) - (this->yTicksMin < 0 ? ((this->yTicksMin * -1) + (*this->data)[index]) : (*this->data)[index]) * yScale;
if ((*this->data)[index] > this->yTicks)
{
this->yTicks = (*this->data)[index];
redraw = true;
}
cr->line_to(x, y);
index++;
}
cr->stroke();
colorNumber++;
}
}
if (redraw)
{
return this->on_draw(cr);
}
// Draw legend
colorNumber = 0;
cr->move_to(offset * 2, offset - 10);
for (uint32_t rx = 0; rx < csi->numRx; rx++)
{
for (uint32_t tx = 0; tx < csi->numTx; tx++)
{
cr->set_source_rgb(colors[colorNumber][0], colors[colorNumber][1], colors[colorNumber][2]); // Black color
cr->show_text(std::string("RX" + std::to_string(rx + 1)) + std::string("TX" + std::to_string(tx + 1)));
cr->show_text(" ");
colorNumber++;
}
}
}
// Draw x label
cr->set_source_rgb(0.0, 0.0, 0.0); // Black color
cr->move_to(width / 2, (offset / 2));
cr->show_text(this->title);
// Draw x label
cr->set_source_rgb(0.0, 0.0, 0.0); // Black color
cr->move_to(width / 2, height - (offset / 2));
cr->show_text(this->xLabel);
// Draw y label
cr->move_to((offset / 2), height / 2);
cr->rotate(-M_PI / 2); // Rotate text for y label
cr->show_text(this->yLabel);
// Draw x label
cr->set_source_rgb(0.0, 0.0, 0.0); // Black color
cr->set_font_size(30);
cr->move_to(width / 2, (offset / 2));
cr->show_text(this->title);
return true;
}