Warning, file /education/labplot/src/backend/datasources/filters/CANFilter.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002     File                 : CANFilter.cpp
0003     Project              : LabPlot
0004     Description          : I/O-filter for parsing CAN files which need a dbc file to parse data
0005     --------------------------------------------------------------------
0006     SPDX-FileCopyrightText: 2023 Martin Marmsoler <martin.marmsoler@gmail.com>
0007     SPDX-License-Identifier: GPL-3.0-or-later
0008 */
0009 
0010 #include "backend/datasources/filters/CANFilter.h"
0011 #include "backend/core/column/Column.h"
0012 #include "backend/datasources/AbstractDataSource.h"
0013 #include "backend/datasources/filters/CANFilterPrivate.h"
0014 #include "backend/lib/XmlStreamReader.h"
0015 #include "backend/lib/macros.h"
0016 
0017 //////////////////////////////////////////////////////////////////////
0018 CANFilter::CANFilter(FileType type, CANFilterPrivate* p)
0019     : AbstractFileFilter(type)
0020     , d(p) {
0021 }
0022 
0023 CANFilter::~CANFilter() = default;
0024 
0025 /*!
0026   reads the content of the file \c fileName to the data source \c dataSource.
0027 */
0028 void CANFilter::readDataFromFile(const QString& fileName, AbstractDataSource* dataSource, AbstractFileFilter::ImportMode mode) {
0029     d->readDataFromFile(fileName, dataSource, mode);
0030 }
0031 
0032 /*!
0033 writes the content of the data source \c dataSource to the file \c fileName.
0034 */
0035 void CANFilter::write(const QString& fileName, AbstractDataSource* dataSource) {
0036     d->write(fileName, dataSource);
0037 }
0038 
0039 ///////////////////////////////////////////////////////////////////////
0040 
0041 QStringList CANFilter::lastErrors() {
0042     return d->lastErrors();
0043 }
0044 
0045 QStringList CANFilter::vectorNames() const {
0046     return d->m_signals.signal_names;
0047 }
0048 
0049 void CANFilter::setConvertTimeToSeconds(bool convert) {
0050     if (convert == d->convertTimeToSeconds)
0051         return;
0052     d->clearParseState();
0053     d->convertTimeToSeconds = convert;
0054 }
0055 
0056 void CANFilter::setTimeHandlingMode(TimeHandling mode) {
0057     if (mode == d->timeHandlingMode)
0058         return;
0059     d->clearParseState();
0060     d->timeHandlingMode = mode;
0061 }
0062 
0063 QString CANFilter::fileInfoString(const QString& fileName) {
0064     DEBUG(Q_FUNC_INFO);
0065     QString info;
0066 
0067     Q_UNUSED(fileName);
0068     return info;
0069 }
0070 
0071 bool CANFilter::setDBCFile(const QString& file) {
0072     return d->setDBCFile(file);
0073 }
0074 
0075 QVector<QStringList> CANFilter::preview(const QString& filename, int lines) {
0076     return d->preview(filename, lines);
0077 }
0078 
0079 const QVector<AbstractColumn::ColumnMode> CANFilter::columnModes() const {
0080     return d->columnModes();
0081 }
0082 
0083 std::vector<void*> CANFilter::dataContainer() const {
0084     return d->m_DataContainer.dataContainer();
0085 }
0086 
0087 // #####################################################################
0088 // ################### Private implementation ##########################
0089 // #####################################################################
0090 void CANFilterPrivate::DataContainer::clear() {
0091     for (uint i = 0; i < m_dataContainer.size(); i++) {
0092         switch (m_columnModes.at(i)) {
0093         case AbstractColumn::ColumnMode::BigInt:
0094             delete static_cast<QVector<qint64>*>(m_dataContainer[i]);
0095             break;
0096         case AbstractColumn::ColumnMode::Integer:
0097             delete static_cast<QVector<qint32>*>(m_dataContainer[i]);
0098             break;
0099         case AbstractColumn::ColumnMode::Double:
0100             delete static_cast<QVector<double>*>(m_dataContainer[i]);
0101             break;
0102         // TODO: implement missing cases
0103         case AbstractColumn::ColumnMode::Text:
0104         case AbstractColumn::ColumnMode::Month:
0105         case AbstractColumn::ColumnMode::Day:
0106         case AbstractColumn::ColumnMode::DateTime:
0107             break;
0108         }
0109     }
0110     m_columnModes.clear();
0111     m_dataContainer.clear();
0112 }
0113 
0114 size_t CANFilterPrivate::DataContainer::size() const {
0115     return m_dataContainer.size();
0116 }
0117 
0118 const QVector<AbstractColumn::ColumnMode> CANFilterPrivate::DataContainer::columnModes() const {
0119     return m_columnModes;
0120 }
0121 
0122 /*!
0123  * \brief dataContainer
0124  * Do not modify outside as long as DataContainer exists!
0125  * \return
0126  */
0127 std::vector<void*> CANFilterPrivate::DataContainer::dataContainer() const {
0128     return m_dataContainer;
0129 }
0130 
0131 AbstractColumn::ColumnMode CANFilterPrivate::DataContainer::columnMode(int index) const {
0132     return m_columnModes.at(index);
0133 }
0134 
0135 const void* CANFilterPrivate::DataContainer::datas(size_t index) const {
0136     if (index < size())
0137         return m_dataContainer.at(index);
0138     return nullptr;
0139 }
0140 
0141 bool CANFilterPrivate::DataContainer::resize(uint32_t s) const {
0142     for (uint32_t i = 0; i < m_dataContainer.size(); i++) {
0143         switch (m_columnModes.at(i)) {
0144         case AbstractColumn::ColumnMode::BigInt:
0145             static_cast<QVector<qint64>*>(m_dataContainer[i])->resize(s);
0146             break;
0147         case AbstractColumn::ColumnMode::Integer:
0148             static_cast<QVector<qint32>*>(m_dataContainer[i])->resize(s);
0149             break;
0150         case AbstractColumn::ColumnMode::Double:
0151             static_cast<QVector<double>*>(m_dataContainer[i])->resize(s);
0152             break;
0153         // TODO: implement missing cases
0154         case AbstractColumn::ColumnMode::Text:
0155         case AbstractColumn::ColumnMode::Month:
0156         case AbstractColumn::ColumnMode::Day:
0157         case AbstractColumn::ColumnMode::DateTime:
0158             break;
0159         }
0160     }
0161 
0162     if (m_dataContainer.size() == 0)
0163         return true;
0164 
0165     // Check that all vectors have same length
0166     int size = -1;
0167     switch (m_columnModes.at(0)) {
0168     case AbstractColumn::ColumnMode::BigInt:
0169         size = static_cast<QVector<qint64>*>(m_dataContainer[0])->size();
0170         break;
0171     case AbstractColumn::ColumnMode::Integer:
0172         size = static_cast<QVector<qint32>*>(m_dataContainer[0])->size();
0173         break;
0174     case AbstractColumn::ColumnMode::Double:
0175         size = static_cast<QVector<double>*>(m_dataContainer[0])->size();
0176         break;
0177     // TODO: implement missing cases
0178     case AbstractColumn::ColumnMode::Text:
0179     case AbstractColumn::ColumnMode::Month:
0180     case AbstractColumn::ColumnMode::Day:
0181     case AbstractColumn::ColumnMode::DateTime:
0182         break;
0183     }
0184 
0185     if (size == -1)
0186         return false;
0187 
0188     for (uint32_t i = 0; i < m_dataContainer.size(); i++) {
0189         int s = -1;
0190         switch (m_columnModes.at(i)) {
0191         case AbstractColumn::ColumnMode::BigInt:
0192             s = static_cast<QVector<qint64>*>(m_dataContainer[i])->size();
0193             break;
0194         case AbstractColumn::ColumnMode::Integer:
0195             s = static_cast<QVector<qint32>*>(m_dataContainer[i])->size();
0196             break;
0197         case AbstractColumn::ColumnMode::Double:
0198             s = static_cast<QVector<double>*>(m_dataContainer[i])->size();
0199             break;
0200         // TODO: implement missing cases
0201         case AbstractColumn::ColumnMode::Text:
0202         case AbstractColumn::ColumnMode::Month:
0203         case AbstractColumn::ColumnMode::Day:
0204         case AbstractColumn::ColumnMode::DateTime:
0205             break;
0206         }
0207         if (s != size)
0208             return false;
0209     }
0210     return true;
0211 }
0212 
0213 CANFilterPrivate::CANFilterPrivate(CANFilter* owner)
0214     : q(owner) {
0215 }
0216 
0217 /*!
0218     parses the content of the file \c fileName and fill the tree using rootItem.
0219     returns -1 on error
0220 */
0221 QVector<QStringList> CANFilterPrivate::preview(const QString& fileName, int lines) {
0222     if (!isValid(fileName))
0223         return QVector<QStringList>();
0224 
0225     const int readMessages = readDataFromFile(fileName, lines);
0226     if (readMessages == 0)
0227         return QVector<QStringList>();
0228 
0229     QVector<QStringList> strings;
0230 
0231     for (int i = 0; i < readMessages; i++) {
0232         QStringList l;
0233         for (size_t c = 0; c < m_DataContainer.size(); c++) {
0234             const auto* data_ptr = m_DataContainer.datas(c);
0235             if (!data_ptr)
0236                 continue;
0237 
0238             switch (m_DataContainer.columnMode(c)) {
0239             case AbstractColumn::ColumnMode::BigInt: {
0240                 const auto v = *static_cast<const QVector<qint64>*>(data_ptr);
0241                 l.append(QString::number(v.at(i)));
0242                 break;
0243             }
0244             case AbstractColumn::ColumnMode::Integer: {
0245                 const auto v = *static_cast<const QVector<qint32>*>(data_ptr);
0246                 l.append(QString::number(v.at(i)));
0247                 break;
0248             }
0249             case AbstractColumn::ColumnMode::Double: {
0250                 const auto v = *static_cast<const QVector<double>*>(data_ptr);
0251                 l.append(QString::number(v.at(i)));
0252                 break;
0253             }
0254             // TODO: other cases
0255             case AbstractColumn::ColumnMode::Text:
0256             case AbstractColumn::ColumnMode::Month:
0257             case AbstractColumn::ColumnMode::Day:
0258             case AbstractColumn::ColumnMode::DateTime:
0259                 break;
0260             }
0261         }
0262         strings.append(l);
0263     }
0264     return strings;
0265 }
0266 
0267 void CANFilterPrivate::clearParseState() {
0268     m_parseState = ParseState();
0269 }
0270 
0271 int CANFilterPrivate::readDataFromFile(const QString& fileName, int lines) {
0272     switch (timeHandlingMode) {
0273     case CANFilter::TimeHandling::ConcatNAN:
0274         // fall through
0275     case CANFilter::TimeHandling::ConcatPrevious:
0276         return readDataFromFileCommonTime(fileName, lines);
0277     case CANFilter::TimeHandling::Separate:
0278         return readDataFromFileSeparateTime(fileName, lines);
0279     }
0280     return 0;
0281 }
0282 
0283 /*!
0284     reads the content of the file \c fileName to the data source \c dataSource.
0285     Uses the settings defined in the data source.
0286 */
0287 int CANFilterPrivate::readDataFromFile(const QString& fileName, AbstractDataSource* dataSource, AbstractFileFilter::ImportMode mode, int lines) {
0288     if (!isValid(fileName))
0289         return 0;
0290 
0291     int rows = readDataFromFile(fileName, lines);
0292     if (rows == 0)
0293         return 0;
0294 
0295     auto dc = m_DataContainer.dataContainer();
0296     const int columnOffset = dataSource->prepareImport(dc, mode, rows, m_signals.signal_names.length(), m_signals.signal_names, columnModes(), false);
0297     dataSource->finalizeImport(columnOffset, 0, m_signals.signal_names.length() - 1);
0298 
0299     // Assign value labels to the column
0300     auto columns = dataSource->children<Column>();
0301     if ((size_t)columns.size() == m_signals.value_descriptions.size()) {
0302         int counter = 0;
0303         auto signal_descriptions = m_signals.value_descriptions.begin();
0304         while (signal_descriptions != m_signals.value_descriptions.end()) {
0305             if (signal_descriptions->size() > 0) {
0306                 auto it = signal_descriptions->begin();
0307                 while (it != signal_descriptions->end()) {
0308                     columns[counter]->addValueLabel((qint64)it->value, it->description);
0309                     it++;
0310                 }
0311             }
0312             counter++;
0313             signal_descriptions++;
0314         }
0315     }
0316     return rows;
0317 }
0318 
0319 /*!
0320     writes the content of \c dataSource to the file \c fileName.
0321 */
0322 void CANFilterPrivate::write(const QString& /*fileName*/, AbstractDataSource* /*dataSource*/) {
0323     // TODO: Not yet implemented
0324 }
0325 
0326 bool CANFilterPrivate::setDBCFile(const QString& filename) {
0327     return m_dbcParser.parseFile(filename) == DbcParser::ParseStatus::Success;
0328 }
0329 
0330 const QVector<AbstractColumn::ColumnMode> CANFilterPrivate::columnModes() {
0331     return m_DataContainer.columnModes();
0332 }
0333 
0334 // ##############################################################################
0335 // ##################  Serialization/Deserialization  ###########################
0336 // ##############################################################################
0337 
0338 /*!
0339   Saves as XML.
0340  */
0341 void CANFilter::save(QXmlStreamWriter* writer) const {
0342     writer->writeStartElement(QStringLiteral("hdfFilter"));
0343     writer->writeEndElement();
0344 }
0345 
0346 /*!
0347   Loads from XML.
0348 */
0349 bool CANFilter::load(XmlStreamReader*) {
0350     return true;
0351 }