/* 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 <gui_about.h> #include <gui_dfu_progress.h> #include <version.h> #include <wx/wx.h> #include <wx/uri.h> #include <wx/sstream.h> #include <wx/mstream.h> #include <wx/protocol/http.h> #include <thread> GuiAbout::GuiAbout(wxWindow *parent, const wxString &title, Powermon &powermon): wxDialog(parent, wxID_ANY, title), mPowermon(powermon) { //main window sizer wxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL); SetSizer(main_sizer); wxString str; str.Printf(wxT("%s v%X.%02X. (C) Thornwave Labs Inc"), g_version_tag, g_version_bcd >> 8, g_version_bcd & 0xFF); main_sizer->Add(new wxStaticText(this, wxID_ANY, str), 0, wxALL | wxEXPAND, 5); str.Printf(wxT("Device name: %s"), mPowermon.getLastDeviceInfo().name); main_sizer->Add(new wxStaticText(this, wxID_ANY, str), 0, wxALL | wxEXPAND, 5); str.Printf(wxT("Device model: %s"), Powermon::getHardwareString(mPowermon.getLastDeviceInfo().hardware_revision_bcd)); main_sizer->Add(new wxStaticText(this, wxID_ANY, str), 0, wxALL | wxEXPAND, 5); str.Printf(wxT("Device serial: %016" PRIX64), mPowermon.getLastDeviceInfo().serial); main_sizer->Add(new wxStaticText(this, wxID_ANY, str), 0, wxALL | wxEXPAND, 5); uint16_t version = mPowermon.getLastDeviceInfo().firmware_version_bcd; str.Printf(wxT("Firmware: v%X.%02X"), version >> 8, version & 0xFF); main_sizer->Add(new wxStaticText(this, wxID_ANY, str), 0, wxALL | wxEXPAND, 5); if (Powermon::hasWifi(mPowermon.getLastDeviceInfo().hardware_revision_bcd)) str = wxString(wxT("Device IP Address: ")) + Powermon::getIpAddressString(mPowermon.getLastDeviceInfo().address); else str = wxString(wxT("Device Bluetooth Address: ")) + Powermon::getMacAddressString(mPowermon.getLastDeviceInfo().address); main_sizer->Add(new wxStaticText(this, wxID_ANY, str), 0, wxALL | wxEXPAND, 5); mStatusStatic = new wxStaticText(this, wxID_ANY, wxT("Checking for firmware update ...")); main_sizer->AddSpacer(20); main_sizer->Add(mStatusStatic, 0, wxALL | wxEXPAND, 5); main_sizer->AddSpacer(20); mUpdateButton = new wxButton(this, ID_BUTTON_UPDATE, wxT("Update"), wxDefaultPosition, wxSize(120, 40)); mUpdateButton->Enable(false); main_sizer->Add(mUpdateButton, 0, wxALL | wxEXPAND, 5); main_sizer->SetSizeHints(this); Centre(); mFirmwareVersionBcd = 0; std::thread download_thread([this](void) { //wxString str = Powermon::getUpdateFirmwareImageUrl(mPowermon.getLastDeviceInfo().hardware_revision_bcd, mPowermon.getLastDeviceInfo().firmware_version_bcd); wxString str = wxT("https://files.thornwave.com/fwup/pmonw/pmonw_fw_dfu_dev.bin"); wxURI uri(str); wxHTTP http; http.SetHeader("Content-type", "text/html; charset=utf-8"); http.Connect(uri.GetServer()); wxInputStream* httpStream = http.GetInputStream(uri.GetPath()); if (http.GetError() == wxPROTO_NOERR) { wxMemoryOutputStream out; httpStream->Read(out); wxStreamBuffer* httpStreamBuffer = out.GetOutputStreamBuffer(); httpStreamBuffer->Seek(0, wxFromStart); const size_t size = httpStreamBuffer->GetBufferSize(); mFirmwareImage.resize(size); if (httpStreamBuffer->Read(mFirmwareImage.data(), size) == size) mFirmwareVersionBcd = Powermon::checkFirmwareImage(mFirmwareImage.data(), mFirmwareImage.size(), mPowermon.getLastDeviceInfo().hardware_revision_bcd); } delete httpStream; http.Close(); wxQueueEvent(this, new GuiEvent([this](const GuiEvent &event) { DownloadDone(); })); }); download_thread.detach(); } GuiAbout::~GuiAbout() { } void GuiAbout::DownloadDone(void) { if (mFirmwareVersionBcd > 0 #ifndef DEBUG && mFirmwareVersionBcd > mPowermon.getLastDeviceInfo().firmware_version_bcd #endif ) { wxString str; str.Printf(wxT("Firmware update to version %X.%02X is available"), mFirmwareVersionBcd >> 8, mFirmwareVersionBcd & 0xFF); mStatusStatic->SetLabel(str); mUpdateButton->Enable(true); } else { mStatusStatic->SetLabel(wxT("No firmware update is available at the moment")); } mStatusStatic->Refresh(); } void GuiAbout::UpdateFirmware(void) { GuiDFUProgress progress(this, wxT("Updating firmware ..."), mPowermon, mFirmwareImage); const auto status = progress.ShowModal(); if (status == GuiDFUProgress::SUCCESS) { EndModal(wxID_OK); } else if (status == GuiDFUProgress::CANCELLED) { EndModal(wxID_CANCEL); } else if (status == GuiDFUProgress::FAILED) { wxMessageDialog msg(this, wxT("Firmware update error."), wxT("Error"), wxOK | wxSTAY_ON_TOP | wxCENTRE | wxICON_ERROR); msg.ShowModal(); EndModal(wxID_CANCEL); } } void GuiAbout::OnButtonUpdateClicked(wxCommandEvent &event) { wxMessageDialog msg(this, wxT("You are about to update the firmware in your PowerMon device. \n" "Do not disconnect the power, sit back and relax."), wxT("Confirmation"), wxOK | wxCANCEL | wxICON_QUESTION | wxSTAY_ON_TOP | wxCENTRE); if (msg.ShowModal() == wxID_OK) { UpdateFirmware(); } } void GuiAbout::OnGuiEvent(GuiEvent &event) { event.process(); } BEGIN_EVENT_TABLE(GuiAbout, wxDialog) GUI_EVT(GuiAbout::OnGuiEvent) EVT_BUTTON(ID_BUTTON_UPDATE, GuiAbout::OnButtonUpdateClicked) END_EVENT_TABLE()