Newer
Older
powermon_manager_sw / gui / gui_chart.cpp
@Razvan Turiac Razvan Turiac on 8 Jul 5 KB Initial import
/* Copyright (C) 2020 - 2024, Thornwave Labs Inc
 * Written by Razvan Turiac <razvan.turiac@thornwave.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 
 * documentation files (the “Software”), to deal in the Software without restriction, including without limitation 
 * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 * Attribution shall be given to Thornwave Labs Inc. and shall be made visible to the final user. 
 * 
 * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 
 * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#include <string.h>

#include <gui_app.h>
#include <gui_chart.h>

#include <model.h>

#include <math.h>

#include <resources/img_thornwave_icon_png.cpp>


GuiChart::GuiChart(wxWindow *parent, const wxString &title): wxFrame(parent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, wxMINIMIZE_BOX | wxMAXIMIZE_BOX | wxRESIZE_BORDER | wxSYSTEM_MENU | wxCAPTION | wxCLOSE_BOX | wxCLIP_CHILDREN)
{
	wxBitmap icon_bmp = wxBITMAP_PNG_FROM_DATA(img_thornwave_icon);

	wxIcon icon;
	icon.CopyFromBitmap(icon_bmp);
	SetIcon(icon);

	//main window sizer & panel
	wxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL);
	SetSizer(main_sizer);
	
	mScopeDisplay = new ScopeDisplay(this, wxID_ANY, wxDefaultPosition, FromDIP(wxSize(800, 600)));
	mScopeDisplay->setListener(this);

	std::vector<uint64_t> scales;
	//scales.push_back((uint64_t)1000 * 1000 * 30);	//30 seconds / div
	scales.push_back((uint64_t)1000 * 1000 * 60 * 1);	//1 minute / div
	scales.push_back((uint64_t)1000 * 1000 * 60 * 2);	//2 minutes / div
	scales.push_back((uint64_t)1000 * 1000 * 60 * 5);	//5 minutes / div
	scales.push_back((uint64_t)1000 * 1000 * 60 * 10);	//10 minutes / div
	scales.push_back((uint64_t)1000 * 1000 * 60 * 20);	//20 minutes / div
	scales.push_back((uint64_t)1000 * 1000 * 60 * 30);	//30 minutes / div
	scales.push_back((uint64_t)1000 * 1000 * 60 * 60 * 1);	//1 hour / div
	scales.push_back((uint64_t)1000 * 1000 * 60 * 60 * 2);	//2 hours / div
	scales.push_back((uint64_t)1000 * 1000 * 60 * 60 * 6);	//6 hours / div
	scales.push_back((uint64_t)1000 * 1000 * 60 * 60 * 12);	//12 hours / div
	scales.push_back((uint64_t)1000 * 1000 * 60 * 60 * 24 * 1);	//1 day / div
	scales.push_back((uint64_t)1000 * 1000 * 60 * 60 * 24 * 2);	//2 day / div
	scales.push_back((uint64_t)1000 * 1000 * 60 * 60 * 24 * 7);	//7 day / div

	mScopeDisplay->SetTimeScales(scales, 6);
	
	main_sizer->Add(mScopeDisplay, 1, wxALL | wxEXPAND, FromDIP(6));

	main_sizer->SetSizeHints(this);
	Centre();
	
	Bind(wxEVT_CLOSE_WINDOW, &GuiChart::OnClose, this);
	
	mScopeDisplay->addWaveform(wxT("Voltage 1"), wxT("V"), wxT("V"), 5);
	mScopeDisplay->addWaveform(wxT("Voltage 2"), wxT("V"), wxT("V"), 5);
	mScopeDisplay->addWaveform(wxT("Current"), wxT("I"), wxT("A"), 5);
	mScopeDisplay->addWaveform(wxT("Power"), wxT("P"), wxT("W"), 5);
	mScopeDisplay->addWaveform(wxT("Temperature"), wxT("T"), wxT("\u00B0C"), 5);
	mScopeDisplay->addWaveform(wxT("SoC"), wxT("%"), wxT("%"), 10);
}



GuiChart::~GuiChart()
{
}


void GuiChart::update(void)
{
	const auto &log_data = Model::getInstance().logData;

	mScopeDisplay->setMinTime((uint64_t)log_data.front().time * 1000000);
	mScopeDisplay->setMaxTime((uint64_t)log_data.back().time * 1000000);
	mScopeDisplay->EndTimePos();
}


void GuiChart::OnClose(wxCloseEvent &event)
{
	Hide();
}


void GuiChart::getChartData(uint64_t start_time, uint64_t last_time, size_t point_count, std::vector<DataVector> &data)
{
	const auto &log_data = Model::getInstance().logData;

	for(auto &d: data)
		d = std::vector<float>(point_count, NAN);

	start_time = start_time / 1000000;
	last_time = (last_time + 999999) / 1000000;

	const uint32_t step = (last_time - start_time) / point_count;
	uint64_t time = start_time + step;

	uint32_t count = 0;
	std::vector<float> avg(data.size(), 0);

	std::vector<PowermonLogFile::Sample>::const_iterator it = std::find_if(log_data.begin(), log_data.end(), [start_time](const PowermonLogFile::Sample &sample)
	{
		return sample.time >= start_time;
	});

	uint32_t pos;
	for(pos = 0; pos < point_count && (it != log_data.end()); it++)
	{
		if (it->time < time)
		{
			avg[0] += it->voltage1;
			avg[1] += it->voltage2;
			avg[2] += it->current;
			avg[3] += it->power;
			avg[4] += it->temperature;
			avg[5] += (it->soc <= 100) ? it->soc : NAN;

			count++;
		}
		else
		{
			if (count)
			{
				uint32_t i = 0;
				for(auto &a: avg)
				{
					a /= count;
					data[i++][pos] = a;
				}
				pos++;
			}

			avg[0] = it->voltage1;
			avg[1] = it->voltage2;
			avg[2] = it->current;
			avg[3] = it->power;
			avg[4] = it->temperature;
			avg[5] = (it->soc <= 100) ? it->soc : NAN;

			count = 1;
			time += step;
		}
	}
}


	
BEGIN_EVENT_TABLE(GuiChart, wxFrame)
END_EVENT_TABLE()