-
Notifications
You must be signed in to change notification settings - Fork 14
/
agent.cpp
executable file
·314 lines (264 loc) · 10.7 KB
/
agent.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
#include <QDebug>
#include <QDesktopServices>
#include <QJsonDocument>
#include <QJsonObject>
#include <QtNetwork>
#include <QTime>
#include <QThread>
#include <QUrl>
#include "agent.h"
//Agent::Agent()
Agent::Agent(QObject *parent) : QObject(parent)
{
qDebug() << "Agent::Agent()" << "thread: " << QThread::currentThread();
this->httpCapable = true;
this->majorVersion = 1;
this->minorVersion = 0;
this->patchVersion = 1;
#ifdef AGENT_BUILD_NOTE
this->buildNote = AGENT_BUILD_NOTE;
#endif
this->firmwareUploadStatus = "idle";
//Initialize devices array with null pointers
this->activeDevice = 0;
}
Agent::~Agent(){
qDebug("Agent Descructor");
if(this->activeDevice != 0)
{
qDebug("Freeing Active Device");
releaseActiveDevice();
}
}
//Return all UART devices on the system that are not busy plus the active device even if it is busy
QVector<QString> Agent::enumerateDevices() {
//---------- UART ----------
QVector<QString> devices = QVector<QString>();
QList<QSerialPortInfo> serialPortInfo = Serial::getSerialPortInfo();
//Loop over all devices on the system
for(int i=0; i<serialPortInfo.length(); i++)
{
if(serialPortInfo[i].isBusy())
{
//Only add a busy device if it is the active device
if(this->activeDevice != 0)
{
if(serialPortInfo[i].portName() == this->activeDevice->name)
{
devices.append(serialPortInfo[i].portName());
}
}
}
else
{
//Device is available, add it
devices.append(serialPortInfo[i].portName());
}
}
//---------- HTTP ----------
//TODO?
return devices;
}
QByteArray Agent::getVersion() {
return QByteArray(QString("%1.%2.%3").arg(majorVersion).arg(minorVersion).arg(patchVersion).toUtf8());
}
int Agent::getMajorVersion() {
return this->majorVersion;
}
int Agent::getMinorVersion() {
return this->minorVersion;
}
int Agent::getPatchVersion() {
return this->patchVersion;
}
QString Agent::getBuildNote() {
return this->buildNote;
}
bool Agent::launchWfl() {
//Todo - Launch Electron Version If It Exists
if(internetAvailable()) {
return QDesktopServices::openUrl(QUrl("http://waveformslive.com/"));
} else {
return QDesktopServices::openUrl(QUrl("http://127.0.0.1:42135/"));
}
}
//Set the active device by name. A new device object is created unless the target device is already active and open. This command also puts the device into JSON mode.
bool Agent::setActiveDeviceByName(QString deviceName) {
qDebug() << "Agent::setActiveDeviceByName()" << "thread: " << QThread::currentThread();
QVector<QString> devices = enumerateDevices();
if(this->activeDevice != 0)
{
//An active device exists
if(this->activeDevice->name == deviceName)
{
//The target device matches the active device, check if it is still available
for(int i=0; i<devices.size(); i++)
{
if(deviceName == devices[i])
{
// -- TODO OLD REMOVE - Target device is already active and still exists. SoftReset it to make sure the agent is the app that has it open (not some other app)
// -- NEW - Check active device name against target device name to avoid having to soft reset the device.
if(this->activeDevice->name == deviceName)
{
releaseActiveDevice();
this->activeDevice = new WflSerialDevice(deviceName);
this->activeDevice->moveToThread(this->getThread());
// this->activeDevice = new WflSerialDevice(deviceName);
if(!this->activeDevice->isOpen()){
//Failed to open serial port
return false;
}
this->activeDevice->name = deviceName;
emit activeDeviceChanged(QString(deviceName));
qDebug() << "~~~~ENTER JSON MODE~~~~~~" << this->activeDevice->writeRead("{\"mode\":\"JSON\"}\r\n");
//Connect release signal to device
connect(this, SIGNAL(startReleaseDevice()), activeDevice, SLOT(release()));
connect(this, SIGNAL(softResetActiveDeviceSignal()), activeDevice, SLOT(softReset()));
return true;
} else {
//No response from the device, something else must have it open
releaseActiveDevice();
return false;
}
}
}
//Target device is already active but no longer available
releaseActiveDevice();
return false;
} else {
//The current active device is not the target active device, free it
releaseActiveDevice();
}
}
//No active device, check if target device is available, if so set it as the active device
for(int i=0; i<devices.size(); i++)
{
if(devices[i] == deviceName)
{
//Create device object and enable JSON mode
this->activeDevice = new WflSerialDevice(deviceName);
this->activeDevice->moveToThread(this->getThread());
// this->activeDevice = new WflSerialDevice(deviceName);
if(!this->activeDevice->isOpen()){
//Failed to open serial port
return false;
}
this->activeDevice->name = deviceName;
emit activeDeviceChanged(QString(deviceName));
qDebug() << "~~~~ENTER JSON MODE~~~~~~" << this->activeDevice->writeRead("{\"mode\":\"JSON\"}\r\n");
//Connect release signal to device
connect(this, SIGNAL(startReleaseDevice()), activeDevice, SLOT(release()));
connect(this, SIGNAL(softResetActiveDeviceSignal()), activeDevice, SLOT(softReset()));
return true;
}
}
//Target device does not exist
return false;
}
//Call to emit signal to free the active device.
void Agent::releaseActiveDevice(){
qDebug() << "Agent::releaseActiveDevice" << "thread: " << QThread::currentThread();
//Directly call activeDevice->release() if trigger source is in same thread as agent to avoid deadlock
if(QThread::currentThread() == this->getThread()) {
activeDevice->release();
} else {
//Release trigger signal came from different thread, signal release and loop to wait for response
QEventLoop loop;
//Connect signal to detect when device has been released
connect(this->activeDevice, SIGNAL(releaseComplete()), &loop, SLOT(quit()));
if(this->activeDevice != 0) {
//emit release signal
emit startReleaseDevice();
//Loop unit device has been released
loop.exec();
qDebug() << "Agent::releaseActiveDevice() - Post Loop";
}
disconnect(this->activeDevice, SIGNAL(releaseComplete()), &loop, SLOT(quit()));
}
this->activeDevice = 0;
//Emit signal to update GUI menu text
emit activeDeviceChanged("");
}
//Returns true if internet access is available
bool Agent::internetAvailable() {
QNetworkAccessManager nam;
QNetworkRequest req(QUrl("http://waveformslive.com"));
QNetworkReply *response = nam.get(req);
QEventLoop loop;
connect(response, SIGNAL(finished()), &loop, SLOT(quit()));
loop.exec();
if(response->bytesAvailable()) {
return true;
} else {
return false;
}
}
//Use Digilent PGM to update the active device firmware with the specified firmware hex file. This function blocks until the firmware upload is complete and ruturns true if the firmware upload was successful and false otherwise.
bool Agent::updateActiveDeviceFirmware(QString hexPath, bool enterBootloader) {
firmwareUploadStatus = "uploading";
if(this->activeDevice != NULL && this->activeDevice->deviceType == "UART") {
this->pgm = new DigilentPgm();
QString portName = this->activeDevice->name;
//Send enter device bootloader command if necissary
if(enterBootloader) {
QByteArray devResp = this->activeDevice->writeRead("{\"device\":[{\"command\":\"enterBootloader\"}]})");
QJsonDocument resDoc = QJsonDocument::fromJson(devResp);
QJsonObject resObj = resDoc.object();
QJsonArray deviceCmds = resObj.value("device").toArray();
QJsonObject enterBootloaderObj = deviceCmds[0].toObject();
int waitTime = enterBootloaderObj.value("wait").toInt();
//Wait for device to enter bootloader
QTime stopWatch;
stopWatch.start();
QTime startTime = QTime::currentTime();
QTime doneTime = startTime.addMSecs(waitTime);
while (QTime::currentTime() < doneTime) {
QCoreApplication::processEvents(QEventLoop::AllEvents, 1);
}
}
//Release the device so we can update it's firmware
this->releaseActiveDevice();
//Use Digilent PGM to update the firmware
if(this->pgm->programByPort(hexPath, portName)) {
//Programming successful, free PGM and make device active again
this->pgm->releaseDevice();
delete this->pgm;
qDebug() << "Firmware updated successfully";
if(this->setActiveDeviceByName(portName)) {
firmwareUploadStatus = "idle";
emit updateActiveDeviceFirmwareComplete(true);
return true;
} else {
qDebug() << "Failed to set" << portName << "as the active device after updating firmware";
firmwareUploadStatus = "error";
emit updateActiveDeviceFirmwareComplete(false);
return false;
}
} else {
qDebug() << "Failed to update firmware";
delete this->pgm;
firmwareUploadStatus = "error";
emit updateActiveDeviceFirmwareComplete(false);
return false;
}
} else {
qDebug() << "Unable to program non-uart devices at this time";
firmwareUploadStatus = "error";
emit updateActiveDeviceFirmwareComplete(false);
return false;
}
}
QString Agent::getFirmwareUploadStatus() {
return this->firmwareUploadStatus;
}
int Agent::getFirmwareUploadProgress() {
return this->pgm->progress;
}
QThread* Agent::getThread() {
return this->thread();
}
/*
WflDevice* Agent::createNewWflSerialDevice(QString address) {
return new WflSerialDevice(deviceName);
}
*/