wiRedPanda
Logic Circuit Simulator
Loading...
Searching...
No Matches
DolphinFile.cpp
Go to the documentation of this file.
1// Copyright 2015 - 2026, GIBIS-UNIFESP and the wiRedPanda contributors
2// SPDX-License-Identifier: GPL-3.0-or-later
3
5
6#include <QCoreApplication>
7#include <QDataStream>
8#include <QFile>
9#include <QSaveFile>
10#include <QTextStream>
11
13#include "App/Core/Common.h"
15
16namespace DolphinFile {
17
18void save(const SignalModel &model, const QString &fileName, const int inputPorts)
19{
20 // QSaveFile writes to a temp file and atomically renames on commit,
21 // preventing data loss if the process is interrupted during a write
22 QSaveFile file(fileName);
23
24 if (!file.open(QIODevice::WriteOnly)) {
25 throw PANDACEPTION_WITH_CONTEXT("BewavedDolphin", "Error opening file: %1", file.errorString());
26 }
27
28 if (fileName.endsWith(".dolphin")) {
29 qCDebug(zero) << "Saving dolphin file.";
30 QDataStream stream(&file);
32 DolphinSerializer::saveBinary(stream, &model, inputPorts);
33 } else {
34 qCDebug(zero) << "Saving CSV file.";
35 DolphinSerializer::saveCSV(file, &model);
36 }
37
38 if (!file.commit()) {
39 throw PANDACEPTION_WITH_CONTEXT("BewavedDolphin", "Error saving file: %1", file.errorString());
40 }
41}
42
43DolphinSerializer::WaveformData load(const QString &fileName, const int maxInputPorts)
44{
45 QFile file(fileName);
46
47 if (!file.exists()) {
48 throw PANDACEPTION_WITH_CONTEXT("BewavedDolphin", "File \"%1\" does not exist!", fileName);
49 }
50
51 if (!file.open(QIODevice::ReadOnly)) {
52 qCDebug(zero) << "Could not open file in ReadOnly mode: " << file.errorString();
53 throw PANDACEPTION_WITH_CONTEXT("BewavedDolphin", "Could not open file for reading: %1", file.errorString());
54 }
55
57
58 if (fileName.endsWith(".dolphin")) {
59 qCDebug(zero) << "Dolphin file opened.";
60 QDataStream stream(&file);
62 data = DolphinSerializer::loadBinary(stream, maxInputPorts);
63 } else if (fileName.endsWith(".csv")) {
64 qCDebug(zero) << "CSV file opened.";
65 data = DolphinSerializer::loadCSV(file, maxInputPorts);
66 } else {
67 qCDebug(zero) << "Format not supported. Could not open file: " << fileName;
68 throw PANDACEPTION_WITH_CONTEXT("BewavedDolphin", "Format not supported. Could not open file: %1", fileName);
69 }
70
71 file.close();
72 return data;
73}
74
75DolphinSerializer::WaveformData parseTerminal(QTextStream &in, const int maxInputPorts)
76{
77 // Protocol: first line is "rows,cols"; subsequent lines contain comma-separated 0/1
78 // values per row. This allows driving the simulator from scripts without a GUI dialog.
79 QString str = in.readLine();
80 const auto wordList(str.split(','));
81
82 if (wordList.size() < 2) {
83 throw PANDACEPTION_WITH_CONTEXT("BewavedDolphin", "Invalid header: expected 'rows,cols' on the first line.");
84 }
85
86 int rows = wordList.at(0).toInt();
87 const int cols = wordList.at(1).toInt();
88
89 if (rows <= 0) {
90 throw PANDACEPTION_WITH_CONTEXT("BewavedDolphin", "Invalid row count %1: must be positive.", QString::number(rows));
91 }
92
93 // Clamp rows to the number of actual input ports to avoid out-of-bounds writes
94 if (rows > maxInputPorts) {
95 rows = maxInputPorts;
96 }
97
98 if ((cols < 1) || (cols > SignalModel::kMaxColumns)) {
99 throw PANDACEPTION_WITH_CONTEXT("BewavedDolphin", "Invalid column count %1: must be between 1 and %2.", QString::number(cols), QString::number(SignalModel::kMaxColumns));
100 }
101
103 data.inputPorts = rows;
104 data.columns = cols;
105 data.values.resize(rows * cols);
106
107 for (int row = 0; row < rows; ++row) {
108 str = in.readLine();
109 const auto wordList2(str.split(','));
110
111 if (wordList2.size() < cols) {
112 throw PANDACEPTION_WITH_CONTEXT("BewavedDolphin", "Row %1 has %2 value(s) but %3 are required.", QString::number(row), QString::number(wordList2.size()), QString::number(cols));
113 }
114
115 for (int col = 0; col < cols; ++col) {
116 data.values[row * cols + col] = wordList2.at(col).toInt();
117 }
118 }
119
120 return data;
121}
122
123} // namespace DolphinFile
Common logging utilities, the Pandaception error type, and helper macros.
#define PANDACEPTION_WITH_CONTEXT(context, msg,...)
Definition Common.h:102
#define qCDebug(category)
Definition Common.h:29
DolphinFile: reads/writes a SignalModel to .dolphin/.csv files on disk.
Circuit and waveform file serialization/deserialization utilities.
SignalModel for the beWavedDolphin waveform table.
static void readDolphinHeader(QDataStream &stream)
Reads and validates the BeWavedDolphin waveform file header.
static void writeDolphinHeader(QDataStream &stream)
Writes the BeWavedDolphin waveform file header to stream.
QStandardItemModel subclass that makes all cells non-editable.
Definition SignalModel.h:21
static constexpr int kMaxColumns
Definition SignalModel.h:38
Disk I/O for the beWavedDolphin formats: opens the file, dispatches by extension (....
DolphinSerializer::WaveformData parseTerminal(QTextStream &in, const int maxInputPorts)
DolphinSerializer::WaveformData load(const QString &fileName, const int maxInputPorts)
void save(const SignalModel &model, const QString &fileName, const int inputPorts)
Writes model to fileName atomically, choosing the format by extension.
void saveBinary(QDataStream &stream, const QStandardItemModel *model, const int inputPorts)
Serializes input rows to the binary .dolphin stream.
void saveCSV(QSaveFile &file, const QStandardItemModel *model)
Serializes all rows (inputs + outputs) to a .csv file.
WaveformData loadCSV(QFile &file, const int maxInputPorts)
Deserializes input rows from a .csv file.
WaveformData loadBinary(QDataStream &stream, const int maxInputPorts)
Deserializes input rows from a binary .dolphin stream.
Raw waveform data returned by the load functions.
Definition Serializer.h:33
int inputPorts
Number of input rows stored in values.
Definition Serializer.h:34
QVector< int > values
Cell values in row-major order (inputs only): index = row * columns + col.
Definition Serializer.h:37