QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
Bootloader.cc
Go to the documentation of this file.
1#include "Bootloader.h"
3#include "FirmwareImage.h"
4#include "QGC.h"
5
6#include <QtCore/QElapsedTimer>
7#include <QtCore/QFile>
8#include <QtCore/QThread>
9
10QGC_LOGGING_CATEGORY(FirmwareUpgradeLog, "VehicleSetup.FirmwareUpgrade")
11QGC_LOGGING_CATEGORY(FirmwareUpgradeVerboseLog, "VehicleSetup.FirmwareUpgrade:verbose")
12
14Bootloader::Bootloader(bool sikRadio, QObject *parent)
15 : QObject (parent)
16 , _sikRadio (sikRadio)
17{
18
19}
20
21bool Bootloader::open(const QString portName)
22{
23 qCDebug(FirmwareUpgradeLog) << "open:" << portName;
24
25 _port.setPortName (portName);
31
32 if (!_port.open(QIODevice::ReadWrite)) {
33 _errorString = tr("Open failed on port %1: %2").arg(portName, _port.errorString());
34 return false;
35 }
36
37 if (_sikRadio) {
38 // Radios are slow to start up
39 QThread::msleep(1000);
40 }
41 return true;
42}
43
44QString Bootloader::_getNextLine(int timeoutMsecs)
45{
46 QString line;
47 QElapsedTimer timeout;
48 bool foundCR = false;
49
50 timeout.start();
51 while (timeout.elapsed() < timeoutMsecs) {
52 char oneChar;
53 _port.waitForReadyRead(100);
54 if (_port.read(&oneChar, 1) > 0) {
55 if (oneChar == '\r') {
56 foundCR = true;
57 continue;
58 } else if (oneChar == '\n' && foundCR) {
59 return line;
60 }
61 line += oneChar;
62 }
63 }
64
65 return QString();
66}
67
68bool Bootloader::getBoardInfo(uint32_t& bootloaderVersion, uint32_t& boardID, uint32_t& flashSize)
69{
70 if (_sikRadio) {
71 // Try sync to see if already in bootloader mode
72 _sync();
73 if (_inBootloaderMode) {
74 qCDebug(FirmwareUpgradeLog) << "Radio in bootloader mode already";
75 if (!_get3DRRadioBoardId(_boardID)) {
76 goto Error;
77 }
78 } else {
79 qCDebug(FirmwareUpgradeLog) << "Radio in normal mode";
80 _port.readAll();
82 // Put radio into command mode
83 _write("+++");
84 if (!_port.waitForReadyRead(2000)) {
85 _errorString = tr("Unable to put radio into command mode +++");
86 goto Error;
87 }
88 QByteArray bytes = _port.readAll();
89 if (!bytes.contains("OK")) {
90 _errorString = tr("Radio did not respond to command mode");
91 goto Error;
92 }
93
94 // Use ATI2 command to get board id
95 _write("ATI2\r\n");
96 QString echo = _getNextLine(2000);
97 if (echo.isEmpty() || echo != "ATI2") {
98 _errorString = tr("Radio did not respond to ATI2 command");
99 goto Error;
100 }
101 QString boardIdStr = _getNextLine(2000);
102 bool ok = false;
103 _boardID = boardIdStr.toInt(&ok);
104 if (boardIdStr.isEmpty() || !ok) {
105 _errorString = tr("Radio did not return board id");
106 goto Error;
107 }
108 }
109 bootloaderVersion = 0;
110 boardID = _boardID;
111 flashSize = 0;
112
113 return true;
114 } else {
115 if (!_sync()) {
116 goto Error;
117 }
118 if (!_protoGetDevice(INFO_BL_REV, _bootloaderVersion)) {
119 goto Error;
120 }
121 if (_bootloaderVersion < BL_REV_MIN || _bootloaderVersion > BL_REV_MAX) {
122 _errorString = tr("Found unsupported bootloader version: %1").arg(_bootloaderVersion);
123 goto Error;
124 }
125 if (!_protoGetDevice(INFO_BOARD_ID, _boardID)) {
126 goto Error;
127 }
128 if (!_protoGetDevice(INFO_FLASH_SIZE, _boardFlashSize)) {
129 qWarning() << _errorString;
130 goto Error;
131 }
132
133 // Older V2 boards have large flash space but silicon error which prevents it from being used. Bootloader v5 and above
134 // will correctly account/report for this. Older bootloaders will not. Newer V2 board which support larger flash space are
135 // reported as V3 board id.
136 if (_boardID == boardIDPX4FMUV2 && _bootloaderVersion >= _bootloaderVersionV2CorrectFlash && _boardFlashSize > _flashSizeSmall) {
137 _boardID = boardIDPX4FMUV3;
138 }
139
140 bootloaderVersion = _bootloaderVersion;
141 boardID = _boardID;
142 flashSize = _boardFlashSize;
143
144 return true;
145 }
146
147Error:
148 qCDebug(FirmwareUpgradeLog) << "getBoardInfo failed:" << _errorString;
149 _errorString.prepend(tr("Get Board Info: "));
150 return false;
151}
152
154{
155 if (_sikRadio && !_inBootloaderMode) {
156 _write("AT&UPDATE\r\n");
157 if (!_port.waitForReadyRead(1500)) {
158 _errorString = tr("Unable to reboot radio (ready read)");
159 return false;
160 }
162
163 if (!_sync()) {
164 return false;
165 }
166 }
167 return true;
168}
169
171{
172 uint32_t timeout = _eraseTimeout;
173
174 // If flash size is bigger then 2MB we need to increase timeout
175 if(_boardFlashSize > 2000 * 1024) {
176 // Increase timeout for each 1MB by 4 seconds
177 timeout += (_boardFlashSize / 1e6) * 4000;
178 }
179
180 // Erase is slow, need larger timeout
181 if (!_sendCommand(PROTO_CHIP_ERASE, timeout)) {
182 _errorString = tr("Erase failed: %1").arg(_errorString);
183 return false;
184 }
185
186 return true;
187}
188
190{
191 if (image->imageIsBinFormat()) {
192 return _binProgram(image);
193 } else {
194 return _ihxProgram(image);
195 }
196}
197
199{
200 bool success;
201 if (_sikRadio && !_inBootloaderMode) {
202 qCDebug(FirmwareUpgradeLog) << "reboot ATZ";
203 _port.readAll();
204 success = _write("ATZ\r\n");
205 } else {
206 qCDebug(FirmwareUpgradeLog) << "reboot";
207 success = _write(PROTO_BOOT) && _write(PROTO_EOC);
208 }
209 _port.flush();
210 if (success) {
211 QThread::msleep(1000);
212 }
213 return success;
214}
215
216bool Bootloader::_write(const char* data)
217{
218 return _write((uint8_t*)data, qstrlen(data));
219}
220
221bool Bootloader::_write(const uint8_t* data, qint64 maxSize)
222{
223 qint64 bytesWritten = _port.write((const char*)data, maxSize);
224 if (bytesWritten == -1) {
225 _errorString = tr("Write failed: %1").arg(_port.errorString());
226 qWarning() << _errorString;
227 return false;
228 }
229 if (bytesWritten != maxSize) {
230 _errorString = tr("Incorrect number of bytes returned for write: actual(%1) expected(%2)").arg(bytesWritten).arg(maxSize);
231 qWarning() << _errorString;
232 return false;
233 }
234
235 return true;
236}
237
238bool Bootloader::_write(const uint8_t byte)
239{
240 uint8_t buf[1] = { byte };
241 return _write(buf, 1);
242}
243
244bool Bootloader::_read(uint8_t* data, qint64 cBytesExpected, int readTimeout)
245{
246 QElapsedTimer timeout;
247
248 timeout.start();
249 while (_port.bytesAvailable() < cBytesExpected) {
250 if (timeout.elapsed() > readTimeout) {
251 _errorString = tr("Timeout waiting for bytes to be available");
252 return false;
253 }
254 _port.waitForReadyRead(100);
255 }
256
257 qint64 bytesRead;
258 bytesRead = _port.read((char *)data, cBytesExpected);
259
260 if (bytesRead != cBytesExpected) {
261 _errorString = tr("Read failed: error: %1").arg(_port.errorString());
262 return false;
263 }
264
265 return true;
266}
267
270bool Bootloader::_getCommandResponse(int responseTimeout)
271{
272 uint8_t response[2];
273
274 if (!_read(response, 2, responseTimeout)) {
275 _errorString.prepend(tr("Get Command Response: "));
276 return false;
277 }
278
279 // Make sure we get a good sync response
280 if (response[0] != PROTO_INSYNC) {
281 _errorString = tr("Invalid sync response: 0x%1 0x%2").arg(response[0], 2, 16, QLatin1Char('0')).arg(response[1], 2, 16, QLatin1Char('0'));
282 return false;
283 } else if (response[0] == PROTO_INSYNC && response[1] == PROTO_BAD_SILICON_REV) {
284 _errorString = tr("This board is using a microcontroller with faulty silicon and an incorrect configuration and should be put out of service.");
285 return false;
286 } else if (response[1] != PROTO_OK) {
287 QString responseCode = tr("Unknown response code");
288 if (response[1] == PROTO_FAILED) {
289 responseCode = "PROTO_FAILED";
290 } else if (response[1] == PROTO_INVALID) {
291 responseCode = "PROTO_INVALID";
292 }
293 _errorString = tr("Command failed: 0x%1 (%2)").arg(response[1], 2, 16, QLatin1Char('0')).arg(responseCode);
294 return false;
295 }
296
297 return true;
298}
299
303bool Bootloader::_protoGetDevice(uint8_t param, uint32_t& value)
304{
305 uint8_t buf[3] = { PROTO_GET_DEVICE, param, PROTO_EOC };
306
307 if (!_write(buf, sizeof(buf))) {
308 goto Error;
309 }
310 if (!_read((uint8_t*)&value, sizeof(value))) {
311 goto Error;
312 }
313 if (!_getCommandResponse()) {
314 goto Error;
315 }
316
317 return true;
318
319Error:
320 _errorString.prepend(tr("Get Device: "));
321 return false;
322}
323
327bool Bootloader::_sendCommand(const uint8_t cmd, int responseTimeout)
328{
329 uint8_t buf[2] = { cmd, PROTO_EOC };
330
331 if (!_write(buf, 2)) {
332 goto Error;
333 }
334 _port.flush();
335
336 if (!_getCommandResponse(responseTimeout)) {
337 goto Error;
338 }
339
340 return true;
341
342Error:
343 _errorString.prepend(tr("Send Command: "));
344 return false;
345}
346
347bool Bootloader::_binProgram(const FirmwareImage* image)
348{
349 QFile firmwareFile(image->binFilename());
350 if (!firmwareFile.open(QIODevice::ReadOnly)) {
351 _errorString = tr("Unable to open firmware file %1: %2").arg(image->binFilename(), firmwareFile.errorString());
352 return false;
353 }
354 uint32_t imageSize = (uint32_t)firmwareFile.size();
355
356 uint8_t imageBuf[PROG_MULTI_MAX];
357 uint32_t bytesSent = 0;
358 _imageCRC = 0;
359
360 Q_ASSERT(PROG_MULTI_MAX <= 0x8F);
361
362 while (bytesSent < imageSize) {
363 int bytesToSend = imageSize - bytesSent;
364 if (bytesToSend > (int)sizeof(imageBuf)) {
365 bytesToSend = (int)sizeof(imageBuf);
366 }
367
368 Q_ASSERT((bytesToSend % 4) == 0);
369
370 int bytesRead = firmwareFile.read((char *)imageBuf, bytesToSend);
371 if (bytesRead == -1 || bytesRead != bytesToSend) {
372 _errorString = tr("Firmware file read failed: %1").arg(firmwareFile.errorString());
373 return false;
374 }
375
376 Q_ASSERT(bytesToSend <= 0x8F);
377
378 bool failed = true;
379 if (_write(PROTO_PROG_MULTI) &&
380 _write((uint8_t)bytesToSend) &&
381 _write(imageBuf, bytesToSend) &&
382 _write(PROTO_EOC)) {
383 if (_getCommandResponse()) {
384 failed = false;
385 }
386 }
387 if (failed) {
388 _errorString = tr("Flash failed: %1 at address 0x%2").arg(_errorString).arg(bytesSent, 8, 16, QLatin1Char('0'));
389 return false;
390 }
391
392 bytesSent += bytesToSend;
393
394 // Calculate the CRC now so we can test it after the board is flashed.
395 _imageCRC = QGC::crc32((uint8_t *)imageBuf, bytesToSend, _imageCRC);
396
397 emit updateProgress(bytesSent, imageSize);
398 }
399 firmwareFile.close();
400
401 // We calculate the CRC using the entire flash size, filling the remainder with 0xFF.
402 while (bytesSent < _boardFlashSize) {
403 const uint8_t fill = 0xFF;
404 _imageCRC = QGC::crc32(&fill, 1, _imageCRC);
405 bytesSent++;
406 }
407
408 return true;
409}
410
411bool Bootloader::_ihxProgram(const FirmwareImage* image)
412{
413 uint32_t imageSize = image->imageSize();
414 uint32_t bytesSent = 0;
415
416 for (uint16_t index=0; index<image->ihxBlockCount(); index++) {
417 bool failed;
418 uint16_t flashAddress;
419 QByteArray bytes;
420
421 if (!image->ihxGetBlock(index, flashAddress, bytes)) {
422 _errorString = tr("Unable to retrieve block from ihx: index %1").arg(index);
423 return false;
424 }
425
426 qCDebug(FirmwareUpgradeVerboseLog) << QString("Bootloader::_ihxProgram - address:0x%1 size:%2 block:%3").arg(flashAddress, 8, 16, QLatin1Char('0')).arg(bytes.length()).arg(index);
427
428 // Set flash address
429
430 failed = true;
431 if (_write(PROTO_LOAD_ADDRESS) &&
432 _write(flashAddress & 0xFF) &&
433 _write((flashAddress >> 8) & 0xFF) &&
434 _write(PROTO_EOC)) {
435 _port.flush();
436 if (_getCommandResponse()) {
437 failed = false;
438 }
439 }
440
441 if (failed) {
442 _errorString = tr("Unable to set flash start address: 0x%2").arg(flashAddress, 8, 16, QLatin1Char('0'));
443 return false;
444 }
445
446 // Flash
447
448 int bytesIndex = 0;
449 uint16_t bytesLeftToWrite = bytes.length();
450
451 while (bytesLeftToWrite > 0) {
452 uint8_t bytesToWrite;
453
454 if (bytesLeftToWrite > PROG_MULTI_MAX) {
455 bytesToWrite = PROG_MULTI_MAX;
456 } else {
457 bytesToWrite = bytesLeftToWrite;
458 }
459
460 failed = true;
461 if (_write(PROTO_PROG_MULTI) &&
462 _write(bytesToWrite) &&
463 _write(&((uint8_t *)bytes.data())[bytesIndex], bytesToWrite) &&
464 _write(PROTO_EOC)) {
465 _port.flush();
466 if (_getCommandResponse()) {
467 failed = false;
468 }
469 }
470 if (failed) {
471 _errorString = tr("Flash failed: %1 at address 0x%2").arg(_errorString).arg(flashAddress, 8, 16, QLatin1Char('0'));
472 return false;
473 }
474
475 bytesIndex += bytesToWrite;
476 bytesLeftToWrite -= bytesToWrite;
477 bytesSent += bytesToWrite;
478
479 emit updateProgress(bytesSent, imageSize);
480 }
481 }
482
483 return true;
484}
485
487{
488 bool ret;
489
490 if (!image->imageIsBinFormat() || _bootloaderVersion <= 2) {
491 ret = _verifyBytes(image);
492 } else {
493 ret = _verifyCRC();
494 }
495
496 reboot();
497
498 return ret;
499}
500
502bool Bootloader::_verifyBytes(const FirmwareImage* image)
503{
504 if (image->imageIsBinFormat()) {
505 return _binVerifyBytes(image);
506 } else {
507 return _ihxVerifyBytes(image);
508 }
509}
510
511bool Bootloader::_binVerifyBytes(const FirmwareImage* image)
512{
513 Q_ASSERT(image->imageIsBinFormat());
514
515 QFile firmwareFile(image->binFilename());
516 if (!firmwareFile.open(QIODevice::ReadOnly)) {
517 _errorString = tr("Unable to open firmware file %1: %2").arg(image->binFilename(), firmwareFile.errorString());
518 return false;
519 }
520 uint32_t imageSize = (uint32_t)firmwareFile.size();
521
522 if (!_sendCommand(PROTO_CHIP_VERIFY)) {
523 return false;
524 }
525
526 uint8_t fileBuf[READ_MULTI_MAX];
527 uint8_t readBuf[READ_MULTI_MAX];
528 uint32_t bytesVerified = 0;
529
530 Q_ASSERT(PROG_MULTI_MAX <= 0x8F);
531
532 while (bytesVerified < imageSize) {
533 int bytesToRead = imageSize - bytesVerified;
534 if (bytesToRead > (int)sizeof(readBuf)) {
535 bytesToRead = (int)sizeof(readBuf);
536 }
537
538 Q_ASSERT((bytesToRead % 4) == 0);
539
540 int bytesRead = firmwareFile.read((char *)fileBuf, bytesToRead);
541 if (bytesRead == -1 || bytesRead != bytesToRead) {
542 _errorString = tr("Firmware file read failed: %1").arg(firmwareFile.errorString());
543 return false;
544 }
545
546 Q_ASSERT(bytesToRead <= 0x8F);
547
548 bool failed = true;
549 if (_write(PROTO_READ_MULTI) &&
550 _write((uint8_t)bytesToRead) &&
551 _write(PROTO_EOC)) {
552 _port.flush();
553 if (_read(readBuf, bytesToRead)) {
554 if (_getCommandResponse()) {
555 failed = false;
556 }
557 }
558 }
559 if (failed) {
560 _errorString = tr("Read failed: %1 at address: 0x%2").arg(_errorString).arg(bytesVerified, 8, 16, QLatin1Char('0'));
561 return false;
562 }
563
564 for (int i=0; i<bytesToRead; i++) {
565 if (fileBuf[i] != readBuf[i]) {
566 _errorString = tr("Compare failed: expected(0x%1) actual(0x%2) at address: 0x%3").arg(fileBuf[i], 2, 16, QLatin1Char('0')).arg(readBuf[i], 2, 16, QLatin1Char('0')).arg(bytesVerified + i, 8, 16, QLatin1Char('0'));
567 return false;
568 }
569 }
570
571 bytesVerified += bytesToRead;
572
573 emit updateProgress(bytesVerified, imageSize);
574 }
575
576 firmwareFile.close();
577
578 return true;
579}
580
581bool Bootloader::_ihxVerifyBytes(const FirmwareImage* image)
582{
583 Q_ASSERT(!image->imageIsBinFormat());
584
585 uint32_t imageSize = image->imageSize();
586 uint32_t bytesVerified = 0;
587
588 for (uint16_t index=0; index<image->ihxBlockCount(); index++) {
589 bool failed;
590 uint16_t readAddress;
591 QByteArray imageBytes;
592
593 if (!image->ihxGetBlock(index, readAddress, imageBytes)) {
594 _errorString = tr("Unable to retrieve block from ihx: index %1").arg(index);
595 return false;
596 }
597
598 qCDebug(FirmwareUpgradeLog) << QString("Bootloader::_ihxVerifyBytes - address:0x%1 size:%2 block:%3").arg(readAddress, 8, 16, QLatin1Char('0')).arg(imageBytes.length()).arg(index);
599
600 // Set read address
601
602 failed = true;
603 if (_write(PROTO_LOAD_ADDRESS) &&
604 _write(readAddress & 0xFF) &&
605 _write((readAddress >> 8) & 0xFF) &&
606 _write(PROTO_EOC)) {
607 _port.flush();
608 if (_getCommandResponse()) {
609 failed = false;
610 }
611 }
612
613 if (failed) {
614 _errorString = tr("Unable to set read start address: 0x%2").arg(readAddress, 8, 16, QLatin1Char('0'));
615 return false;
616 }
617
618 // Read back
619
620 int bytesIndex = 0;
621 uint16_t bytesLeftToRead = imageBytes.length();
622
623 while (bytesLeftToRead > 0) {
624 uint8_t bytesToRead;
625 uint8_t readBuf[READ_MULTI_MAX];
626
627 if (bytesLeftToRead > READ_MULTI_MAX) {
628 bytesToRead = READ_MULTI_MAX;
629 } else {
630 bytesToRead = bytesLeftToRead;
631 }
632
633 failed = true;
634 if (_write(PROTO_READ_MULTI) &&
635 _write(bytesToRead) &&
636 _write(PROTO_EOC)) {
637 _port.flush();
638 if (_read(readBuf, bytesToRead)) {
639 if (_getCommandResponse()) {
640 failed = false;
641 }
642 }
643 }
644 if (failed) {
645 _errorString = tr("Read failed: %1 at address: 0x%2").arg(_errorString).arg(readAddress, 8, 16, QLatin1Char('0'));
646 return false;
647 }
648
649 // Compare
650
651 for (int i=0; i<bytesToRead; i++) {
652 if ((uint8_t)imageBytes[bytesIndex + i] != readBuf[i]) {
653 _errorString = tr("Compare failed: expected(0x%1) actual(0x%2) at address: 0x%3")
654 .arg(static_cast<qulonglong>(static_cast<quint8>(imageBytes[bytesIndex + i])), 2, 16, QLatin1Char('0'))
655 .arg(static_cast<qulonglong>(static_cast<quint8>(readBuf[i])), 2, 16, QLatin1Char('0'))
656 .arg(static_cast<qulonglong>(readAddress + i), 8, 16, QLatin1Char('0'));
657 return false;
658 }
659 }
660
661 bytesVerified += bytesToRead;
662 bytesIndex += bytesToRead;
663 bytesLeftToRead -= bytesToRead;
664
665 emit updateProgress(bytesVerified, imageSize);
666 }
667 }
668
669 return true;
670}
671
673bool Bootloader::_verifyCRC(void)
674{
675 uint8_t buf[2] = { PROTO_GET_CRC, PROTO_EOC };
676
677 quint32 flashCRC = 0;
678
679 bool failed = true;
680 if (_write(buf, 2)) {
681 _port.flush();
682 if (_read((uint8_t*)&flashCRC, sizeof(flashCRC), _verifyTimeout)) {
683 if (_getCommandResponse()) {
684 failed = false;
685 }
686 }
687 }
688 if (failed) {
689 return false;
690 }
691
692 if (_imageCRC != flashCRC) {
693 _errorString = tr("CRC mismatch: board(0x%1) file(0x%2)").arg(flashCRC, 4, 16, QLatin1Char('0')).arg(_imageCRC, 4, 16, QLatin1Char('0'));
694 return false;
695 }
696
697 return true;
698}
699
700bool Bootloader::_syncWorker(void)
701{
702 // Send sync command
703 if (_sendCommand(PROTO_GET_SYNC)) {
704 _inBootloaderMode = true;
705 return true;
706 } else {
707 _errorString.prepend("Sync: ");
708 return false;
709 }
710}
711
712bool Bootloader::_sync(void)
713{
714 // Sometimes getting sync is flaky, try 3 times
715 _port.readAll();
716 bool success = false;
717 for (int i=0; i<3; i++) {
718 success = _syncWorker();
719
720 if (success) {
721 return true;
722 }
723 }
724 return success;
725}
726
727bool Bootloader::_get3DRRadioBoardId(uint32_t& boardID)
728{
729 uint8_t buf[2] = { PROTO_GET_DEVICE, PROTO_EOC };
730
731 if (!_write(buf, sizeof(buf))) {
732 goto Error;
733 }
734 _port.flush();
735
736 if (!_read((uint8_t*)buf, 2)) {
737 goto Error;
738 }
739 if (!_getCommandResponse()) {
740 goto Error;
741 }
742
743 boardID = buf[0];
744
745 _bootloaderVersion = 0;
746 _boardFlashSize = 0;
747
748 return true;
749
750Error:
751 _errorString.prepend(tr("Get Board Id: "));
752 return false;
753}
#define QGC_LOGGING_CATEGORY(name, categoryStr)
Bootloader Utility routines. Works with PX4 and 3DR Radio bootloaders.
Definition Bootloader.h:19
bool program(const FirmwareImage *image)
void updateProgress(int curr, int total)
Signals progress indicator for long running bootloader utility routines.
bool erase(void)
static const int boardIDPX4FMUV2
PX4 V2 board, as from USB PID.
Definition Bootloader.h:41
bool reboot(void)
bool initFlashSequence(void)
static const int boardIDPX4FMUV3
Definition Bootloader.h:42
bool open(const QString portName)
Definition Bootloader.cc:21
bool verify(const FirmwareImage *image)
bool getBoardInfo(uint32_t &bootloaderVersion, uint32_t &boardID, uint32_t &flashSize)
Definition Bootloader.cc:68
Support for Intel Hex firmware file.
bool imageIsBinFormat(void) const
QString binFilename(void) const
bool ihxGetBlock(uint16_t index, uint16_t &address, QByteArray &bytes) const
uint32_t imageSize(void) const
Returns the number of bytes in the image.
uint16_t ihxBlockCount(void) const
bool open(OpenMode mode) override
bool setStopBits(StopBits stopBits)
void setPortName(const QString &name)
bool waitForReadyRead(int msecs=30000) override
bool setBaudRate(qint32 baudRate, Directions directions=AllDirections)
bool setDataBits(DataBits dataBits)
bool setParity(Parity parity)
qint64 bytesAvailable() const override
bool setFlowControl(FlowControl flowControl)
Error
Error codes for decompression operations.
quint32 crc32(const quint8 *src, unsigned len, unsigned state)
Definition QGC.cc:97