//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // DBC Decriptor // // // // Made by Pierre Hudelaine // // // // Contact: pierre.hudelaine@hds.utc.fr // // // // Translate a DBC file to Pacpus code // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// #include "mainwindow.h" #include "ui_mainwindow.h" #include #include #include #include #include #include #include //----------------------------------------------------------------------------// // Constructor // //----------------------------------------------------------------------------// MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); connect(ui->actionOpen, SIGNAL(triggered()), this, SLOT(openDBCFile())); connect(ui->actionClose_all_files, SIGNAL(triggered()), this, SLOT(clearDBC())); connect(ui->actionQuitter, SIGNAL(triggered()), this, SLOT(close())); connect(ui->pushButton_open_file, SIGNAL(clicked()), this, SLOT(openDBCFile())); ui->label_file_error->setText(""); ui->label_value_frame_id->setText(""); ui->label_value_frame_name->setText(""); ui->label_value_number_of_signals->setText(""); ui->label_value_total_frames->setText("0"); ui->label_value_total_signals->setText("0"); ui->lineEdit_output_path->setText(QApplication::applicationDirPath()); } //----------------------------------------------------------------------------// // Destructor // //----------------------------------------------------------------------------// MainWindow::~MainWindow() { delete ui; } //----------------------------------------------------------------------------// // Open the DBC file // //----------------------------------------------------------------------------// void MainWindow::openDBCFile() { clearDBC(); dbcFiles_.fileName = QFileDialog::getOpenFileName(this, "Open dbc file", "", "dbc files (*.dbc);;Text files (*.txt);;All files (*.*)"); QFile file(dbcFiles_.fileName); if (!file.open(QIODevice::ReadOnly)) { ui->label_file_error->setText("Can not open the file"); } else { QTextStream stream(&file); dbcFiles_.content = stream.readAll().split('\n'); QStringList signalName; bool frameFound = false; StructFrame tmpFrame; tmpFrame.frameID = 0; tmpFrame.frameName = ""; tmpFrame.numberOfSignals = 0; for (int i = 0; i < dbcFiles_.content.size(); i++) { if (frameFound) { // " SG_" is the beginning if a line containing a signal information if (dbcFiles_.content[i].startsWith(" SG_")) { tmpFrame.numberOfSignals++; getSignalParameters(dbcFiles_.content[i], &tmpFrame); } else frameFound = false; } // "BO_" is the beginning of a line containing a frame information and all signals are following if (dbcFiles_.content[i].startsWith("BO_")) { int numberOfSpace = 0, j = 0; QString tmp; frameFound = true; // Get the ID of the frame while(numberOfSpace != 2) { if (dbcFiles_.content[i][j] == ' ') numberOfSpace++; if (numberOfSpace == 1) tmp.append(dbcFiles_.content[i][j]); j++; } tmpFrame.frameID = tmp.toInt(); tmp = ""; // Get the name of the frame while(dbcFiles_.content[i][j] != ':') { tmp.append(dbcFiles_.content[i][j]); j++; } tmpFrame.frameName = tmp; } else if (dbcFiles_.content[i].startsWith("CM_")) { // Get the comment at the end of the DBC file findComment(i); } else if (dbcFiles_.content[i].startsWith("VAL_")) { // Get the value descritpion at the end of the DBC file findValueDescription(i); } // If a hole frame has been treated it's registered in the vector if (tmpFrame.numberOfSignals != 0 && !frameFound) { dbcFiles_.canFrames.append(tmpFrame); ui->label_value_total_frames->setText(QString().setNum(ui->label_value_total_frames->text().toInt() + 1)); ui->label_value_total_signals->setText(QString().setNum(ui->label_value_total_signals->text().toInt() + tmpFrame.numberOfSignals)); tmpFrame.frameID = 0; tmpFrame.frameName = ""; tmpFrame.numberOfSignals = 0; tmpFrame.signalsVector.clear(); } } // Frames are added in the list for (int i = 0; i < dbcFiles_.canFrames.size(); i++) { if (dbcFiles_.canFrames[i].frameID >= 255) signalName.append("0x" + QString().setNum(dbcFiles_.canFrames[i].frameID, 16).toUpper() + " " + dbcFiles_.canFrames[i].frameName); else signalName.append("0x0" + QString().setNum(dbcFiles_.canFrames[i].frameID, 16).toUpper() + " " + dbcFiles_.canFrames[i].frameName); } ui->listWidget_signals->addItems(signalName); file.close(); //printAllFrames(); } } //----------------------------------------------------------------------------// // Print the parameters for a specific frame // //----------------------------------------------------------------------------// void MainWindow::printFrame(int i, int j) { qDebug() << dbcFiles_.canFrames[i].signalsVector[j].signalName << " " << dbcFiles_.canFrames[i].signalsVector[j].startBit << " " << dbcFiles_.canFrames[i].signalsVector[j].length << " " << ((dbcFiles_.canFrames[i].signalsVector[j].order) ? "Motorola" : "Intel") << " " << ((dbcFiles_.canFrames[i].signalsVector[j].valueType) ? "Signed" : "Unsigned") << " " << dbcFiles_.canFrames[i].signalsVector[j].gain << " " << dbcFiles_.canFrames[i].signalsVector[j].offset << " " << dbcFiles_.canFrames[i].signalsVector[j].min << " " << dbcFiles_.canFrames[i].signalsVector[j].max << " " << ((dbcFiles_.canFrames[i].signalsVector[j].unit != "") ? dbcFiles_.canFrames[i].signalsVector[j].unit : "") << dbcFiles_.canFrames[i].signalsVector[j].comment; } //----------------------------------------------------------------------------// // Print the parameters of all frames // //----------------------------------------------------------------------------// void MainWindow::printAllFrames() { for (int i = 0; i < dbcFiles_.canFrames.size(); i++) { for (int j = 0; j < dbcFiles_.canFrames[i].signalsVector.size(); j++) { printFrame(i, j); } } } //----------------------------------------------------------------------------// // Get the the signals informations in the DBC file // //----------------------------------------------------------------------------// void MainWindow::getSignalParameters(QString actualLine, StructFrame * actualCanFrame) { StructSignal tmpSignal; tmpSignal.order = true; tmpSignal.gain = 0.0; tmpSignal.length = 0; tmpSignal.offset = 0.0; tmpSignal.signalName = ""; tmpSignal.valueType = true; tmpSignal.startBit = 0; tmpSignal.unit = ""; tmpSignal.comment = ""; tmpSignal.description = ""; // Removing the untreated and unsued caracters actualLine.remove('('); actualLine.remove(')'); actualLine.remove('['); actualLine.remove(']'); QStringList cutLine = actualLine.split(' '); // Get the name tmpSignal.signalName = cutLine.at(2); cutLine = actualLine.split(" : "); // Get the second part with the signal parameters for example : 63|8@0+ // 63 = startBit; 8 = length; 0 = Motorola order; + = Unsigned value QStringList cutLineValue = cutLine.at(1).split(' '); tmpSignal.startBit = cutLineValue.at(0).split('|').at(0).toInt(); tmpSignal.length = cutLineValue.at(0).split('|').at(1).split('@').at(0).toInt(); if (cutLineValue.at(0).split('|').at(1).split('@').at(1).at(0) == '1') tmpSignal.order = false; if (cutLineValue.at(0).split('|').at(1).split('@').at(1).at(1) == '+') tmpSignal.valueType = false; // Get the offset and the gain for example : (0.05,2) // 0.05 = gain; 2 = offset; tmpSignal.gain = cutLineValue.at(1).split(',').at(0).toDouble(); tmpSignal.offset = cutLineValue.at(1).split(',').at(1).toDouble(); // Get the max and min for exemple : [-6.4|6.35] // -6.4 = max; 6.35 = max; tmpSignal.min = cutLineValue.at(2).split('|').at(0).toDouble(); tmpSignal.max = cutLineValue.at(2).split('|').at(1).toDouble(); // Get the unit for example : "m/s" // m/s = unit tmpSignal.unit = cutLineValue.at(3); tmpSignal.unit.remove('"'); actualCanFrame->signalsVector.append(tmpSignal); } //----------------------------------------------------------------------------// // Find a comment and associate it to the signal // //----------------------------------------------------------------------------// void MainWindow::findComment(int k) { for (int i = 0; i < dbcFiles_.canFrames.size(); i++) { for (int j = 0; j < dbcFiles_.canFrames[i].signalsVector.size(); j++) { if (dbcFiles_.content[k].contains(dbcFiles_.canFrames[i].signalsVector[j].signalName)) { dbcFiles_.canFrames[i].signalsVector[j].comment = dbcFiles_.content[k].split('"').at(1); while (dbcFiles_.content[k].at(dbcFiles_.content[k].size() - 2) != ';') { k++; dbcFiles_.canFrames[i].signalsVector[j].comment += dbcFiles_.content[k]; } return; } } } } //----------------------------------------------------------------------------// // Find the value description and associate it to the signal // //----------------------------------------------------------------------------// void MainWindow::findValueDescription(int k) { for (int i = 0; i < dbcFiles_.canFrames.size(); i++) { for (int j = 0; j < dbcFiles_.canFrames[i].signalsVector.size(); j++) { if (dbcFiles_.content[k].contains(dbcFiles_.canFrames[i].signalsVector[j].signalName)) { dbcFiles_.canFrames[i].signalsVector[j].description = dbcFiles_.content[k].right(dbcFiles_.content[k].length() - (dbcFiles_.content[k].indexOf(dbcFiles_.canFrames[i].signalsVector[j].signalName) + dbcFiles_.canFrames[i].signalsVector[j].signalName.length())); return; } } } } //----------------------------------------------------------------------------// // Called from the HMI to clear the last information // //----------------------------------------------------------------------------// void MainWindow::clearDBC() { dbcFiles_.canFrames.clear(); dbcFiles_.content.clear(); dbcFiles_.fileName = ""; ui->listWidget_signals->clear(); ui->label_file_error->setText(""); ui->label_value_frame_id->setText(""); ui->label_value_frame_name->setText(""); ui->label_value_number_of_signals->setText(""); ui->label_value_total_frames->setText("0"); ui->label_value_total_signals->setText("0"); } //----------------------------------------------------------------------------// // Actualize the HMI with the last information // //----------------------------------------------------------------------------// void MainWindow::on_listWidget_signals_currentRowChanged(int currentRow) { if (currentRow >= 0) { if (dbcFiles_.canFrames[currentRow].frameID >= 255) ui->label_value_frame_id->setText("0x" + QString().setNum(dbcFiles_.canFrames[currentRow].frameID, 16).toUpper()); else ui->label_value_frame_id->setText("0x0" + QString().setNum(dbcFiles_.canFrames[currentRow].frameID, 16).toUpper()); ui->label_value_frame_name->setText(dbcFiles_.canFrames[currentRow].frameName); ui->label_value_number_of_signals->setText(QString().setNum(dbcFiles_.canFrames[currentRow].numberOfSignals)); } } //----------------------------------------------------------------------------// // Generate the c++ files from the dbc information previouly registered // //----------------------------------------------------------------------------// void MainWindow::on_pushButton_generate_clicked() { QDate date(QDate::currentDate()); // Creating the beginnig of the structure file QString outputStructFile = templateStructFile; outputStructFile.insert(outputStructFile.indexOf("created:") + 8, " " + QString().setNum(date.year()) + "/" + QString().setNum(date.month()) + "/" + QString().setNum(date.day())); outputStructFile.insert(outputStructFile.indexOf("#ifndef __STRUCTURECAN") + 22, ui->lineEdit_export_name->text().toUpper()); outputStructFile.insert(outputStructFile.indexOf("#define __STRUCTURECAN") + 22, ui->lineEdit_export_name->text().toUpper()); for (int i = 0; i < dbcFiles_.canFrames.size(); i++) { QString outputCPPFile = templateCPPFile; QString outputHFile = templateHFile; // Creating the beginning of each c++ files outputCPPFile.insert(outputCPPFile.indexOf("created:") + 8, " " + QString().setNum(date.year()) + "/" + QString().setNum(date.month()) + "/" + QString().setNum(date.day())); outputCPPFile.insert(outputCPPFile.indexOf("#include \"CanFrame.h\"") + 18, dbcFiles_.canFrames[i].frameName); outputCPPFile.insert(outputCPPFile.indexOf("void CanFrame") + 13, dbcFiles_.canFrames[i].frameName); // Creating the beginning of each h files outputHFile.insert(outputHFile.indexOf("created:") + 8, " " + QString().setNum(date.year()) + "/" + QString().setNum(date.month()) + "/" + QString().setNum(date.day())); outputHFile.insert(outputHFile.indexOf("#ifndef __CanFrame") + 18, dbcFiles_.canFrames[i].frameName); outputHFile.insert(outputHFile.indexOf("#define __CanFrame") + 18, dbcFiles_.canFrames[i].frameName); outputHFile.insert(outputHFile.indexOf("#include \"structureCan") + 22, ui->lineEdit_export_name->text()); outputHFile.insert(outputHFile.indexOf("class CAN") + 9, ui->lineEdit_export_name->text().toUpper()); outputHFile.insert(outputHFile.indexOf("_API CanFrame") + 13, dbcFiles_.canFrames[i].frameName); outputHFile.insert(outputHFile.indexOf("CanFrame()") + 8, dbcFiles_.canFrames[i].frameName); outputHFile.insert(outputHFile.indexOf("~CanFrame()") + 9, dbcFiles_.canFrames[i].frameName); outputHFile.insert(outputHFile.indexOf("Struct data_;") + 6, dbcFiles_.canFrames[i].frameName); outputHFile.insert(outputHFile.indexOf("return sizeof(Struct)") + 20, dbcFiles_.canFrames[i].frameName); // Adding the structure of frames outputStructFile.insert(outputStructFile.indexOf("#include \"Pacpus/kernel/road_time.h") + 36, "\n\ntypedef struct\n{\n} Struct" + dbcFiles_.canFrames[i].frameName + ";"); for (int j = 0; j < dbcFiles_.canFrames[i].signalsVector.size(); j++) { QString tmpCpp = "\n"; // If variables are bool if (dbcFiles_.canFrames[i].signalsVector[j].length == 1) { tmpCpp.append(" data_." + dbcFiles_.canFrames[i].signalsVector[j].signalName + " = mDecodeToBool(d_.frame.data, " + QString().setNum(dbcFiles_.canFrames[i].signalsVector[j].startBit) + ");"); if (dbcFiles_.canFrames[i].signalsVector[j].description != "") outputStructFile.insert(outputStructFile.indexOf("} Struct" + dbcFiles_.canFrames[i].frameName), " bool " + dbcFiles_.canFrames[i].signalsVector[j].signalName + "; /// " + dbcFiles_.canFrames[i].signalsVector[j].description + "\n"); else outputStructFile.insert(outputStructFile.indexOf("} Struct" + dbcFiles_.canFrames[i].frameName), " bool " + dbcFiles_.canFrames[i].signalsVector[j].signalName + ";\n"); } else { // If variables are Motorola or Intel if (dbcFiles_.canFrames[i].signalsVector[j].order) tmpCpp.append(" if (mDecodeTo"); else tmpCpp.append(" if (iDecodeTo"); // If variables are signed... if (dbcFiles_.canFrames[i].signalsVector[j].valueType) { if (dbcFiles_.canFrames[i].signalsVector[j].length <= 8) tmpCpp.append("I8(&ctmp, "); else if (dbcFiles_.canFrames[i].signalsVector[j].length <= 16) tmpCpp.append("I16(&stmp, "); else if (dbcFiles_.canFrames[i].signalsVector[j].length <= 32) tmpCpp.append("I32(<mp, "); else if (dbcFiles_.canFrames[i].signalsVector[j].length <= 64) tmpCpp.append("I64(&lltmp, "); } else // ...Or not signed { if (dbcFiles_.canFrames[i].signalsVector[j].length <= 8) tmpCpp.append("UI8(&uctmp, "); else if (dbcFiles_.canFrames[i].signalsVector[j].length <= 16) tmpCpp.append("UI16(&ustmp, "); else if (dbcFiles_.canFrames[i].signalsVector[j].length <= 32) tmpCpp.append("UI32(&ultmp, "); else if (dbcFiles_.canFrames[i].signalsVector[j].length <= 64) tmpCpp.append("UI64(&ulltmp, "); } // Code c++ added in the QString tmpCpp.append("d_.frame.data, " + QString().setNum(dbcFiles_.canFrames[i].signalsVector[j].startBit) + ", " + QString().setNum(dbcFiles_.canFrames[i].signalsVector[j].length) + "))\n"); tmpCpp.append(" data_." + dbcFiles_.canFrames[i].signalsVector[j].signalName + " = "); // Find the c++ type between double or integer if (floor(dbcFiles_.canFrames[i].signalsVector[j].gain) == dbcFiles_.canFrames[i].signalsVector[j].gain) { // If it's need a brace in c++ if (dbcFiles_.canFrames[i].signalsVector[j].gain != 1 && dbcFiles_.canFrames[i].signalsVector[j].offset != 0) tmpCpp.append("("); // Define the type of the pointer which will store temporally the data if (!dbcFiles_.canFrames[i].signalsVector[j].valueType) tmpCpp.append("u"); if (dbcFiles_.canFrames[i].signalsVector[j].length <= 8) tmpCpp.append("ctmp"); else if (dbcFiles_.canFrames[i].signalsVector[j].length <= 16) tmpCpp.append("stmp"); else if (dbcFiles_.canFrames[i].signalsVector[j].length <= 32) tmpCpp.append("ltmp"); else if (dbcFiles_.canFrames[i].signalsVector[j].length <= 64) tmpCpp.append("lltmp"); // Setting the gain and the offset if (dbcFiles_.canFrames[i].signalsVector[j].gain != 1 && dbcFiles_.canFrames[i].signalsVector[j].offset != 0) tmpCpp.append(" * " + QString().setNum(dbcFiles_.canFrames[i].signalsVector[j].gain) + ") + " + QString().setNum(dbcFiles_.canFrames[i].signalsVector[j].offset) + ";"); else if (dbcFiles_.canFrames[i].signalsVector[j].gain != 1) tmpCpp.append(" * " + QString().setNum(dbcFiles_.canFrames[i].signalsVector[j].gain) + ";"); else if (dbcFiles_.canFrames[i].signalsVector[j].offset != 0) tmpCpp.append(" + " + QString().setNum(dbcFiles_.canFrames[i].signalsVector[j].offset) + ";"); else tmpCpp.append(";"); // Adding the value in the structure QString tmp; // Find the c++ variable type /!\ May differ from the signal !!!! if (dbcFiles_.canFrames[i].signalsVector[j].offset < 0 && !dbcFiles_.canFrames[i].signalsVector[j].valueType) tmp.append(" int"); else tmp.append(" uint"); if (dbcFiles_.canFrames[i].signalsVector[j].length <= 8) tmp.append("8_t " + dbcFiles_.canFrames[i].signalsVector[j].signalName + ";"); else if (dbcFiles_.canFrames[i].signalsVector[j].length <= 16) tmp.append("16_t " + dbcFiles_.canFrames[i].signalsVector[j].signalName + ";"); else if (dbcFiles_.canFrames[i].signalsVector[j].length <= 32) tmp.append("32_t " + dbcFiles_.canFrames[i].signalsVector[j].signalName + ";"); else if (dbcFiles_.canFrames[i].signalsVector[j].length <= 64) tmp.append("64_t " + dbcFiles_.canFrames[i].signalsVector[j].signalName + ";"); if (dbcFiles_.canFrames[i].signalsVector[j].description != "") tmp.append(" /// " + dbcFiles_.canFrames[i].signalsVector[j].description); outputStructFile.insert(outputStructFile.indexOf("} Struct" + dbcFiles_.canFrames[i].frameName), tmp + "\n"); } else { tmpCpp.append("static_cast("); if (dbcFiles_.canFrames[i].signalsVector[j].gain != 1 && dbcFiles_.canFrames[i].signalsVector[j].offset != 0) tmpCpp.append("("); if (!dbcFiles_.canFrames[i].signalsVector[j].valueType) tmpCpp.append("u"); if (dbcFiles_.canFrames[i].signalsVector[j].length <= 8) tmpCpp.append("ctmp"); else if (dbcFiles_.canFrames[i].signalsVector[j].length <= 16) tmpCpp.append("stmp"); else if (dbcFiles_.canFrames[i].signalsVector[j].length <= 32) tmpCpp.append("ltmp"); else if (dbcFiles_.canFrames[i].signalsVector[j].length <= 64) tmpCpp.append("lltmp"); if (dbcFiles_.canFrames[i].signalsVector[j].gain != 1 && dbcFiles_.canFrames[i].signalsVector[j].offset != 0) tmpCpp.append(" * " + QString().setNum(dbcFiles_.canFrames[i].signalsVector[j].gain) + ") + " + QString().setNum(dbcFiles_.canFrames[i].signalsVector[j].offset) + ");"); else if (dbcFiles_.canFrames[i].signalsVector[j].gain != 1) tmpCpp.append(" * " + QString().setNum(dbcFiles_.canFrames[i].signalsVector[j].gain) + ");"); else if (dbcFiles_.canFrames[i].signalsVector[j].offset != 0) tmpCpp.append(" + " + QString().setNum(dbcFiles_.canFrames[i].signalsVector[j].offset) + ");"); else tmpCpp.append(");"); QString tmp = ""; if (dbcFiles_.canFrames[i].signalsVector[j].description != "") tmp.append(" /// " + dbcFiles_.canFrames[i].signalsVector[j].description); outputStructFile.insert(outputStructFile.indexOf("} Struct" + dbcFiles_.canFrames[i].frameName), " double " + dbcFiles_.canFrames[i].signalsVector[j].signalName + "; " + tmp + "\n"); } } if (dbcFiles_.canFrames[i].signalsVector[j].comment != "") tmpCpp.append(" /*" + dbcFiles_.canFrames[i].signalsVector[j].comment + "*/"); outputCPPFile.insert(outputCPPFile.indexOf("unsigned char uctmp = 0") + 24, tmpCpp); } outputStructFile.insert(outputStructFile.indexOf("Struct" + dbcFiles_.canFrames[i].frameName + ";") + dbcFiles_.canFrames[i].frameName.size() + 7, "\n\ntypedef struct\n{\n road_time_t time;\n road_timerange_t timerange;\n Struct" + dbcFiles_.canFrames[i].frameName + " d;\n} TimeStampedStruct" + dbcFiles_.canFrames[i].frameName + ";"); QFile canFrameCpp(ui->lineEdit_output_path->text() + "/CanFrame" + dbcFiles_.canFrames[i].frameName + ".cpp"); canFrameCpp.open(QIODevice::WriteOnly); QTextStream cppOut(&canFrameCpp); cppOut << outputCPPFile; canFrameCpp.close(); QFile canFrameH(ui->lineEdit_output_path->text() + "/CanFrame" + dbcFiles_.canFrames[i].frameName + ".h"); canFrameH.open(QIODevice::WriteOnly); QTextStream hOut(&canFrameH); hOut << outputHFile; canFrameH.close(); } QFile struc(ui->lineEdit_output_path->text() + "/strucureCan" + ui->lineEdit_export_name->text() + ".h"); struc.open(QIODevice::WriteOnly); QTextStream strucOut(&struc); strucOut << outputStructFile; struc.close(); } //----------------------------------------------------------------------------// // Unlock the pushButton "Generate" when a string is registerer // //----------------------------------------------------------------------------// void MainWindow::on_lineEdit_export_name_textChanged(const QString &arg1) { if (arg1 == "") ui->pushButton_generate->setEnabled(false); else ui->pushButton_generate->setEnabled(true); } //----------------------------------------------------------------------------// // Select the output directory // //----------------------------------------------------------------------------// void MainWindow::on_pushButton_output_path_clicked() { QString tmp = ""; if ((tmp = QFileDialog::getExistingDirectory(0, 0, ui->lineEdit_output_path->text())) != "") ui->lineEdit_output_path->setText(tmp); }