bool MacroPacket::read(CommPortPtr dev, int len, QString &err) { if (command == 0) { if (MACRO_DEBUG) printf("reading command from device\n"); int n = dev->read(&command, 1, err); if (n <= 0) { err = (n < 0) ? (tr("read command error: ") + err) : tr("read timeout"); return false; } checksum += command; len--; if (MACRO_DEBUG) printf("command %s\n" ,cEscape(&command,n).toLatin1().constData()); } if (MACRO_DEBUG) printf("reading %d from device\n", len); char buf[len]; int n = dev->read(&buf, len, err); if (n <= 0) { err = (n < 0) ? (tr("read error: ") + err) : tr("read timeout"); return false; } else if (n < len) { err += QString(tr(", read only %1 bytes instead of: %2")) .arg(n).arg(len); return false; } if (MACRO_DEBUG) printf("payload %s\n" ,cEscape(buf,n).toLatin1().constData()); addToPayload(buf,n); return true; }
int PowerTapDevice::readUntilNewline(CommPortPtr dev, char *buf, int len, QString &err) { int sofar = 0; while (!hasNewline(buf, sofar)) { assert(sofar < len); // Read one byte at a time to avoid waiting for timeout. int n = dev->read(buf + sofar, 1, err); if (n <= 0) { err = (n < 0) ? (tr("read error: ") + err) : tr("read timeout"); err += QString(tr(", read %1 bytes so far: \"%2\"")) .arg(sofar).arg(cEscape(buf, sofar)); return -1; } sofar += n; } return sofar; }
bool MacroPacket::write(CommPortPtr dev, QString &err) { const char *msg = cEscape(data(), payload.count()+2).toLatin1().constData(); if (MACRO_DEBUG) printf("writing '%s' to device\n", msg); int n = dev->write(data(), payload.count()+2, err); if (n != payload.count()+2) { if (n < 0) { if (MACRO_DEBUG) printf("failed to write %s to device: %s\n", msg, err.toLatin1().constData()); err = QString(tr("failed to write to device: %1")).arg(err); } else { if (MACRO_DEBUG) printf("timeout writing %s to device\n", msg); err = QString(tr("timeout writing to device")); } return false; } if (MACRO_DEBUG) printf("writing to device ok\n"); return true; }
bool PowerTapDevice::download( const QDir &tmpdir, QList<DeviceDownloadFile> &files, QString &err) { if (!dev->open(err)) { err = tr("ERROR: open failed: ") + err; return false; } // make several attempts at reading the version int attempts = 3; int veridx = -1; int version_len; char vbuf[256]; QByteArray version; do { if (!doWrite(dev, 0x56, false, err)) // 'V' return false; emit updateStatus( tr("Reading version...") ); if(m_Cancelled) { err = tr("download cancelled"); return false; } version_len = readUntilNewline(dev, vbuf, sizeof(vbuf), err); if (version_len < 0) { err = tr("Error reading version: ") + err; return false; } if (PT_DEBUG) { printf("read version \"%s\"\n", cEscape(vbuf, version_len).toLatin1().constData()); } version = QByteArray(vbuf, version_len); // We expect the version string to be something like // "VER 02.21 PRO...", so if we see two V's, it's probably // because there's a hardware echo going on. veridx = version.indexOf("VER"); } while ((--attempts > 0) && (veridx < 0)); if (veridx < 0) { err = QString(tr("Unrecognized version \"%1\"")) .arg(cEscape(vbuf, version_len)); return false; } bool hwecho = version.indexOf('V') < veridx; if (PT_DEBUG) printf("hwecho=%s\n", hwecho ? "true" : "false"); emit updateStatus( tr("Reading header...") ); if(m_Cancelled) { err = tr("download cancelled"); return false; } if (!doWrite(dev, 0x44, hwecho, err)) // 'D' return false; unsigned char header[6]; int header_len = dev->read(header, sizeof(header), err); if (header_len != 6) { if (header_len < 0) err = tr("ERROR: reading header: ") + err; else err = tr("ERROR: timeout reading header"); return false; } if (PT_DEBUG) { printf("read header \"%s\"\n", cEscape((char*) header, sizeof(header)).toLatin1().constData()); } QVector<unsigned char> records; for (size_t i = 0; i < sizeof(header); ++i) records.append(header[i]); emit updateStatus( tr("Reading data...") ); if(m_Cancelled) { err = tr("download cancelled"); return false; } double recIntSecs = 0.0; fflush(stdout); while (true) { if (PT_DEBUG) printf("reading block\n"); unsigned char buf[256 * 6 + 1]; int n = dev->read(buf, 2, err); if (n < 2) { if (n < 0) err = tr("ERROR: reading first two: ") + err; else err = tr("ERROR: timeout reading first two"); return false; } if (PT_DEBUG) { printf("read 2 bytes: \"%s\"\n", cEscape((char*) buf, 2).toLatin1().constData()); } if (hasNewline((char*) buf, 2)) break; unsigned count = 2; while (count < sizeof(buf)) { n = dev->read(buf + count, sizeof(buf) - count, err); if (n < 0) { err = tr("ERROR: reading block: ") + err; return false; } if (n == 0) { err = tr("ERROR: timeout reading block"); return false; } if (PT_DEBUG) { printf("read %d bytes: \"%s\"\n", n, cEscape((char*) buf + count, n).toLatin1().constData()); } count += n; } unsigned csum = 0; for (int i = 0; i < ((int) sizeof(buf)) - 1; ++i) csum += buf[i]; if ((csum % 256) != buf[sizeof(buf) - 1]) { err = tr("ERROR: bad checksum"); return false; } if (PT_DEBUG) printf("good checksum\n"); for (size_t i = 0; i < sizeof(buf) - 1; ++i) records.append(buf[i]); if (recIntSecs == 0.0) { unsigned char *data = records.data(); bool bIsVer81 = PowerTapUtil::is_Ver81(data); for (int i = 0; i < records.size(); i += 6) { if (PowerTapUtil::is_config(data + i, bIsVer81)) { unsigned unused1, unused2, unused3; PowerTapUtil::unpack_config( data + i, &unused1, &unused2, &recIntSecs, &unused3, bIsVer81); } } } if (recIntSecs != 0.0) { int min = (int) round(records.size() / 6 * recIntSecs); emit updateProgress( QString(tr("progress: %1:%2")) .arg(min / 60) .arg(min % 60, 2, 10, QLatin1Char('0'))); } if(m_Cancelled){ err = tr("download cancelled"); return false; } if (!doWrite(dev, 0x71, hwecho, err)) // 'q' return false; } QString tmpl = tmpdir.absoluteFilePath(".ptdl.XXXXXX"); QTemporaryFile tmp(tmpl); tmp.setAutoRemove(false); if (!tmp.open()) { err = tr("Failed to create temporary file ") + tmpl + ": " + tmp.error(); return false; } // QTemporaryFile initially has permissions set to 0600. // Make it readable by everyone. tmp.setPermissions(tmp.permissions() | QFile::ReadOwner | QFile::ReadUser | QFile::ReadGroup | QFile::ReadOther); DeviceDownloadFile file; file.extension = "raw"; file.name = tmp.fileName(); QTextStream os(&tmp); os << hex; os.setPadChar('0'); bool time_set = false; unsigned char *data = records.data(); bool bIsVer81 = PowerTapUtil::is_Ver81(data); for (int i = 0; i < records.size(); i += 6) { if (data[i] == 0 && !bIsVer81) continue; for (int j = 0; j < 6; ++j) { os.setFieldWidth(2); os << data[i+j]; os.setFieldWidth(1); os << ((j == 5) ? "\n" : " "); } if (!time_set && PowerTapUtil::is_time(data + i, bIsVer81)) { struct tm time; time_t timet = PowerTapUtil::unpack_time(data + i, &time, bIsVer81); file.startTime.setTime_t( timet ); time_set = true; } } if (!time_set) { err = tr("Failed to find start time."); tmp.setAutoRemove(true); return false; } // hack for CERVO bug dates >= 2016 set the year to 2000 (!) if (file.startTime.date().year() == 2000) { // it's in the past... so set year to this QDate date(QDate::currentDate().year(), file.startTime.date().month(), file.startTime.date().day()); // is that a future date? if (date > QDate::currentDate()) date = date.addYears(-1); // now update for file, if it's valid otherwise keep as it is if(date.isValid()) file.startTime.setDate(date); } files << file; return true; }