#include "BossaWindow.h"
#include "BossaApp.h"
#include "BossaAbout.h"
#include "BossaInfo.h"
#include "Device.h"
#include <string>
#include <algorithm>
#if defined(_WIN32) || defined(_WIN64)
#define F_OK 0
#define access(...) _access(__VA_ARGS__)
#endif
using namespace std;
BossaWindow::BossaWindow() : MainFrame(NULL)
{
_bossaBitmap->SetBitmap(wxGetApp().bitmaps.getBossaLogo());
_aboutButton->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
wxCommandEventHandler(BossaWindow::OnAbout),
NULL, this);
_refreshButton->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
wxCommandEventHandler(BossaWindow::OnRefresh),
NULL, this);
_portComboBox->Connect(wxEVT_COMMAND_COMBOBOX_SELECTED,
wxCommandEventHandler(BossaWindow::OnSerial),
NULL, this);
_writeButton->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
wxCommandEventHandler(BossaWindow::OnWrite),
NULL, this);
_verifyButton->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
wxCommandEventHandler(BossaWindow::OnVerify),
NULL, this);
_readButton->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
wxCommandEventHandler(BossaWindow::OnRead),
NULL, this);
_infoButton->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
wxCommandEventHandler(BossaWindow::OnInfo),
NULL, this);
_exitButton->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
wxCommandEventHandler(BossaWindow::OnExit),
NULL, this);
Connect(wxEVT_THREAD_PROGRESS,
wxCommandEventHandler(BossaWindow::OnThreadProgress),
NULL, this);
Connect(wxEVT_THREAD_SUCCESS,
wxCommandEventHandler(BossaWindow::OnThreadSuccess),
NULL, this);
Connect(wxEVT_THREAD_WARNING,
wxCommandEventHandler(BossaWindow::OnThreadWarning),
NULL, this);
Connect(wxEVT_THREAD_ERROR,
wxCommandEventHandler(BossaWindow::OnThreadError),
NULL, this);
Connect(wxEVT_PROGRESS_CANCEL,
wxCommandEventHandler(BossaWindow::OnProgressCancel),
NULL, this);
RefreshSerial();
Disconnected();
wxString port;
wxConfig& config = wxGetApp().config;
if (config.Read(_("Port"), &port))
{
if (_portComboBox->FindString(port) >= 0)
{
PortFactory& portFactory = wxGetApp().portFactory;
Samba& samba = wxGetApp().samba;
if (samba.connect(portFactory.create(std::string(port.mb_str()))))
{
CreateDevice();
}
}
}
wxString file;
if (config.Read(_("File"), &file))
{
_filePicker->SetPath(file);
}
wxIcon icon;
icon.CopyFromBitmap(wxGetApp().bitmaps.getBossaIcon());
SetIcon(icon);
Iconize(false);
}
BossaWindow::~BossaWindow()
{
wxConfig& config = wxGetApp().config;
config.Write(_("Port"), _portComboBox->GetStringSelection());
config.Write(_("File"), _filePicker->GetPath());
}
void
BossaWindow::RefreshSerial()
{
string port;
wxString selection = _portComboBox->GetStringSelection();
PortFactory& portFactory = wxGetApp().portFactory;
_portComboBox->Clear();
for (port = portFactory.begin();
port != portFactory.end();
port = portFactory.next())
{
_portComboBox->Append(wxString(port.c_str(), wxConvUTF8));
}
if (!_portComboBox->SetStringSelection(selection))
Disconnected();
}
void
BossaWindow::OnAbout(wxCommandEvent& event)
{
BossaAbout* dialog = new BossaAbout(this);
dialog->ShowModal();
dialog->Destroy();
}
void
BossaWindow::OnRefresh(wxCommandEvent& event)
{
RefreshSerial();
}
void
BossaWindow::Connected()
{
Device::FlashPtr& flash = wxGetApp().device.getFlash();
Samba& samba = wxGetApp().samba;
const SerialPort& port = samba.getSerialPort();
_statusBar->SetStatusText(wxT("Connected"), 0);
_statusBar->SetStatusText(wxString::Format(wxT("Device: %s"), flash->name().c_str()), 1);
_portComboBox->SetStringSelection(wxString(port.name().c_str(), wxConvUTF8));
_writeButton->Enable(true);
_verifyButton->Enable(true);
_readButton->Enable(true);
_infoButton->Enable(true);
}
void
BossaWindow::Disconnected()
{
_statusBar->SetStatusText(wxT("Not connected"), 0);
_statusBar->SetStatusText(_(""), 1);
_portComboBox->SetSelection(wxNOT_FOUND);
_writeButton->Enable(false);
_verifyButton->Enable(false);
_readButton->Enable(false);
_infoButton->Enable(false);
}
void
BossaWindow::Error(const wxString& message)
{
wxMessageDialog* dialog = new wxMessageDialog(
this,
message,
_("Error"),
wxOK | wxICON_ERROR
);
dialog->ShowModal();
dialog->Destroy();
}
void
BossaWindow::Warning(const wxString& message)
{
wxMessageDialog* dialog = new wxMessageDialog(
this,
message,
_("Warning"),
wxOK | wxICON_WARNING
);
dialog->ShowModal();
dialog->Destroy();
}
void
BossaWindow::Info(const wxString& message)
{
wxMessageDialog* dialog = new wxMessageDialog(
this,
message,
_("Info"),
wxOK | wxICON_INFORMATION
);
dialog->ShowModal();
dialog->Destroy();
}
bool
BossaWindow::Question(const wxString& message)
{
wxMessageDialog* dialog = new wxMessageDialog(
this,
message,
_("Question"),
wxYES_NO | wxICON_QUESTION
);
int resp = dialog->ShowModal();
dialog->Destroy();
return (resp == wxID_YES);
}
void
BossaWindow::CreateDevice()
{
Device& device = wxGetApp().device;
try
{
device.create();
}
catch (exception& e)
{
Disconnected();
Error(wxString(e.what(), wxConvUTF8));
return;
}
_statusBar->SetStatusText(wxString::Format(wxT("Device: %s"), device.getFlash()->name().c_str()), 1);
Connected();
}
void
BossaWindow::OnSerial(wxCommandEvent& event)
{
PortFactory& portFactory = wxGetApp().portFactory;
Samba& samba = wxGetApp().samba;
wxString port = _portComboBox->GetString(event.GetSelection());
if (!samba.connect(portFactory.create(std::string(port.mb_str()))))
{
Disconnected();
Error(wxString::Format(_("Could not connect to device on %s"), port.c_str()));
return;
}
CreateDevice();
}
bool
BossaWindow::GetOffset(uint32_t& offset)
{
offset = 0;
return true;
}
void
BossaWindow::OnWrite(wxCommandEvent& event)
{
Device::FlashPtr& flash = wxGetApp().device.getFlash();
uint32_t offset;
if (_filePicker->GetPath().IsEmpty())
{
Error(wxT("You must specify a file first"));
return;
}
if (!GetOffset(offset))
return;
if (access(_filePicker->GetPath().mb_str(), F_OK))
{
Error(wxT("File does not exist"));
return;
}
try
{
std::vector<bool> regions = flash->getLockRegions();
if (std::find(regions.begin(), regions.end(), true) != regions.end())
{
if (!Question(wxT("The flash is currently locked. Do you want to unlock it and proceed with the write?")))
return;
flash->setLockRegions(std::vector<bool>(regions.size(), false));
}
}
catch(exception& e)
{
Error(wxString(e.what(), wxConvUTF8));
return;
}
_progress = new BossaProgress(this);
_thread = new WriteThread(
this,
_filePicker->GetPath(),
true, true, false, false, false, false, offset
);
if (_thread->Create() != wxTHREAD_NO_ERROR ||
_thread->Run() != wxTHREAD_NO_ERROR)
{
Error(wxT("Unable to start worker thread"));
return;
}
_progress->ShowModal();
_progress->Destroy();
}
void
BossaWindow::OnVerify(wxCommandEvent& event)
{
uint32_t offset;
if (_filePicker->GetPath().IsEmpty())
{
Error(wxT("You must specify a file first"));
return;
}
if (!GetOffset(offset))
return;
if (access(_filePicker->GetPath().mb_str(), F_OK))
{
Error(wxT("File does not exist"));
return;
}
_progress = new BossaProgress(this);
_thread = new VerifyThread(
this,
_filePicker->GetPath(),
offset
);
if (_thread->Create() != wxTHREAD_NO_ERROR ||
_thread->Run() != wxTHREAD_NO_ERROR)
{
Error(wxT("Unable to start worker thread"));
return;
}
_progress->ShowModal();
_progress->Destroy();
}
void
BossaWindow::OnRead(wxCommandEvent& event)
{
uint32_t offset;
size_t size;
if (_filePicker->GetPath().IsEmpty())
{
Error(wxT("You must specify a file first"));
return;
}
if (!access(_filePicker->GetPath().mb_str(), F_OK))
{
if (!Question(wxT("File already exists. Do you want to replace it?")))
return;
}
size = 0;
if (!GetOffset(offset))
return;
_progress = new BossaProgress(this);
_thread = new ReadThread(
this,
_filePicker->GetPath(),
size,
offset
);
if (_thread->Create() != wxTHREAD_NO_ERROR ||
_thread->Run() != wxTHREAD_NO_ERROR)
{
Error(_("Unable to start worker thread"));
return;
}
_progress->ShowModal();
_progress->Destroy();
}
void
BossaWindow::OnInfo(wxCommandEvent& event)
{
BossaInfo* info;
try
{
info = new BossaInfo(this);
}
catch (exception& e)
{
Error(wxString(e.what(), wxConvUTF8));
return;
}
info->ShowModal();
info->Destroy();
}
void
BossaWindow::OnExit(wxCommandEvent& event)
{
Destroy();
}
void
BossaWindow::OnThreadProgress(wxCommandEvent& event)
{
_progress->SetValue(event.GetInt());
_progress->SetLabel(event.GetString());
}
void
BossaWindow::OnThreadSuccess(wxCommandEvent& event)
{
wxString message = event.GetString();
if (!message.IsEmpty())
Info(message);
_progress->EndModal(0);
}
void
BossaWindow::OnThreadWarning(wxCommandEvent& event)
{
wxString message = event.GetString();
Warning(message);
_progress->EndModal(0);
}
void
BossaWindow::OnThreadError(wxCommandEvent& event)
{
wxString message = event.GetString();
Error(message);
_progress->EndModal(0);
}
void
BossaWindow::OnProgressCancel(wxCommandEvent& event)
{
_thread->stop();
}