34 #include <QApplication>
39 #define TL_DFU_QXTLOG_DEBUG(...) qDebug() << __VA_ARGS__
41 #define TL_DFU_QXTLOG_DEBUG(...)
42 #endif // TL_DFU_DEBUG
44 using namespace tl_dfu;
49 qRegisterMetaType<tl_dfu::Status>(
"TL_DFU::Status");
60 bool DFUObject::EnterDFU()
64 message.v.enter_dfu.device_number = 0;
65 int result = SendData(message);
68 TL_DFU_QXTLOG_DEBUG(QString(
"EnterDFU:%0 bytes sent").arg(result));
84 messagePackets msg = CalculatePadding(numberOfBytes);
87 message.v.xfer_start.expected_crc = ntohl(crc);
88 message.v.xfer_start.packets_in_transfer = ntohl(msg.numberOfPackets);
89 message.v.xfer_start.words_in_last_packet = msg.lastPacketCount;
90 message.v.xfer_start.label = label;
92 TL_DFU_QXTLOG_DEBUG(QString(
"Number of packets:%0 Size of last packet:%1")
93 .arg(msg.numberOfPackets)
94 .arg(msg.lastPacketCount));
96 int result = SendData(message);
97 QEventLoop m_eventloop;
98 QTimer::singleShot(500, &m_eventloop, &QEventLoop::quit);
100 TL_DFU_QXTLOG_DEBUG(QString(
"%0 bytes sent").arg(result));
113 bool DFUObject::UploadData(qint32
const &numberOfBytes, QByteArray &
data)
115 messagePackets msg = CalculatePadding(numberOfBytes);
116 TL_DFU_QXTLOG_DEBUG(QString(
"Start Uploading:%0 56 byte packets").arg(msg.numberOfPackets));
121 int laspercentage = 0;
122 for (quint32 packetcount = 0; packetcount < msg.numberOfPackets; ++packetcount) {
123 percentage = (float)(packetcount + 1) / msg.numberOfPackets * 100;
124 if (laspercentage != (
int)percentage)
126 laspercentage = (int)percentage;
127 if (packetcount == msg.numberOfPackets)
128 packetsize = msg.lastPacketCount;
131 message.v.xfer_cont.current_packet_number = ntohl(packetcount);
132 char *pointer = data.data();
133 pointer = pointer + 4 * 14 * packetcount;
134 CopyWords(pointer, reinterpret_cast<char *>(message.v.xfer_cont.data), packetsize * 4);
135 int result = SendData(message);
162 TL_DFU_QXTLOG_DEBUG(QString(
"DOWNLOAD PARTITION- SETTING DOWNLOAD CONFIG PARTITION=%1 SIZE:%2")
167 threadJob.requestedOperation = ThreadJobStruc::Download;
168 threadJob.requestSize = size;
169 threadJob.requestTransferType = partition;
170 threadJob.requestStorage = firmwareArray;
183 message.v.wipe_partition.label = partition;
184 int result = SendData(message);
195 switch (threadJob.requestedOperation) {
196 case ThreadJobStruc::Download:
197 TL_DFU_QXTLOG_DEBUG(
"DOWNLOAD THREAD STARTED");
198 downloadResult = DownloadPartition(threadJob.requestStorage, threadJob.requestSize,
199 threadJob.requestTransferType);
200 TL_DFU_QXTLOG_DEBUG(
"DOWNLOAD FINISHED");
203 case ThreadJobStruc::Upload:
204 uploadStatus = UploadPartition(*threadJob.requestStorage, threadJob.requestTransferType);
205 TL_DFU_QXTLOG_DEBUG(
"UPLOAD FINISHED");
221 bool DFUObject::DownloadPartition(QByteArray *fw, qint32
const &numberOfBytes,
231 messagePackets msg = CalculatePadding(numberOfBytes);
238 message.v.xfer_start.packets_in_transfer = ntohl(msg.numberOfPackets + offset);
239 message.v.xfer_start.words_in_last_packet = msg.lastPacketCount;
240 message.v.xfer_start.label = partition;
242 int result = SendData(message);
245 TL_DFU_QXTLOG_DEBUG(QString(
"StartDownload %0 Last Packet Size %1 Bytes sent %2")
246 .arg(msg.numberOfPackets)
247 .arg(msg.lastPacketCount)
250 int laspercentage = 0;
253 for (; x < msg.numberOfPackets; ++
x) {
255 percentage = (float)(x + 1) / msg.numberOfPackets * 100;
256 if (laspercentage != (
int)percentage)
258 laspercentage = (int)percentage;
260 result = ReceiveData(message);
264 <<
"Message different from BL_MSG_READ_CONT received while downloading partition";
267 if (ntohl(message.v.xfer_cont.current_packet_number) != (x - offset)) {
269 "Wrong packet number received while downloading partition- %0 vs %1")
270 .arg(ntohl(message.v.xfer_cont.current_packet_number))
272 if (ntohl(message.v.xfer_cont.current_packet_number) > (x - offset)) {
273 if ((numTries--) > 0) {
277 for (
unsigned int i = 0;
i < (msg.numberOfPackets + 10);
i++) {
279 if (ReceiveData(dummy, 400) <= 0) {
291 if (x == msg.numberOfPackets - 1)
292 size = msg.lastPacketCount * 4;
295 fw->append(reinterpret_cast<char *>(message.v.xfer_cont.data), size);
302 TL_DFU_QXTLOG_DEBUG(QString(
"Download operation completed-- %1 bytes").arg(fw->size()));
315 return SendData(message);
321 int DFUObject::AbortOperation(
void)
325 return SendData(message);
335 DFUObject::messagePackets DFUObject::CalculatePadding(quint32 numberOfBytes)
339 msg.numberOfPackets = numberOfBytes / 4 / 14;
340 msg.pad = (numberOfBytes - msg.numberOfPackets * 4 * 14) / 4;
342 msg.lastPacketCount = 14;
344 ++msg.numberOfPackets;
345 msg.lastPacketCount = msg.pad;
361 message.v.jump_fw.safe_word = ntohs((quint16)0x5afe);
363 message.v.jump_fw.safe_word = 0x0000;
365 message.v.jump_fw.unused2[0] = 0;
366 message.v.jump_fw.unused2[1] = 0;
367 return SendData(message);
373 DFUObject::statusReport DFUObject::StatusRequest()
375 DFUObject::statusReport rep;
379 int result = SendData(message);
382 TL_DFU_QXTLOG_DEBUG(QString(
"StatusRequest:%0 bytes sent").arg(result));
383 result = ReceiveData(message);
384 TL_DFU_QXTLOG_DEBUG(QString(
"StatusRequest:%0 bytes received").arg(result));
386 TL_DFU_QXTLOG_DEBUG(QString(
"Status:%0").arg(message.v.status_rep.current_state));
388 rep.additional = (quint32)ntohl(message.v.status_rep.additional_state);
403 TL_DFU_QXTLOG_DEBUG(
"FINDDEVICES BEGIN");
406 message.v.cap_req.device_number = 1;
408 QString(
"FINDDEVICES SENDING CAPABILITIES REQUEST BUFFER_SIZE:%0").arg(BUF_LEN));
409 int result = SendData(message);
410 TL_DFU_QXTLOG_DEBUG(QString(
"FINDDEVICES CAPABILITIES REQUEST BYTES_SENT:%0").arg(result));
412 return currentDevice;
414 result = ReceiveData(message);
415 TL_DFU_QXTLOG_DEBUG(QString(
"FINDDEVICES CAPABILITIES ANSWER BYTES_RECEIVED:%0").arg(result));
417 return currentDevice;
419 currentDevice.
BL_Version = message.v.cap_rep_specific.bl_version;
420 currentDevice.
HW_Rev = message.v.cap_rep_specific.board_rev;
421 if (message.v.cap_rep_specific.cap_extension_magic == BL_CAP_EXTENSION_MAGIC)
422 currentDevice.
CapExt =
true;
424 currentDevice.
CapExt =
false;
425 currentDevice.
SizeOfDesc = message.v.cap_rep_specific.desc_size;
426 currentDevice.
ID = ntohs(message.v.cap_rep_specific.device_id);
427 message.v.cap_rep_specific.device_number = 1;
428 currentDevice.
FW_CRC = ntohl(message.v.cap_rep_specific.fw_crc);
429 currentDevice.
SizeOfCode = ntohl(message.v.cap_rep_specific.fw_size);
430 if (currentDevice.
CapExt) {
431 for (
int partition = 0; partition < 10; ++partition) {
433 ntohl(message.v.cap_rep_specific.partition_sizes[partition]));
437 TL_DFU_QXTLOG_DEBUG(QString(
"Device ID=%0").arg(currentDevice.
ID));
438 TL_DFU_QXTLOG_DEBUG(QString(
"Device SizeOfCode=%0").arg(currentDevice.
SizeOfCode));
439 TL_DFU_QXTLOG_DEBUG(QString(
"Device SizeOfDesc=%0").arg(currentDevice.
SizeOfDesc));
440 TL_DFU_QXTLOG_DEBUG(QString(
"BL Version=%0").arg(currentDevice.
BL_Version));
441 TL_DFU_QXTLOG_DEBUG(QString(
"FW CRC=%0").arg(currentDevice.
FW_CRC));
443 for (
int partition = 0; partition < 10; ++partition)
444 TL_DFU_QXTLOG_DEBUG(QString(
"Partition %0 Size %1")
448 TL_DFU_QXTLOG_DEBUG(
"No partition found, probably using old bootloader");
451 return currentDevice;
463 QEventLoop m_eventloop;
470 QTimer::singleShot(200, &m_eventloop, &QEventLoop::quit);
473 m_hidHandle = hid_open_path(port.
path.toLatin1());
475 QTimer::singleShot(200, &m_eventloop, &QEventLoop::quit);
479 TL_DFU_QXTLOG_DEBUG(QString(
"Could not process enterDFU command"));
487 TL_DFU_QXTLOG_DEBUG(QString(
"Status different that DFUidle after enterDFU command"));
497 TL_DFU_QXTLOG_DEBUG(QString(
"Could not open USB port"));
515 hid_close(m_hidHandle);
524 bool DFUObject::EndOperation()
528 int result = SendData(message);
529 TL_DFU_QXTLOG_DEBUG(QString(
"%0 bytes sent").arg(result));
547 threadJob.requestedOperation = ThreadJobStruc::Upload;
548 threadJob.requestTransferType = partition;
549 threadJob.requestStorage = &sourceArray;
550 threadJob.partition_size = size;
563 DFUObject::statusReport ret;
568 TL_DFU_QXTLOG_DEBUG(
"Starting Firmware Upload...");
570 TL_DFU_QXTLOG_DEBUG(QString(
"Bytes Loaded=%0").arg(sourceArray.length()));
571 if (sourceArray.length() % 4 != 0) {
572 int pad = sourceArray.length() / 4;
575 pad = pad - sourceArray.length();
576 sourceArray.append(QByteArray(pad, 255));
579 if (threadJob.partition_size < (quint32)sourceArray.length()) {
580 TL_DFU_QXTLOG_DEBUG(
"ERROR array too big for device");
585 TL_DFU_QXTLOG_DEBUG(QString(
"NEW FIRMWARE CRC=%0").arg(crc));
587 if (!StartUpload(sourceArray.length(), partition,
crc)) {
588 ret = StatusRequest();
589 qDebug() << QString(
"[tl_dfu] StartUpload failed, status: %1, additional: 0x%2")
590 .arg(StatusToString(ret.status))
591 .arg(ret.additional, 8, 16, QChar(
'0'));
596 TL_DFU_QXTLOG_DEBUG(
"Erasing memory");
598 TL_DFU_QXTLOG_DEBUG(
"returning TL_DFU::abort");
602 ret = StatusRequest();
604 TL_DFU_QXTLOG_DEBUG(QString(
"Erase returned:%0").arg(StatusToString(ret.status)));
608 "[tl_dfu] Couldn't start partition upload, status: %1, additional: 0x%2")
609 .arg(StatusToString(ret.status))
610 .arg(ret.additional, 8, 16, QChar(
'0'));
617 if (!UploadData(sourceArray.length(), sourceArray)) {
618 ret = StatusRequest();
619 qDebug() << QString(
"[tl_dfu] UploadData failed, status: %1, additional: 0x%2")
620 .arg(StatusToString(ret.status))
621 .arg(ret.additional, 8, 16, QChar(
'0'));
625 if (!EndOperation()) {
626 ret = StatusRequest();
627 qDebug() << QString(
"[tl_dfu] EndOperation failed, status: %1, additional: 0x%2")
628 .arg(StatusToString(ret.status))
629 .arg(ret.additional, 8, 16, QChar(
'0'));
633 ret = StatusRequest();
635 qDebug() << QString(
"[tl_dfu] Upload failed, status: %1, additional: 0x%2")
636 .arg(StatusToString(ret.status))
637 .arg(ret.additional, 8, 16, QChar(
'0'));
641 TL_DFU_QXTLOG_DEBUG(QString(
"Status=%0").arg(StatusToString(ret.status)));
642 TL_DFU_QXTLOG_DEBUG(
"Firmware Uploading succeeded");
652 void DFUObject::CopyWords(
char *source,
char *destination,
int count)
654 for (
int x = 0; x < count; x = x + 4) {
655 *(destination +
x) = source[x + 3];
656 *(destination + x + 1) = source[x + 2];
657 *(destination + x + 2) = source[x + 1];
658 *(destination + x + 3) = source[x + 0];
666 quint32 DFUObject::CRC32WideFast(quint32 Crc, quint32 Size, quint32 *Buffer)
669 static const quint32 CrcTable[16] = {
670 0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9,
671 0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005,
672 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61,
673 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD
676 Crc = Crc ^ *(
reinterpret_cast<quint32 *
>(Buffer));
682 Crc = (Crc << 4) ^ CrcTable[Crc >> 28];
683 Crc = (Crc << 4) ^ CrcTable[Crc >> 28];
684 Crc = (Crc << 4) ^ CrcTable[Crc >> 28];
685 Crc = (Crc << 4) ^ CrcTable[Crc >> 28];
686 Crc = (Crc << 4) ^ CrcTable[Crc >> 28];
687 Crc = (Crc << 4) ^ CrcTable[Crc >> 28];
688 Crc = (Crc << 4) ^ CrcTable[Crc >> 28];
689 Crc = (Crc << 4) ^ CrcTable[Crc >> 28];
703 if (array.length() % 4 != 0) {
704 int pad = array.length() / 4;
707 pad = pad - array.length();
708 array.append(QByteArray(pad, 255));
713 if ((
int)Size > array.length()) {
714 TL_DFU_QXTLOG_DEBUG(
"Padding");
715 quint32 pad = Size - array.length();
716 array.append(QByteArray(pad, 255));
719 int maxSize = ((quint32)array.length() > Size) ? Size : array.length();
723 quint32 *
t =
reinterpret_cast<quint32 *
>(malloc(Size));
724 for (
int x = 0; x < maxSize / 4; x++) {
726 aux = (char)array[x * 4 + 3] & 0xFF;
728 aux += (char)array[x * 4 + 2] & 0xFF;
730 aux += (char)array[x * 4 + 1] & 0xFF;
732 aux += (char)array[x * 4 + 0] & 0xFF;
735 quint32 crc = DFUObject::CRC32WideFast(0xFFFFFFFF, Size / 4, reinterpret_cast<quint32 *>(t));
745 int DFUObject::SendData(bl_messages data)
751 char array[
sizeof(bl_messages) + 1];
753 memcpy(array + 1, &data,
sizeof(bl_messages));
757 for (
int i = 0;
i < 10;
i++) {
758 ret = hid_write(m_hidHandle, reinterpret_cast<unsigned char *>(array), BUF_LEN);
761 qDebug() <<
"hid_write returned error" << ret;
762 QThread::usleep(2000);
776 int DFUObject::ReceiveData(bl_messages &data,
int timeoutMS)
782 char array[
sizeof(bl_messages) + 1];
784 hid_read_timeout(m_hidHandle, reinterpret_cast<unsigned char *>(array), BUF_LEN, timeoutMS);
785 memcpy(&data, array + 1,
sizeof(bl_messages));
798 return QString(tr(
"bootloader"));
801 return QString(tr(
"description"));
804 return QString(tr(
"firmware"));
807 return QString(tr(
"settings"));
810 return QString(tr(
"autotune"));
813 return QString(tr(
"log"));
816 return QString(tr(
"extension"));
819 return QString::number(label);
837 return "Wrong packet received";
839 return "Too many packets received";
841 return "Too few packets received";
843 return "Last operation success";
845 return "Downloading";
849 return "Last operation failed";
851 return "Outside Device Capabilities";
853 return "CRC check FAILED";
855 return "Jump to user FW failed";
859 return "Upload Starting";
bool DownloadPartitionThreaded(QByteArray *firmwareArray, dfu_partition_label partition, int size)
device findCapabilities()
void CloseBootloaderComs()
void operationProgress(QString status, int progress)
bool WipePartition(dfu_partition_label partition)
QString partitionStringFromLabel(dfu_partition_label label)
QByteArray DownloadDescriptionAsByteArray(int const &numberOfChars)
bool UploadPartitionThreaded(QByteArray &sourceArray, dfu_partition_label partition, int size)
bool OpenBootloaderComs(USBPortInfo port)
void downloadFinished(bool)
static quint32 CRCFromQBArray(QByteArray array, quint32 Size)
QVector< quint32 > PartitionSizes
QString path
Opaque OS-specific path.
void uploadFinished(tl_dfu::Status)