diff --git a/oscar/tests/prs1tests.cpp b/oscar/tests/prs1tests.cpp index f1cfd470..8b282de4 100644 --- a/oscar/tests/prs1tests.cpp +++ b/oscar/tests/prs1tests.cpp @@ -13,6 +13,7 @@ static PRS1Loader* s_loader = nullptr; static void iterateTestCards(const QString & root, void (*action)(const QString &)); +static QString prs1OutputPath(const QString & inpath, const QString & serial, const QString & basename, const QString & suffix); static QString prs1OutputPath(const QString & inpath, const QString & serial, int session, const QString & suffix); void PRS1Tests::initTestCase(void) @@ -74,9 +75,166 @@ void PRS1Tests::testSessionsToYaml() } +// ==================================================================================================== + +static QString ts(qint64 msecs) +{ + return QDateTime::fromMSecsSinceEpoch(msecs).toString(Qt::ISODate); +} + +static QString byteList(QByteArray data) +{ + QStringList l; + for (int i = 0; i < data.size(); i++) { + l.push_back(QString( "%1" ).arg((int) data[i] & 0xFF, 2, 16, QChar('0') ).toUpper()); + } + QString s = l.join(""); + return s; +} + +void ChunkToYaml(QFile & file, PRS1DataChunk* chunk) +{ + QTextStream out(&file); + + // chunk header + out << "chunk:" << endl; + out << " at: " << hex << chunk->m_filepos << endl; + out << " version: " << dec << chunk->fileVersion << endl; + out << " size: " << chunk->blockSize << endl; + out << " htype: " << chunk->htype << endl; + out << " family: " << chunk->family << endl; + out << " familyVersion: " << chunk->familyVersion << endl; + out << " ext: " << chunk->ext << endl; + out << " session: " << chunk->sessionid << endl; + out << " start: " << ts(chunk->timestamp * 1000L) << endl; + + // hblock for V3 non-waveform chunks + if (chunk->fileVersion == 3 && chunk->htype == 0) { + out << " hblock:" << endl; + QMapIterator i(chunk->hblock); + while (i.hasNext()) { + i.next(); + out << " " << (int) i.key() << ": " << i.value() << endl; + } + } + + // waveform chunks + if (chunk->htype == 1) { + out << " intervals: " << chunk->interval_count << endl; + out << " intervalSeconds: " << (int) chunk->interval_seconds << endl; + out << " interleave:" << endl; + for (int i=0; i < chunk->waveformInfo.size(); i++) { + const PRS1Waveform & w = chunk->waveformInfo.at(i); + out << " " << i << ": " << w.interleave << endl; + } + out << " end: " << ts((chunk->timestamp + chunk->duration) * 1000L) << endl; + } + + // header checksum + out << " checksum: " << hex << chunk->storedChecksum << endl; + if (chunk->storedChecksum != chunk->calcChecksum) { + out << " calcChecksum: " << hex << chunk->calcChecksum << endl; + } + + // data + out << " data: " << byteList(chunk->m_data) << endl; + + // data CRC + out << " crc: " << hex << chunk->storedCrc << endl; + if (chunk->storedCrc != chunk->calcCrc) { + out << " calcCrc: " << hex << chunk->calcCrc << endl; + } + out << endl; +} + +void parseAndEmitChunkYaml(const QString & path) +{ + qDebug() << path; + + QStringList paths; + QString propertyfile; + int sessionid_base; + sessionid_base = s_loader->FindSessionDirsAndProperties(path, paths, propertyfile); + + Machine *m = s_loader->CreateMachineFromProperties(propertyfile); + Q_ASSERT(m != nullptr); + + // This mirrors the functional bits of PRS1Loader::ScanFiles. + + QDir dir; + dir.setFilter(QDir::NoDotAndDotDot | QDir::Dirs | QDir::Files | QDir::Hidden | QDir::NoSymLinks); + dir.setSorting(QDir::Name); + + int size = paths.size(); + + // for each p0/p1/p2/etc... folder + for (int p=0; p < size; ++p) { + dir.setPath(paths.at(p)); + if (!dir.exists() || !dir.isReadable()) { + qWarning() << dir.canonicalPath() << "can't read directory"; + continue; + } + QFileInfoList flist = dir.entryInfoList(); + + // Scan for individual .00X files + for (int i = 0; i < flist.size(); i++) { + QFileInfo fi = flist.at(i); + QString inpath = fi.canonicalFilePath(); + bool ok; + + QString ext_s = fi.fileName().section(".", -1); + ext_s.toInt(&ok); + if (!ok) { + // not a numerical extension + qWarning() << inpath << "unexpected filename"; + continue; + } + + QString session_s = fi.fileName().section(".", 0, -2); + session_s.toInt(&ok, sessionid_base); + if (!ok) { + // not a numerical session ID + qWarning() << inpath << "unexpected filename"; + continue; + } + + // Create the YAML file. + QString outpath = prs1OutputPath(path, m->serial(), fi.fileName(), "-chunks.yml"); + QFile file(outpath); + if (!file.open(QFile::WriteOnly | QFile::Truncate)) { + qDebug() << outpath; + Q_ASSERT(false); + } + + // Parse the chunks in the file. + QList chunks = s_loader->ParseFile(inpath); + for (int i=0; i < chunks.size(); i++) { + // Emit the YAML. + PRS1DataChunk * chunk = chunks.at(i); + ChunkToYaml(file, chunk); + delete chunk; + } + + file.close(); + } + } +} + +void PRS1Tests::testChunksToYaml() +{ + iterateTestCards(TESTDATA_PATH "prs1/input/", parseAndEmitChunkYaml); +} + + // ==================================================================================================== QString prs1OutputPath(const QString & inpath, const QString & serial, int session, const QString & suffix) +{ + QString basename = QString("%1").arg(session, 8, 10, QChar('0')); + return prs1OutputPath(inpath, serial, basename, suffix); +} + +QString prs1OutputPath(const QString & inpath, const QString & serial, const QString & basename, const QString & suffix) { // Output to prs1/output/FOLDER/SERIAL-000000(-session.yml, etc.) QDir path(inpath); @@ -90,7 +248,7 @@ QString prs1OutputPath(const QString & inpath, const QString & serial, int sessi QString filename = QString("%1-%2%3") .arg(serial) - .arg(session, 6, 10, QChar('0')) + .arg(basename) .arg(suffix); return outdir.path() + QDir::separator() + filename; } diff --git a/oscar/tests/prs1tests.h b/oscar/tests/prs1tests.h index 592d7225..5c8f2992 100644 --- a/oscar/tests/prs1tests.h +++ b/oscar/tests/prs1tests.h @@ -18,6 +18,7 @@ class PRS1Tests : public QObject private slots: void initTestCase(); + void testChunksToYaml(); void testSessionsToYaml(); // void test2(); void cleanupTestCase();