1 /**
2 @file LMS_Programing_wxgui.cpp
3 @author Lime Microsystems
4 @brief panel for uploading data to FPGA
5 */
6 #include "LMS_Programing_wxgui.h"
7
8 #include <wx/sizer.h>
9 #include <wx/stattext.h>
10 #include <wx/choice.h>
11 #include <wx/button.h>
12 #include <wx/string.h>
13 #include <wx/gauge.h>
14
15 #include <wx/filedlg.h>
16 #include <wx/msgdlg.h>
17 #include <wx/wfstream.h>
18
19 #include "LMSBoards.h"
20
21 const long LMS_Programing_wxgui::ID_PROGRAMING_FINISHED_EVENT = wxNewId();
22 const long LMS_Programing_wxgui::ID_PROGRAMING_STATUS_EVENT = wxNewId();
23 const long LMS_Programing_wxgui::ID_BUTTON1 = wxNewId();
24 const long LMS_Programing_wxgui::ID_BUTTON2 = wxNewId();
25 const long LMS_Programing_wxgui::ID_GAUGE1 = wxNewId();
26 const long LMS_Programing_wxgui::ID_CHOICE2 = wxNewId();
27 const long LMS_Programing_wxgui::ID_CHOICE1 = wxNewId();
28
BEGIN_EVENT_TABLE(LMS_Programing_wxgui,wxFrame)29 BEGIN_EVENT_TABLE(LMS_Programing_wxgui, wxFrame)
30 END_EVENT_TABLE()
31
32 LMS_Programing_wxgui::LMS_Programing_wxgui(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, int styles, wxString idname)
33 {
34 mProgrammingInProgress.store(false);
35 mAbortProgramming.store(false);
36 wxFlexGridSizer* FlexGridSizer3;
37 wxFlexGridSizer* FlexGridSizer2;
38 wxFlexGridSizer* FlexGridSizer7;
39 wxFlexGridSizer* FlexGridSizer8;
40 wxFlexGridSizer* FlexGridSizer6;
41 wxFlexGridSizer* FlexGridSizer1;
42
43 wxFrame::Create(parent, id, title, wxDefaultPosition, wxDefaultSize, styles, _T("id"));
44 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE));
45 FlexGridSizer1 = new wxFlexGridSizer(0, 1, 5, 0);
46 FlexGridSizer2 = new wxFlexGridSizer(0, 2, 5, 5);
47 btnOpen = new wxButton(this, ID_BUTTON1, _T("Open"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_BUTTON1"));
48 FlexGridSizer2->Add(btnOpen, 1, wxEXPAND | wxALIGN_LEFT | wxALIGN_TOP, 5);
49 FlexGridSizer6 = new wxFlexGridSizer(0, 2, 0, 0);
50 StaticText1 = new wxStaticText(this, wxID_ANY, _T("File:"), wxDefaultPosition, wxDefaultSize, 0, _T("ID_STATICTEXT1"));
51 FlexGridSizer6->Add(StaticText1, 1, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 5);
52 lblFilename = new wxStaticText(this, wxID_ANY, _T("\?"), wxDefaultPosition, wxSize(400, -1), wxST_ELLIPSIZE_START, _T("ID_STATICTEXT2"));
53 FlexGridSizer6->Add(lblFilename, 1, wxALL | wxEXPAND | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 5);
54 FlexGridSizer2->Add(FlexGridSizer6, 1, wxEXPAND | wxALIGN_LEFT | wxALIGN_TOP, 5);
55 btnStartStop = new wxButton(this, ID_BUTTON2, _T("Program"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_BUTTON2"));
56 FlexGridSizer2->Add(btnStartStop, 1, wxEXPAND | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 5);
57 FlexGridSizer8 = new wxFlexGridSizer(0, 1, 0, 0);
58 FlexGridSizer8->AddGrowableCol(0);
59 lblProgressPercent = new wxStaticText(this, wxID_ANY, _T(""), wxDefaultPosition, wxSize(48, -1), 0, _T("ID_STATICTEXT5"));
60
61 progressBar = new wxGauge(this, ID_GAUGE1, 100, wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_GAUGE1"));
62 FlexGridSizer8->Add(progressBar, 1, wxEXPAND | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 0);
63 FlexGridSizer8->AddGrowableRow(0);
64 FlexGridSizer2->Add(FlexGridSizer8, 1, wxEXPAND | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 0);
65 FlexGridSizer2->Add(lblProgressPercent, 1, wxEXPAND | wxALL | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 5);
66 FlexGridSizer1->Add(FlexGridSizer2, 1, wxALIGN_LEFT | wxALIGN_TOP, 5);
67 FlexGridSizer3 = new wxFlexGridSizer(0, 3, 0, 5);
68 FlexGridSizer7 = new wxFlexGridSizer(0, 2, 0, 5);
69 StaticText2 = new wxStaticText(this, wxID_ANY, _T("Programming mode:"), wxDefaultPosition, wxDefaultSize, 0, _T("ID_STATICTEXT3"));
70 FlexGridSizer7->Add(StaticText2, 1, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 5);
71 cmbDevice = new wxChoice(this, ID_CHOICE2, wxDefaultPosition, wxDefaultSize, 0, 0, 0, wxDefaultValidator, _T("ID_CHOICE2"));
72 FlexGridSizer7->Add(cmbDevice, 1, wxEXPAND | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 5);
73 FlexGridSizer3->Add(FlexGridSizer7, 1, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, 5);
74 FlexGridSizer1->Add(FlexGridSizer3, 1, wxEXPAND | wxALIGN_LEFT | wxALIGN_TOP, 5);
75 SetSizer(FlexGridSizer1);
76 FlexGridSizer1->Fit(this);
77 FlexGridSizer1->SetSizeHints(this);
78
79 Connect(ID_BUTTON1, wxEVT_COMMAND_BUTTON_CLICKED, (wxObjectEventFunction)&LMS_Programing_wxgui::OnbtnOpenClick);
80 Connect(btnStartStop->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, (wxObjectEventFunction)&LMS_Programing_wxgui::OnbtnStartProgrammingClick);
81 Connect(ID_CHOICE2, wxEVT_COMMAND_CHOICE_SELECTED, (wxObjectEventFunction)&LMS_Programing_wxgui::OncmbDeviceSelect);
82 Connect(ID_PROGRAMING_FINISHED_EVENT, wxEVT_COMMAND_THREAD, (wxObjectEventFunction)&LMS_Programing_wxgui::OnProgramingFinished);
83 Connect(ID_PROGRAMING_STATUS_EVENT, wxEVT_COMMAND_THREAD, (wxObjectEventFunction)&LMS_Programing_wxgui::OnProgramingStatusUpdate);
84 }
85
~LMS_Programing_wxgui()86 LMS_Programing_wxgui::~LMS_Programing_wxgui()
87 {
88 //make sure the thread has stopped before destroying data
89 if(mProgrammingInProgress.load() == true)
90 {
91 mAbortProgramming.store(true);
92 mWorkerThread.join();
93 }
94 }
95
OnbtnOpenClick(wxCommandEvent & event)96 void LMS_Programing_wxgui::OnbtnOpenClick(wxCommandEvent& event)
97 {
98 wxString wildcards;
99 wxString deviceSelection = cmbDevice->GetStringSelection();
100 auto info = LMS_GetDeviceInfo(lmsControl);
101 if (info)
102 {
103 if (strstr(info->deviceName, lime::GetDeviceName(lime::LMS_DEV_LIMESDR)))
104 {
105 if (deviceSelection.find("FPGA") != wxString::npos)
106 wildcards = "rbf(*.rbf)|*.rbf|All files(*.*)|*.*";
107 else
108 wildcards = "img(*.img)|*.img|All files(*.*)|*.*";
109 }
110 else if (strstr(info->deviceName, lime::GetDeviceName(lime::LMS_DEV_LIMESDRMINI)))
111 wildcards = "rpd(*.rpd)|*.rpd|All files(*.*)|*.*";
112 else if (strstr(info->deviceName, lime::GetDeviceName(lime::LMS_DEV_LIMESDR_QPCIE)))
113 wildcards = "rbf(*.rbf)|*.rbf|All files(*.*)|*.*";
114 }
115 else if (deviceSelection.find("FPGA") != wxString::npos)
116 wildcards = "rbf(*.rbf)|*.rbf|bin(*.bin)|*.bin|rpd(*.rpd)|*.rpd|img(*.img)|*.img|All files(*.*)|*.*";
117 else
118 wildcards = "img(*.img)|*.img|rbf(*.rbf)|*.rbf|bin(*.bin)|*.bin|rpd(*.rpd)|*.rpd|All files(*.*)|*.*";
119
120 wxFileDialog dlg(this, _("Select file"), _(""), _(""), wildcards, wxFD_OPEN | wxFD_FILE_MUST_EXIST);
121
122 if (dlg.ShowModal() == wxID_CANCEL)
123 return;
124
125 lblFilename->SetLabel(dlg.GetPath());
126 }
127
OnbtnStartProgrammingClick(wxCommandEvent & event)128 void LMS_Programing_wxgui::OnbtnStartProgrammingClick(wxCommandEvent& event)
129 {
130 //if needed load program data from file
131 wxString deviceSelection = cmbDevice->GetStringSelection();
132
133 if(
134 (deviceSelection.find("Reset") == wxString::npos) &&
135 (deviceSelection.find("Auto") == wxString::npos))
136 {
137 if (lblFilename->GetLabel().length() <= 1)
138 {
139 wxMessageBox(_("Program file not selected"), _("Warning"));
140 return;
141 }
142
143 //using wxWidgets to read file, to support nonascii characters in path
144 wxFFileInputStream fin(lblFilename->GetLabel());
145
146 if(!fin.IsOk())
147 {
148 wxMessageBox(_("Error loading program file"), _("Error"));
149 return;
150 }
151
152 fin.SeekI(0, wxFromEnd);
153 unsigned int m_data_size = fin.TellI();
154
155 mProgramData.resize(m_data_size, 0);
156 fin.SeekI(0, wxFromStart);
157 fin.Read(mProgramData.data(), m_data_size);
158 }
159
160 Disconnect(btnStartStop->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, (wxObjectEventFunction)&LMS_Programing_wxgui::OnbtnStartProgrammingClick);
161 btnOpen->Disable();
162 btnStartStop->SetLabel(_("Abort"));
163
164 mAbortProgramming.store(false);
165 //run programming in separate thread, to prevent GUI freeze
166 mWorkerThread = std::thread(&LMS_Programing_wxgui::DoProgramming, this);
167 Connect(btnStartStop->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, (wxObjectEventFunction)&LMS_Programing_wxgui::OnAbortProgramming);
168 }
169
170 /** @brief Change programming modes according to selected device
171 */
OncmbDeviceSelect(wxCommandEvent & event)172 void LMS_Programing_wxgui::OncmbDeviceSelect(wxCommandEvent& event)
173 {
174 wxString deviceSelection = cmbDevice->GetStringSelection();
175 if(
176 (deviceSelection.find("Reset") == wxString::npos) &&
177 (deviceSelection.find("Auto") == wxString::npos))
178 btnOpenEnb = true;
179 else
180 btnOpenEnb = false;
181 btnOpen->Enable(btnOpenEnb);
182 StaticText1->Enable(btnOpenEnb);
183 lblFilename->Enable(btnOpenEnb);
184 }
185
OnProgramingFinished(wxCommandEvent & event)186 void LMS_Programing_wxgui::OnProgramingFinished(wxCommandEvent& event)
187 {
188 mWorkerThread.join();
189 wxMessageBox(event.GetString(), _("INFO"), wxICON_INFORMATION | wxOK);
190 btnOpen->Enable(btnOpenEnb);
191 Disconnect(btnStartStop->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, (wxObjectEventFunction)&LMS_Programing_wxgui::OnAbortProgramming);
192 Connect(btnStartStop->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, (wxObjectEventFunction)&LMS_Programing_wxgui::OnbtnStartProgrammingClick);
193 btnStartStop->SetLabel(_("Program"));
194 }
195
OnAbortProgramming(wxCommandEvent & event)196 void LMS_Programing_wxgui::OnAbortProgramming(wxCommandEvent& event)
197 {
198 mAbortProgramming.store(true);
199 }
200
SetConnection(lms_device_t * port)201 void LMS_Programing_wxgui::SetConnection(lms_device_t* port)
202 {
203 lmsControl = port;
204 if (lmsControl)
205 {
206 cmbDevice->Clear();
207 lms_name_t modes[16];
208 int count = LMS_GetProgramModes(lmsControl, modes);
209 for (int i = 0; i < count; i ++)
210 if (strstr(modes[i],"MCU") == nullptr)
211 cmbDevice->Append(wxString(modes[i]));
212 cmbDevice->SetSelection(0);
213 wxCommandEvent evt;
214 OncmbDeviceSelect(evt);
215 Layout();
216 }
217 }
218
219 LMS_Programing_wxgui* LMS_Programing_wxgui::obj_ptr=nullptr;
OnProgrammingCallback(int bsent,int btotal,const char * progressMsg)220 bool LMS_Programing_wxgui::OnProgrammingCallback(int bsent, int btotal, const char* progressMsg)
221 {
222 wxCommandEvent evt;
223 evt.SetEventObject(obj_ptr);
224 evt.SetInt(100.0 * bsent / btotal); //round to int
225 evt.SetString(wxString::From8BitData(progressMsg));
226 evt.SetEventType(wxEVT_COMMAND_THREAD);
227 evt.SetId(ID_PROGRAMING_STATUS_EVENT);
228 wxPostEvent(obj_ptr, evt);
229 return obj_ptr->mAbortProgramming.load();
230 }
231
232
DoProgramming()233 void LMS_Programing_wxgui::DoProgramming()
234 {
235 mProgrammingInProgress.store(true);
236 obj_ptr = this;
237 wxString device = cmbDevice->GetStringSelection();
238 int status = LMS_Program(lmsControl, mProgramData.data(), mProgramData.size(), device.c_str(), OnProgrammingCallback);
239 wxCommandEvent evt;
240 evt.SetEventObject(this);
241 evt.SetId(ID_PROGRAMING_FINISHED_EVENT);
242 evt.SetEventType(wxEVT_COMMAND_THREAD);
243 evt.SetString(status == 0 ? _("Programming Completed!") : _("Programming failed!\n"));
244
245 wxPostEvent(this, evt);
246 mProgrammingInProgress.store(false);
247 return;
248 }
249
250 /** Updates GUI elements with programming status
251 */
OnProgramingStatusUpdate(wxCommandEvent & event)252 void LMS_Programing_wxgui::OnProgramingStatusUpdate(wxCommandEvent& event)
253 {
254 progressBar->SetValue(event.GetInt());
255 lblProgressPercent->SetLabel(event.GetString());
256 }
257