예제 #1
0
void
Athlete::updateRideFileIntervals()
{
    // iterate over context->athlete->allIntervals as they are now defined
    // and update the RideFile->intervals
    RideItem *which = (RideItem *)treeWidget->selectedItems().first();
    RideFile *current = which->ride();
    current->clearIntervals();
    for (int i=0; i < allIntervals->childCount(); i++) {
        // add the intervals as updated
        IntervalItem *it = (IntervalItem *)allIntervals->child(i);
        current->addInterval(it->start, it->stop, it->text(0));
    }

    // emit signal for interval data changed
    context->notifyIntervalsChanged();

    // set dirty
    which->setDirty(true);
}
예제 #2
0
RideFile *SrmFileReader::openRideFile(QFile &file, QStringList &errorStrings, QList<RideFile*>*) const
{
    if (!file.open(QFile::ReadOnly)) {
        errorStrings << QString("can't open file %1").arg(file.fileName());
        return NULL;
    }
    QDataStream in(&file);
    in.setByteOrder( QDataStream::LittleEndian );

    RideFile *result = new RideFile;
    result->setDeviceType("SRM");
    result->setFileFormat("SRM training files (srm)");
    result->setTag("Sport", "Bike" );

    char magic[4];
    in.readRawData(magic, sizeof(magic));
    if( strncmp(magic, "SRM", 3)){
        errorStrings << QString("Unrecognized file type, missing magic." );
        return NULL;
    }

    int version = magic[3] - '0';
    switch( version ){
      case 5:
      case 6:
      case 7:
        // ok
        break;

      default:
        errorStrings << QString("Unsupported SRM file format version: %1")
            .arg(version);
        return NULL;
    }

    quint16 dayssince1880 = readShort(in);
    quint16 wheelcirc = readShort(in);
    quint8 recint1 = readByte(in);
    quint8 recint2 = readByte(in);
    quint16 blockcnt = readShort(in);
    quint16 markercnt = readShort(in);
    readByte(in); // padding
    quint8 commentlen = readByte(in);

    if( commentlen > 70 )
        commentlen = 70;

    char comment[71];
    in.readRawData(comment, sizeof(comment) - 1);
    comment[commentlen] = '\0';
    result->setTag("Notes", QString(comment) );

    // assert propper markercnt to avoid segfaults
    if( in.status() != QDataStream::Ok ){
        errorStrings << QString("failed to read file header" );
        return NULL;
    }

    result->setRecIntSecs(((double) recint1) / recint2);
    unsigned recintms = (unsigned) round(result->recIntSecs() * 1000.0);

    result->setTag("Wheel Circumference", QString("%1").arg(wheelcirc) );

    QDate date(1880, 1, 1);
    date = date.addDays(dayssince1880);

    QVector<marker> markers(markercnt + 1);
    for (int i = 0; i <= markercnt; ++i) {
        char mcomment[256];
        size_t mcommentlen = version < 6 ? 3 : 255;
        assert( mcommentlen < sizeof(mcomment) );
        in.readRawData(mcomment, mcommentlen );
        mcomment[mcommentlen] = '\0';

        quint8 active = readByte(in);
        quint16 start = readShort(in);
        quint16 end = readShort(in);
        quint16 avgwatts = readShort(in);
        quint16 avghr = readShort(in);
        quint16 avgcad = readShort(in);
        quint16 avgspeed = readShort(in);
        quint16 pwc150 = readShort(in);

    // data fixup: Although the data chunk index in srm files starts
    // with 1, some srmwin wrote files referencing index 0.
    if( end < 1 ) end = 1;
    if( start < 1 ) start = 1;

    // data fixup: some srmwin versions wrote markers with start > end
    if( end < start ){
        markers[i].start = end;
        markers[i].end = start;
    } else {
        markers[i].start = start;
        markers[i].end = end;
    }

        markers[i].note = QString( mcomment);

        if( i == 0 ){
            result->setTag("Athlete Name", QString(mcomment) );
        }

        (void) active;
        (void) avgwatts;
        (void) avghr;
        (void) avgcad;
        (void) avgspeed;
        (void) pwc150;
        (void) wheelcirc;
    }

    // fail early to tell devs whats wrong with file
    if( in.status() != QDataStream::Ok ){
        errorStrings << QString("failed to read marker" );
        return NULL;
    }

    blockhdr *blockhdrs = new blockhdr[blockcnt+1];
    for (int i = 0; i < blockcnt; ++i) {
        // In the .srm files generated by Rainer Clasen's srmcmd,
        // hsecsincemidn is a *signed* 32-bit integer.  I haven't seen a
        // negative value in any .srm files generated by srmwin.exe, but
        // since the number of hundredths of a second in a day is << 2^31,
        // it seems safe to always treat this number as signed.
        qint32 hsecsincemidn = readLong(in);
        blockhdrs[i].chunkcnt = readShort(in);
        blockhdrs[i].dt = QDateTime(date);
        blockhdrs[i].dt = blockhdrs[i].dt.addMSecs(hsecsincemidn * 10);
    }

    // fail early to tell devs whats wrong with file
    if( in.status() != QDataStream::Ok ){
        errorStrings << QString("failed to read block headers" );
        return NULL;
    }

    quint16 zero = readShort(in);
    quint16 slope = readShort(in);
    quint16 datacnt = readShort(in);
    readByte(in); // padding

    // fail early to tell devs whats wrong with file
    if( in.status() != QDataStream::Ok ){
        errorStrings << QString("failed to read calibration data" );
        return NULL;
    }

    result->setTag("Slope", QString("%1")
        .arg( 140.0 / 42781 * slope, 0, 'f', 2) );
    result->setTag("Zero Offset", QString("%1").arg(zero) );

    // SRM5 files have no blocks - synthesize one
    if( blockcnt < 1 ){
        blockcnt = 0;
        blockhdrs[0].chunkcnt = datacnt;
        blockhdrs[0].dt = QDateTime(date);
    }


    int blknum = 0, blkidx = 0, mrknum = 0, interval = 0;
    double km = 0.0, secs = 0.0;

    if (markercnt > 0)
        mrknum = 1;

    for (int i = 0; i < datacnt; ++i) {
        int cad, hr, watts;
        double kph, alt;
        double temp=-255;
        if (version < 7) {
            quint8 ps[3];
            in.readRawData((char*) ps, sizeof(ps));
            cad = readByte(in);
            hr = readByte(in);
            kph = (((((unsigned) ps[1]) & 0xf0) << 3)
                   | (ps[0] & 0x7f)) * 3.0 / 26.0;
            watts = (ps[1] & 0x0f) | (ps[2] << 0x4);
            alt = 0.0;
        }
        else {
            assert(version == 7);
            watts = readShort(in);
            cad = readByte(in);
            hr = readByte(in);

            qint32 kph_tmp = readSignedLong(in);
            kph = kph_tmp < 0 ? 0 : kph_tmp * 3.6 / 1000.0;

            alt = readSignedLong(in);
            temp = 0.1 * readSignedShort(in);
        }

        if (i == 0) {
            result->setStartTime(blockhdrs[blknum].dt);
        }
        if (mrknum < markers.size() && i == markers[mrknum].end) {
            ++interval;
            ++mrknum;
        }

        // markers count from 1
        if ((i > 0) && (mrknum < markers.size()) && (i == markers[mrknum].start - 1))
            ++interval;

        km += result->recIntSecs() * kph / 3600.0;

        double nm = watts / 2.0 / PI / cad * 60.0;
        result->appendPoint(secs, cad, hr, km, kph, nm, watts, alt, 0.0, 0.0, 0.0, 0.0, temp, 0.0, interval);

        ++blkidx;
        if ((blkidx == blockhdrs[blknum].chunkcnt) && (blknum + 1 < blockcnt)) {
            QDateTime end = blockhdrs[blknum].dt.addMSecs(
                recintms * blockhdrs[blknum].chunkcnt);
            ++blknum;
            blkidx = 0;
            QDateTime start = blockhdrs[blknum].dt;
            qint64 endms =
                ((qint64) end.toTime_t()) * 1000 + end.time().msec();
            qint64 startms =
                ((qint64) start.toTime_t()) * 1000 + start.time().msec();
            double diff_secs = (startms - endms) / 1000.0;
            if (diff_secs < result->recIntSecs()) {
                errorStrings << QString("ERROR: time goes backwards by %1 s"
                                        " on trans " "to block %2"
                                        ).arg(diff_secs).arg(blknum);
                secs += result->recIntSecs(); // for lack of a better option
            }
            else {
                secs += diff_secs;
            }
        }
        else {
            secs += result->recIntSecs();
        }
    }

    // assert some points were found. prevents segfault when looking at
    // the overall markers[0].start/.end
    // note: we're not checking in.status() to cope with truncated files

    if( result->dataPoints().size() < 1 ){
        errorStrings << QString("file contains no data points");
        return NULL;
    }

    double last = 0.0;
    for (int i = 1; i < markers.size(); ++i) {
        const marker &marker = markers[i];
        int start = qMin(marker.start, result->dataPoints().size()) - 1;
        double start_secs = result->dataPoints()[start]->secs;
        int end = qMin(marker.end - 1, result->dataPoints().size() - 1);
        double end_secs = result->dataPoints()[end]->secs + result->recIntSecs();
        if( last < start_secs )
            result->addInterval(last, start_secs, "");
        QString note = QString("%1").arg(i);
        if( marker.note.length() )
            note += QString(" ") + marker.note;
        if( start_secs <= end_secs )
            result->addInterval(start_secs, end_secs, note );
        last = end_secs;
    }
    if (!markers.empty() && markers.last().end < result->dataPoints().size()) {
        double start_secs = result->dataPoints().last()->secs + result->recIntSecs();
        result->addInterval(last, start_secs, "");
    }

    file.close();
    return result;
}
예제 #3
0
    int read_page()
    {
        int sum = 0;
        int bytes_read = 0;

        char record_command = read_bytes(1, &bytes_read, &sum); // Always 0x89

        if ((0xff & record_command) == 0x89)
        {
            // 1. page # data
            int page_number = read_bytes(2, &bytes_read, &sum); // Page #
            int data_number = read_bytes(1, &bytes_read, &sum); // # of data in page



            if (page_number == 1 || (page_number == 64010 and secs == 0.0)) {
                // 2. Training Summary data (60 bytes)";
                read_bytes(39, &bytes_read, &sum);

                int record_training_flag = read_bytes(1, &bytes_read, &sum); // Training Flag

                if ((record_training_flag & 0x01) == 0) {
                    // Only new lap
                    rideFile->addInterval(last_interval_secs, secs, QString("%1").arg(interval));
                    last_interval_secs = secs;
                    interval ++;
                }

                read_bytes(20, &bytes_read, &sum); // Don't care
            }

            if (page_number == 1 || (page_number == 64010 and secs == 0.0)) {
                // Section Start time and date data (12 byte)

                int sec = read_bsd_byte(&bytes_read, &sum); // Section start time sec
                int min = read_bsd_byte(&bytes_read, &sum); // Section start time min
                int hour = read_bsd_byte(&bytes_read, &sum); // Section start time hour
                int day = read_bsd_byte(&bytes_read, &sum); // Section start time day
                int month = read_bytes(1, &bytes_read, &sum); // Section start time month
                int year = read_bsd_byte(&bytes_read, &sum); // Section start time year

                QDateTime t = QDateTime(QDate(2000+year,month,day), QTime(hour,min,sec));

                if (secs == 0.0 || rideFile->startTime().toTime_t()<0) {
                    rideFile->setStartTime(t);
                }
                else {
                    int gap = (t.toTime_t() - rideFile->startTime().toTime_t()) - secs;
                    secs += gap;
                }

                read_bytes(5, &bytes_read, &sum); // Don't care

                read_bytes(1, &bytes_read, &sum); // Data Flag
                data_number--;
            }

            for (int i = 0; i < data_number; ++i) {
                read_graph_data(&secs, &bytes_read, &sum);
            }

            int finish = 259-bytes_read;

            for (int i = 0; i < finish; i++) {
                read_bytes(1, &bytes_read, &sum); // to finish
            }

            read_bytes(1, &bytes_read, &sum); // Checksum
        }

        return bytes_read;
    }
예제 #4
0
RideFile *SrmFileReader::openRideFile(QFile &file, QStringList &errorStrings) const
{
    if (!file.open(QFile::ReadOnly)) {
        errorStrings << QString("can't open file %1").arg(file.fileName());
        return NULL;
    }
    QDataStream in(&file);
    RideFile *result = new RideFile;
    result->setDeviceType("SRM");

    char magic[4];
    in.readRawData(magic, sizeof(magic));
    assert(strncmp(magic, "SRM", 3) == 0);
    int version = magic[3] - '0';
    assert(version == 5 || version == 6 || version == 7);

    quint16 dayssince1880 = readShort(in);
    quint16 wheelcirc = readShort(in);
    quint8 recint1 = readByte(in);
    quint8 recint2 = readByte(in);
    quint16 blockcnt = readShort(in);
    quint16 markercnt = readShort(in);
    readByte(in); // padding
    quint8 commentlen = readByte(in);

    char comment[71];
    in.readRawData(comment, sizeof(comment) - 1);
    comment[commentlen - 1] = '\0';

    result->setRecIntSecs(((double) recint1) / recint2);
    unsigned recintms = (unsigned) round(result->recIntSecs() * 1000.0);

    QDate date(1880, 1, 1);
    date = date.addDays(dayssince1880);

    QVector<marker> markers(markercnt + 1);
    for (int i = 0; i <= markercnt; ++i) {
        char mcomment[256];
        size_t mcommentlen = version < 6 ? 3 : 255;
        assert( mcommentlen < sizeof(mcomment) );
        in.readRawData(mcomment, mcommentlen );
        mcomment[mcommentlen] = '\0';

        quint8 active = readByte(in);
        quint16 start = readShort(in);
        quint16 end = readShort(in);
        quint16 avgwatts = readShort(in);
        quint16 avghr = readShort(in);
        quint16 avgcad = readShort(in);
        quint16 avgspeed = readShort(in);
        quint16 pwc150 = readShort(in);

	// data fixup: Although the data chunk index in srm files starts
	// with 1, some srmwin wrote files referencing index 0.
	if( end < 1 ) end = 1;
	if( start < 1 ) start = 1;

	// data fixup: some srmwin versions wrote markers with start > end
	if( end < start ){
		markers[i].start = end;
		markers[i].end = start;
	} else {
		markers[i].start = start;
		markers[i].end = end;
	}

        (void) active;
        (void) avgwatts;
        (void) avghr;
        (void) avgcad;
        (void) avgspeed;
        (void) pwc150;
        (void) wheelcirc;
    }

    blockhdr *blockhdrs = new blockhdr[blockcnt+1];
    for (int i = 0; i < blockcnt; ++i) {
        // In the .srm files generated by Rainer Clasen's srmcmd,
        // hsecsincemidn is a *signed* 32-bit integer.  I haven't seen a
        // negative value in any .srm files generated by srmwin.exe, but
        // since the number of hundredths of a second in a day is << 2^31,
        // it seems safe to always treat this number as signed.
        qint32 hsecsincemidn = readLong(in);
        blockhdrs[i].chunkcnt = readShort(in);
        blockhdrs[i].dt = QDateTime(date);
        blockhdrs[i].dt = blockhdrs[i].dt.addMSecs(hsecsincemidn * 10);
    }

    quint16 zero = readShort(in);
    quint16 slope = readShort(in);
    quint16 datacnt = readShort(in);
    readByte(in); // padding

    (void) zero;
    (void) slope;

    // SRM5 files have no blocks - synthesize one
    if( blockcnt < 1 ){
        blockcnt = 0;
        blockhdrs[0].chunkcnt = datacnt;
        blockhdrs[0].dt = QDateTime(date);
    }


    int blknum = 0, blkidx = 0, mrknum = 0, interval = 0;
    double km = 0.0, secs = 0.0;

    if (markercnt > 0)
        mrknum = 1;

    for (int i = 0; i < datacnt; ++i) {
        int cad, hr, watts;
        double kph, alt;
        if (version < 7) {
            quint8 ps[3];
            in.readRawData((char*) ps, sizeof(ps));
            cad = readByte(in);
            hr = readByte(in);
            kph = (((((unsigned) ps[1]) & 0xf0) << 3)
                   | (ps[0] & 0x7f)) * 3.0 / 26.0;
            watts = (ps[1] & 0x0f) | (ps[2] << 0x4);
            alt = 0.0;
        }
        else {
            assert(version == 7);
            watts = readShort(in);
            cad = readByte(in);
            hr = readByte(in);
            kph = readLong(in) * 3.6 / 1000.0;
            alt = readLong(in);
            double temp = 0.1 * (qint16) readShort(in);
            (void) temp; // unused for now
        }

        if (i == 0) {
            result->setStartTime(blockhdrs[blknum].dt);
        }
        if (mrknum < markers.size() && i == markers[mrknum].end) {
            ++interval;
            ++mrknum;
        }

        // markers count from 1
        if ((i > 0) && (mrknum < markers.size()) && (i == markers[mrknum].start - 1))
            ++interval;

        km += result->recIntSecs() * kph / 3600.0;

        double nm = watts / 2.0 / PI / cad * 60.0;
        result->appendPoint(secs, cad, hr, km, kph, nm, watts, alt, 0.0, 0.0, 0.0, interval);

        ++blkidx;
        if ((blkidx == blockhdrs[blknum].chunkcnt) && (blknum + 1 < blockcnt)) {
            QDateTime end = blockhdrs[blknum].dt.addMSecs(
                recintms * blockhdrs[blknum].chunkcnt);
            ++blknum;
            blkidx = 0;
            QDateTime start = blockhdrs[blknum].dt;
            qint64 endms =
                ((qint64) end.toTime_t()) * 1000 + end.time().msec();
            qint64 startms =
                ((qint64) start.toTime_t()) * 1000 + start.time().msec();
            double diff_secs = (startms - endms) / 1000.0;
            if (diff_secs < result->recIntSecs()) {
                errorStrings << QString("ERROR: time goes backwards by %1 s"
                                        " on trans " "to block %2"
                                        ).arg(diff_secs).arg(blknum);
                secs += result->recIntSecs(); // for lack of a better option
            }
            else {
                secs += diff_secs;
            }
        }
        else {
            secs += result->recIntSecs();
        }
    }

    double last = 0.0;
    for (int i = 1; i < markers.size(); ++i) {
        const marker &marker = markers[i];
        int start = marker.start - 1;
        double start_secs = result->dataPoints()[start]->secs;
        int end = qMin(marker.end - 1, result->dataPoints().size() - 1);
        double end_secs = result->dataPoints()[end]->secs + result->recIntSecs();
        result->addInterval(last, start_secs, "");
        result->addInterval(start_secs, end_secs, QString("%1").arg(i));
        last = end_secs;
    }
    if (!markers.empty() && markers.last().end < result->dataPoints().size()) {
        double start_secs = result->dataPoints().last()->secs + result->recIntSecs();
        result->addInterval(last, start_secs, "");
    }

    file.close();
    return result;
}