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 }