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