bool MacroDevice::download( const QDir &tmpdir, QList<DeviceDownloadFile> &files, CancelCallback cancelCallback, ProgressCallback progressCallback, QString &err) { if (MACRO_DEBUG) printf("download O-Synce Macro"); if (!dev->open(err)) { err = "ERROR: open failed: " + err; return false; } statusCallback("Request number of training..."); if (MACRO_DEBUG) printf("Request number of training\n"); MacroPacket cmd(NUMBER_OF_TRAINING_REQUESTS); cmd.addToPayload(UNKNOWN); if (!cmd.write(dev, err)) return false; if (cancelCallback()) { err = "download cancelled"; return false; } MacroPacket response = MacroPacket(); response.read(dev, 2, err); if (response.payload.size() == 0) { err = "no data"; return false; } char count = response.payload.at(0); if (count == 0) { err = "no data"; return false; } response.read(dev, 7*count, err); if (!response.verifyCheckSum(dev, err)) { err = "data error"; return false; } if (cancelCallback()) { err = "download cancelled"; return false; } // create temporary file QString tmpl = tmpdir.absoluteFilePath(".macrodl.XXXXXX"); QTemporaryFile tmp(tmpl); tmp.setAutoRemove(false); if (!tmp.open()) { err = "Failed to create temporary file " + tmpl + ": " + tmp.error(); return false; } if (MACRO_DEBUG) printf("Acknowledge"); cmd= MacroPacket(ACKNOWLEDGE); cmd.addToPayload(response.command); if (!cmd.write(dev, err)) return false; // timestamp from the first training struct tm start; start.tm_sec = bcd2Int(response.payload.at(2)); start.tm_min = bcd2Int(response.payload.at(3)); start.tm_hour = bcd2Int(response.payload.at(4)); start.tm_mday = bcd2Int(response.payload.at(5)); start.tm_mon = hex2Int(response.payload.at(6)) -1; start.tm_year = bcd2Int(response.payload.at(7)) -100; start.tm_isdst = -1; DeviceDownloadFile file; file.extension = "osyn"; file.name = tmp.fileName(); file.startTime.setTime_t( mktime( &start )); files.append(file); QTextStream os(&tmp); os << hex; for (int i = 0; i < count; i++) { if (MACRO_DEBUG) printf("Request training %d\n",i); statusCallback( QString("Request datas of training %1 / %2...") .arg(i+1).arg((int)count) ); if (cancelCallback()) { err = "download cancelled"; return false; } cmd = MacroPacket(TRAINING_DETAIL_REQUEST); cmd.addToPayload(i); if (!cmd.write(dev, err)) return false; if (cancelCallback()) { err = "download cancelled"; return false; } bool lastpage = false; while (!lastpage) { MacroPacket response2 = MacroPacket(); response2.read(dev, 259, err); if (!response2.verifyCheckSum(dev, err)) { err = "data error"; return false; } if (hexHex2Int(response2.payload.at(0), response2.payload.at(1)) == LAST_PAGE) lastpage = true; //int training_flag = hex2Int(response2.payload.at(43)); tmp.write(response2.dataArray()); progressCallback( QString("training %1/%2... (%3 Bytes)") .arg(i+1) .arg((int)count) .arg(tmp.size()) ); if (cancelCallback()) { err = "download cancelled"; return false; } if (MACRO_DEBUG) printf("Acknowledge\n"); cmd= MacroPacket(ACKNOWLEDGE); cmd.addToPayload(response2.command); if (!cmd.write(dev, err)) return false; } } tmp.close(); dev->close(); // QTemporaryFile initially has permissions set to 0600. // Make it readable by everyone. tmp.setPermissions(tmp.permissions() | QFile::ReadOwner | QFile::ReadUser | QFile::ReadGroup | QFile::ReadOther); return true; }
bool PowerTapDevice::download( const QDir &tmpdir, QList<DeviceDownloadFile> &files, CancelCallback cancelCallback, ProgressCallback progressCallback, QString &err) { if (!dev->open(err)) { err = "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; statusCallback( "Reading version..." ); if (cancelCallback()) { err = "download cancelled"; return false; } version_len = readUntilNewline(dev, vbuf, sizeof(vbuf), err); if (version_len < 0) { err = "Error reading version: " + err; return false; } if (PT_DEBUG) { printf("read version \"%s\"\n", cEscape(vbuf, version_len).toAscii().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("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"); statusCallback( "Reading header..." ); if (cancelCallback()) { err = "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 = "ERROR: reading header: " + err; else err = "ERROR: timeout reading header"; return false; } if (PT_DEBUG) { printf("read header \"%s\"\n", cEscape((char*) header, sizeof(header)).toAscii().constData()); } QVector<unsigned char> records; for (size_t i = 0; i < sizeof(header); ++i) records.append(header[i]); statusCallback( "Reading ride data..." ); if (cancelCallback()) { err = "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 = "ERROR: reading first two: " + err; else err = "ERROR: timeout reading first two"; return false; } if (PT_DEBUG) { printf("read 2 bytes: \"%s\"\n", cEscape((char*) buf, 2).toAscii().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 = "ERROR: reading block: " + err; return false; } if (n == 0) { err = "ERROR: timeout reading block"; return false; } if (PT_DEBUG) { printf("read %d bytes: \"%s\"\n", n, cEscape((char*) buf + count, n).toAscii().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 = "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); progressCallback( QString("progress: %1:%2") .arg(min / 60) .arg(min % 60, 2, 10, QLatin1Char('0'))); } if (cancelCallback()) { err = "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 = "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 = "Failed to find ride time."; tmp.setAutoRemove(true); return false; } files << file; return true; }