Guest User

Untitled

a guest
Aug 29th, 2016
147
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #pragma once
  2. #include <Loader.h>
  3.  
  4. Loader::Loader() {
  5.  
  6.   startTimer(5*60*1000);
  7.  
  8.   // запустить машину
  9.   programm = compiler.Make(MAIN_PATH);
  10.  
  11.   qDebug() << compiler.mErrorList;
  12.   Q_ASSERT_X(programm != nullptr, "Loader::Loader()", "Compile failed");
  13.  
  14.   // получить таблицу символов скриптов
  15.   QVariantMap map = programm->Symbols();
  16.  
  17.   // счетчик добавить отдельно, он не начинается с vg
  18.   symbolTable.insert("vpuTickCount", map.value("vpuTickCount").toInt());
  19.  
  20.   // запомнить переменные (начинаются с vg)
  21.   foreach(QString symbol, map.keys()) {
  22.     if (symbol.startsWith("vg")) {
  23.       symbolTable.insert(symbol, map.value(symbol).toInt());
  24.     }
  25.  
  26.     if ((!symbol.isNull()) && (symbol.at(0).isUpper())) {
  27.  
  28.       //если останется true - включить символ в список функций
  29.       bool includeFunc = true;
  30.  
  31.       //проверить условия отсева функций
  32.       if (baseFuncList.contains(symbol))
  33.         includeFunc = false;
  34.  
  35.       else if (symbol.startsWith("Module"))
  36.         includeFunc = false;
  37.       else if (symbol.startsWith("Can"))
  38.         includeFunc = false;
  39.       else if (symbol.startsWith("Log"))
  40.         includeFunc = false;
  41.       else if (symbol.startsWith("Setup"))
  42.         includeFunc = false;
  43.       else if (symbol.endsWith("Enter"))
  44.         includeFunc = false;
  45.       else if (symbol.endsWith("Hnd"))
  46.         includeFunc = false;
  47.  
  48.       //добавить функцию в список
  49.       if (includeFunc == true) {
  50.         functionTable.insert(symbol, map.value(symbol).toInt());
  51.         functions[symbol] = map.value(symbol);
  52.       }
  53.     }
  54.   }
  55.  
  56.   // запустить программу
  57.   vpu->SetProgram(programm, false, false);
  58.   vpu->start();
  59.  
  60.   // по обновлению переменных в контроллере обновлять их проекцию в qml
  61.   connect(vpu.data(), SIGNAL(updateVariables()), SLOT(getVariables()));
  62. }
  63.  
  64. void Loader::init() {
  65.  
  66. //  QTimer *timer = new QTimer(this);
  67. //  timer->start(500);
  68. //  connect(timer, &QTimer::timeout, [this] () {
  69. //      QMetaProperty aaa = QQmlProperty(this, "aaa", engine->rootContext()).property();
  70.  
  71. //      int val = aaa.read(this).toInt();
  72.  
  73.  
  74. ////      blockSignals(true);
  75. //      aaa.write(this, val+1);
  76. ////      blockSignals(false);
  77.  
  78. ////      aaa.notifySignal().invoke(this, Qt::DirectConnection);
  79.  
  80. //      qDebug() << "timeout" << aaa.isValid() << val;
  81. //  });
  82.  
  83.   engine = qobject_cast<QQmlApplicationEngine *>(this->QObject::parent());
  84.   Q_ASSERT_X(!engine.isNull(), "Loader::init()", "no engine found!");
  85.  
  86.   QFile file(CONFIG_PATH);
  87.   QTextStream stream(&file);
  88.   QStringList lines;
  89.   int pos = 0;
  90.  
  91.   Q_ASSERT_X(file.exists(), "Loader::init()", "scripts/config.h not exists!");
  92.  
  93.   file.open(QIODevice::ReadOnly);
  94.   while (!stream.atEnd()) {
  95.     QString line = stream.readLine();
  96.     lines += line;
  97.  
  98.     if (line.contains("#define")) {
  99.  
  100.       //узнать, закомментирована ли строка
  101.       QRegExp rexp("//\s?#define");
  102.       bool off = line.count(rexp);
  103.  
  104.       //если да - раскомментировать
  105.       if (off) {
  106.         line.replace(rexp, "#define");
  107.       }
  108.  
  109.       //вырезать комментарий в конце
  110.       int commentPos = line.lastIndexOf("//");
  111.       if (commentPos != -1) {
  112.         line = line.left(commentPos);
  113.       }
  114.  
  115.       //оставить только пару ключ-значение
  116.       line.remove("#define");
  117.       line = line.simplified();
  118.  
  119.       QStringList splitted = line.split(' ');
  120.       QString key = splitted.first();
  121.       if (splitted.size() > 1) {
  122.         QString value = splitted.last();
  123.  
  124.         ConstType type = LINK;
  125.         if (value.contains(QRegExp("^0?x[0-9a-fA-F]+$"))) {
  126.           type = HEX;
  127.         } else if (value.contains(QRegExp("^[0-9]+$"))) {
  128.           type = DEC;
  129.         }
  130.  
  131.         ConfigValue mConfigValue;
  132.         mConfigValue.active = off;
  133.         mConfigValue.line = pos;
  134.         mConfigValue.key = key;
  135.         mConfigValue.value = value;
  136.         mConfigValues += mConfigValue;
  137.  
  138.         if (!off) {
  139.           QVariant variant;
  140.           switch (type) {
  141.           case HEX:
  142.             variant = value.toInt(0, 16);
  143.             break;
  144.           case DEC:
  145.             variant = value.toInt();
  146.           case LINK:
  147.             variant = value;
  148.           }
  149.           config[key] = variant;
  150.         }
  151.       } else {
  152.         config[key] = !off;
  153.       }
  154.     }
  155.  
  156.     pos++;
  157.   }
  158.  
  159.   emit configChanged();
  160.   file.close();
  161.  
  162.   //ищем в конфиге #define LOADER
  163.   QVariant loader = config["LOADER"];
  164.   //если нашли
  165.   if (loader.isValid()) {
  166.     //если он не закомментирован
  167.     if (loader.toBool() == true) {
  168.       const_cast<QString &>(initPath) = SCRIPT_PATH "initLoader.c";
  169.     } else {
  170.       const_cast<QString &>(initPath) = SCRIPT_PATH "initUnloader.c";
  171.     }
  172.   }
  173. }
  174.  
  175. void Loader::initVariables() {
  176.  
  177.   foreach(const QString& variable, symbolTable.keys()) {
  178.     const PropertyPtr prop = PropertyPtr(new QQmlProperty(this, variable));
  179.  
  180.     if (prop->isValid()) {
  181.       variables.insert(variable, prop);
  182.       prop->connectNotifySignal(this, SLOT(setVariable()));
  183.  
  184.     }
  185.   }
  186. }
  187.  
  188. void Loader::initConstants() {
  189.  
  190.   //регулярное выращение для поиска вещественных констант
  191.   const QRegExp realVal(R"(^\s*[a-zA-Z]\w+\s*=\s*-?\d+\.\d{1,3}\s*\*\s*\d+("
  192.                           "\.\d{1,3});\s*(\/{2}.*)?$)");
  193.  
  194.   //регулярное выращение для поиска целочисленных констант
  195.   const QRegExp intVal(R"(^\s*[a-zA-Z]\w+\s*=\s*-?\d+;\s*(\/{2}.*)?$)");
  196.  
  197.   //регулярное выражение для поиска целочисленного элемента массива
  198.   const QRegExp intArr(
  199.       R"(^\s*segments[A-Z]\w*\[\d+\]\s*=\s*-?\d+;\s*(\/{2}.*)?$)");
  200.  
  201.   //регулярное выражение для поиска вещественного элемента массива
  202.   const QRegExp realArr(R"(^\s*segments[A-Z]\w*\[\d+\]\s*=\s*-?\d+\.\d{1,3}\s*"
  203.                           "\*\s*\d+(\.\d{1,3});\s*(\/{2}.*)?$)");
  204.  
  205.   QFile file(initPath);
  206.   Q_ASSERT_X(file.exists(), "Loader::initConstants()",
  207.              "Файл с константами не найден");
  208.  
  209.   QTextStream stream(&file);
  210.   QStringList split;
  211.  
  212.   file.open(QIODevice::ReadOnly);
  213.  
  214.   while (!stream.atEnd()) {
  215.     QString line = stream.readLine();
  216.     initFile += line;
  217.  
  218.     bool isIntVal = line.contains(intVal);
  219.     bool isRealVal = line.contains(realVal);
  220.     bool isIntArr = line.contains(intArr);
  221.     bool isRealArr = line.contains(realArr);
  222.  
  223.     bool isConstant = isIntVal || isRealVal || isIntArr || isRealArr;
  224.  
  225.     if (isConstant) {
  226.       QString variable; //имя переменной
  227.       QString constant; //константа
  228.       QString factor;   //множитель
  229.       QString comment;  //комментарий
  230.       int spaceCount;   //количество пробелов в начале
  231.  
  232.       //определить количество пробелов в начале строки
  233.       QRegExp spaces(R"(^\s*)");
  234.       spaces.indexIn(line);
  235.       spaceCount = spaces.matchedLength();
  236.  
  237.       //определить содержание комментария, если есть
  238.       int commentPos = line.indexOf("//");
  239.       if (commentPos != -1) {
  240.         int commentWidth = line.length() - commentPos - 2;
  241.         comment = line.right(commentWidth);
  242.       }
  243.  
  244.       //подготовить выражение для анализа
  245.       line = line.left(line.indexOf(';')).simplified();
  246.       split = line.split('=');
  247.  
  248.       //получить имя переменной
  249.       variable = split.first().simplified();
  250.  
  251.       //если строка содержит целочисленную или вещественную константу
  252.       {
  253.         // если целочисленное
  254.         if (isIntVal || isIntArr) {
  255.           constant = split.last().simplified();
  256.         }
  257.  
  258.         // если вещественное
  259.         else if (isRealVal || isRealArr) {
  260.           split = split.last().split('*');
  261.           constant = split.first().simplified();
  262.           factor = split.last().simplified();
  263.         }
  264.  
  265.         //
  266.         if (isIntVal || isRealVal || isIntArr) {
  267.           QVariantMap constantElement;
  268.           constantElement["position"] = initFile.length() - 1;
  269.           constantElement["constant"] = constant;
  270.           constantElement["factor"] = factor;
  271.           constantElement["comment"] = comment;
  272.           constantElement["spaces"] = spaceCount;
  273.           constants.insert(variable, constantElement);
  274.  
  275.           if (isIntArr) {
  276.             split = variable.split('[');
  277.  
  278.             variable = split.first().remove("segments");
  279.             int index = split.last().remove(']').toInt();
  280.  
  281.             QVariantList list = segments[variable].toList();
  282.             list.append(constant);
  283.             segments[variable] = list;
  284.           }
  285.         }
  286.       }
  287.     }
  288.   }
  289.  
  290.   file.close();
  291. }
  292.  
  293. void Loader::initFunctions() {
  294.  
  295.   //главный объект qml, который умеет работать с переменными контроллера
  296.   QJSValue qmlRoot = engine->newQObject(this);
  297.  
  298.   //функция, генерирующая функцию для управления контроллером
  299.   QJSValue funcGenerator = engine->evaluate(
  300.       "function(n,r){return function(){n.vgComplete=0;n.vgCall=r;for(var a in "
  301.       "arguments){var "
  302.       "t=arguments[a];n['vgParam'+ ++a]=t}}}");
  303.  
  304.   //функция, создающая в qml свойство-функцию
  305.   QJSValue propertyCreator =
  306.       engine->evaluate("function(obj, name, func) { "
  307.                        "Object.defineProperty(obj, name, {value : func}); }");
  308.  
  309.   foreach(QString funcName, functionTable.keys()) {
  310.     //получить адрес функции
  311.     QJSValue adress = functionTable.value(funcName);
  312.     //подготовить список аргументов для функции-генератора
  313.     QJSValueList args = { qmlRoot, adress };
  314.     //сгенерировать функцию, для вызова функции контроллера
  315.     QJSValue func = funcGenerator.call(args);
  316.     funcName[0] = funcName.at(0).toLower();
  317.     args = { qmlRoot, funcName, func };
  318.     propertyCreator.call(args);
  319.   }
  320. }
  321.  
  322. void Loader::getVariable(const QString &name)
  323. {
  324.     if (!variables.contains(name)) return;
  325.  
  326.     const PropertyPtr variable = variables[name];
  327.  
  328.     if (!variable.isNull()) {
  329.         const int addr = symbolTable.value(name);
  330.         const int prev = variable->read().toInt();
  331.         const int val = vpu->valueByIndex(addr);
  332.  
  333.         if (prev != val) {
  334.             variable->write(val);
  335.         }
  336.     }
  337. }
  338.  
  339. void Loader::getVariables() {
  340.  
  341.   // чтобы отделить изменение переменных по сигналу
  342.   // обновления от изменения вручную - на время
  343.   // выставляем флаг updating
  344.   updating = true;
  345.  
  346.   //хак, сперва обновить vgDevice и vgResult
  347.   getVariable("vgDevice");
  348.   getVariable("vgResult");
  349.  
  350.   // перебираем используемые переменные
  351.   foreach(const QString & variable, variables.keys()) {
  352.       getVariable(variable);
  353.   }
  354.  
  355.   updating = false;
  356. }
  357.  
  358. void Loader::setVariable() {
  359.   // если переменная изменяется из qml
  360.   if (!updating) {
  361.  
  362.     // перебираем все переменные в qml, связаные с контроллером
  363.     foreach(const QString & variable, variables.keys()) {
  364.  
  365.       const PropertyPtr prop = variables[variable];
  366.  
  367.       // получить значение переменной из qml
  368.       int value = prop->read().toInt();
  369.       // получить значение переменной из контроллера
  370.       int prev = vpu->valueByName(variable);
  371.  
  372.       // если отличаются - записать в контроллер
  373.       if (value != prev) {
  374.         vpu->setValueByName(variable, value);
  375.       }
  376.     }
  377.   }
  378. }
  379.  
  380. void Loader::saveInit() {
  381.  
  382.   SaveSegmentsInfo(initFile, segments, constants);
  383.  
  384.   foreach(const QString & variable, symbolTable.keys()) {
  385.     if (constants.contains(variable)) {
  386.       QVariantMap constant = constants.value(variable).toMap();
  387.       QString strFactor = constant["factor"].toString();
  388.       QString strConstant = constant["constant"].toString();
  389.  
  390.       double factor = (strFactor.isEmpty()) ? 1 : strFactor.toDouble();
  391.  
  392.       const int oldValue = strConstant.toDouble() * factor;
  393.       const int newValue = vpu->valueByName(variable);
  394.  
  395.       if (newValue != oldValue) {
  396.  
  397.         QString value;
  398.         if (factor == 1)
  399.           value.setNum(newValue);
  400.         else {
  401.           const double x = newValue / factor;
  402.  
  403.           if (x == int(x)) {
  404.             value.setNum(x, 'f', 1);
  405.           } else {
  406.             value.setNum(x);
  407.           }
  408.  
  409.           // обновить константу в карте
  410.           constant["constant"] = value;
  411.  
  412.           value.append(" * ");
  413.           value.append(strFactor);
  414.         }
  415.  
  416.         const int spaces = constant["spaces"].toInt();
  417.         const QString comment = constant["comment"].toString();
  418.  
  419.         QString newLine = QString(spaces, ' ');
  420.         newLine.append(variable);
  421.         newLine.append(" = ");
  422.         newLine.append(value);
  423.         newLine.append(';');
  424.  
  425.         if (!comment.isEmpty()) {
  426.           newLine.append(" //");
  427.           newLine.append(comment);
  428.         }
  429.  
  430.         const int pos = constant["position"].toInt();
  431.         initFile[pos] = newLine;
  432.       }
  433.     }
  434.   }
  435.  
  436.   //все записать в файл
  437.   QFile file(initPath);
  438.   QTextStream stream(&file);
  439.  
  440.   file.open(QIODevice::WriteOnly);
  441.   stream << initFile.join('\n');
  442.   file.close();
  443. }
  444.  
  445. bool Loader::saveJson(QVariantMap settings, const QString &filePath) {
  446.  
  447.   QString fileName = filePath.split('/').last();
  448.   QJsonDocument config;
  449.   config.setObject(QJsonObject::fromVariantMap(settings));
  450.   QByteArray rawConfig = config.toJson();
  451.  
  452.   // предупредить, если конфиг пустой
  453.   if (config.isEmpty()) {
  454.     QString debug_msg =
  455.         QObject::tr("Config for export in file '%1' is empty").arg(fileName);
  456.     qWarning() << debug_msg.toStdString().c_str();
  457.     return false;
  458.   }
  459.  
  460.   // предупредить, если файла не существует
  461.   bool fileExists = QFile::exists(filePath);
  462.   if (!fileExists) {
  463.     QString debug_msg = QObject::tr("File '%1' is not exist").arg(fileName);
  464.     qWarning() << debug_msg.toStdString().c_str();
  465.   }
  466.  
  467.   // предупредить, если файл не удалось открыть
  468.   QFile configFile(filePath);
  469.   bool fileOpened = configFile.open(QIODevice::WriteOnly);
  470.   if (!fileOpened) {
  471.     QString debug_msg = QObject::tr("Cannot open file '%1'").arg(fileName);
  472.     qWarning() << debug_msg.toStdString().c_str();
  473.     return false;
  474.   }
  475.  
  476.   // регулярка, соответствует числу с одним знаком после запятой, в кавычках
  477.   // нужно убрать кавычки (чтобы при чтении считывалось как число, а не
  478.   // строка)
  479.   QRegExp rx(R"("\d +\.\d ")");
  480.  
  481.   QStringList strings = QString(rawConfig).split('\n');
  482.   QStringList numbers;
  483.  
  484.   // поиск удовлетворяющих выражению строк
  485.   foreach(QString str, strings) {
  486.     int pos = rx.indexIn(str);
  487.     if (pos > -1)
  488.       numbers.append(rx.cap(0));
  489.   }
  490.   // удалить дубликаты
  491.   numbers.removeDuplicates();
  492.  
  493.   // замены строк на обескавыченые
  494.   foreach(QString number, numbers) {
  495.     QString repl = number.mid(1, number.length() - 2);
  496.     rawConfig.replace(number, qPrintable(repl));
  497.   }
  498.  
  499.   int bytesWritten = configFile.write(rawConfig);
  500.   configFile.close();
  501.   if (bytesWritten != rawConfig.size()) {
  502.     QString debug_msg =
  503.         QObject::tr("Error: in file '%1' written %2 bytes of %3")
  504.             .arg(fileName)
  505.             .arg(bytesWritten)
  506.             .arg(rawConfig.size());
  507.     qWarning() << debug_msg.toStdString().c_str();
  508.     return false;
  509.   }
  510.  
  511.   return true;
  512. }
  513.  
  514. QVariantMap Loader::parseJson(const QString &filePath) {
  515.   QString fileName = filePath.split('/').last();
  516.   QVariantMap result;
  517.   QString errMsg;
  518.  
  519.   bool fileExists = QFile::exists(filePath);
  520.   if (!fileExists) {
  521.     errMsg = QObject::tr("File '%1' not exist").arg(fileName);
  522.     qDebug() << qPrintable(errMsg);
  523.     return result;
  524.   }
  525.  
  526.   QFile configFile(filePath);
  527.   bool fileOpen = configFile.open(QIODevice::ReadOnly | QIODevice::Text);
  528.   if (!fileOpen) {
  529.     errMsg = QObject::tr("File '%1' cannot be open").arg(fileName);
  530.     qDebug() << qPrintable(errMsg);
  531.     return result;
  532.   }
  533.  
  534.   QByteArray rawConfig = configFile.readAll();
  535.   configFile.close();
  536.  
  537.   QJsonParseError parseError;
  538.   QJsonDocument config = QJsonDocument::fromJson(rawConfig, &parseError);
  539.  
  540.   bool parseOk = parseError.error == QJsonParseError::NoError;
  541.   if (!parseOk) {
  542.     QString errMsg =
  543.         QObject::tr("File '%1': parse error '%2' in char position %3")
  544.             .arg(fileName)
  545.             .arg(parseError.errorString())
  546.             .arg(parseError.offset);
  547.     qDebug() << qPrintable(errMsg);
  548.  
  549.     return result;
  550.   }
  551.  
  552.   if (config.isEmpty()) {
  553.     errMsg = QObject::tr("File '%1': empty config").arg(fileName);
  554.     qDebug() << qPrintable(errMsg);
  555.     return result;
  556.   }
  557.  
  558.   if (!config.isObject()) {
  559.     errMsg = QObject::tr("File '%1': not object").arg(fileName);
  560.     qDebug() << qPrintable(errMsg);
  561.     return result;
  562.   }
  563.  
  564.   result = config.object().toVariantMap();
  565.   return result;
  566. }
  567.  
  568. void Loader::mouseMoveEvent(QMouseEvent *event) {
  569.   int x = event->x();
  570.   int y = event->y();
  571.  
  572.   if (mouseX != x) {
  573.     mouseX = x;
  574.     emit mouseXChanged();
  575.   }
  576.  
  577.   if (mouseY != y) {
  578.     mouseY = y;
  579.     emit mouseYChanged();
  580.   }
  581.  
  582.   QQuickWindow::mousePressEvent(event);
  583. }
  584.  
  585. void SaveSegmentsInfo(QStringList &lines, const QVariantMap &segments,
  586.                       const QVariantMap &constants) {
  587.   const int segmentCount = segments.value("Id").toList().length();
  588.  
  589.   const QStringList segmentParams = { "AddWidth", "LoadSpeed", "MoveSpeed",
  590.                                       "TransferSpeed" };
  591.  
  592.   foreach(const QString & param, segmentParams) {
  593.     for (int i = 0; i < segmentCount; i++) {
  594.       const QString variable = "segments" + param + QString("[%1]").arg(i);
  595.       const int value = segments.value(param).toList().at(i).toString().toInt();
  596.  
  597.       const QVariantMap constant = constants.value(variable).toMap();
  598.       const QString comment = constant["comment"].toString();
  599.       const int spaces = constant["spaces"].toInt();
  600.  
  601.       const int pos = constant["position"].toInt();
  602.  
  603.       QString newLine = QString(spaces, ' ');
  604.       newLine += variable;
  605.       newLine += " = ";
  606.       newLine += QString::number(value);
  607.       newLine += ';';
  608.       if (!comment.isEmpty()) {
  609.         newLine += " //";
  610.         newLine += comment;
  611.       }
  612.  
  613.       lines[pos] = newLine;
  614.     }
  615.   }
  616. }
Add Comment
Please, Sign In to add comment