#pragma once #include #include #include #include #include "JFile.h" #include "DeviceCommonInfo.h" #include "DeviceChannelTypeStringParser.h" #include "DeviceSeriesParser.h" #include "JTerminal.h" namespace Incart::DevicesInfo { struct DeviceInfoJsonParserCommandsInfo { DeviceCommandInfo* commandInfo; QVariantList commands; }; class DeviceInfoJsonParser { public: static bool parseDevicesInfo(const QString& pathToDeviceCommonInfo, std::unordered_map& devicesInfo) { QDir directoryCommonInfo(pathToDeviceCommonInfo); QStringList fileNames = directoryCommonInfo.entryList(QStringList() << "*.json" << "*.JSON", QDir::Files); bool parseResult = true; for (auto it = fileNames.begin(); it != fileNames.end(); it++) { QString filePath = pathToDeviceCommonInfo + "/" + (*it); DeviceCommonInfo deviceInfo = parseDeviceCommonInfo(filePath, parseResult); if (!parseResult) { Common::JTerminal(JCL_RED) << "Error: can't read devices common info: " << filePath; return false; } devicesInfo.insert(std::pair(static_cast(deviceInfo.type), deviceInfo)); } return true; } static bool parseDevicesInfo(const QString& pathToDeviceCommonInfo, const QString& pathToDeviceCommandsInfo, const QString& pathToComplexCommandInfo, std::unordered_map& devicesInfo) { QDir directoryCommonInfo(pathToDeviceCommonInfo); QStringList fileNames = directoryCommonInfo.entryList(QStringList() << "*.json" << "*.JSON", QDir::Files); bool parseResult = true; for (auto it = fileNames.begin(); it != fileNames.end(); it++) { QString filePath = pathToDeviceCommonInfo + "/" + (*it); DeviceCommonInfo deviceInfo = parseDeviceCommonInfo(filePath, parseResult); if (!parseResult) { Common::JTerminal(JCL_RED) << "Error: can't read devices common info: " << filePath; return false; } devicesInfo.insert(std::pair(static_cast(deviceInfo.type), deviceInfo)); } QDir directorySimpleCommands(pathToDeviceCommandsInfo); fileNames = directorySimpleCommands.entryList(QStringList() << "*.json" << "*.JSON", QDir::Files); for (auto it = fileNames.begin(); it != fileNames.end(); it++) { QString filePath = pathToDeviceCommandsInfo + "/" + (*it); if (!parseDeviceSimpleCommands(filePath, devicesInfo)) { Common::JTerminal(JCL_RED) << "Error: can't read devices simple commands info: " << filePath; return false; } } QDir directoryComplexCommands(pathToComplexCommandInfo); fileNames = directoryComplexCommands.entryList(QStringList() << "*.json" << "*.JSON", QDir::Files); for (auto it = fileNames.begin(); it != fileNames.end(); it++) { QString filePath = pathToComplexCommandInfo + "/" + (*it); if (!parseComplexCommandInfo(filePath, devicesInfo)) { Common::JTerminal(JCL_RED) << "Error: can't read devices complex commands info: " << filePath; return false; } } return true; } static DeviceCommonInfo parseDeviceCommonInfo(const QString& filePath, bool& result) { QByteArray& data = Common::JFile::readFile(filePath); QJsonDocument jsonDocument = QJsonDocument::fromJson(data); if (jsonDocument.isObject()) { QJsonObject jsonObject = jsonDocument.object(); return parseDeviceCommonInfo(jsonObject.toVariantMap(), result); } Common::JTerminal(JCL_YELLOW) << __FUNCTION__ << "json object interpretation error"; result = false; return DeviceCommonInfo(); } static DeviceInfoJsonParserCommandsInfo parseCommandsInfo(const QString& filePath, std::unordered_map& devicesInfo, bool& result) { QByteArray& data = Common::JFile::readFile(filePath); QJsonDocument jsonDocument = QJsonDocument::fromJson(data); if (!jsonDocument.isObject()) { Common::JTerminal(JCL_YELLOW) << __FUNCTION__ << "json object interpretation error"; result = false; return DeviceInfoJsonParserCommandsInfo(); } QJsonObject jsonObject = jsonDocument.object(); int deviceType = jsonObject["Type"].toInt(); auto it = devicesInfo.find(deviceType); if (it == devicesInfo.end()) { Common::JTerminal(JCL_YELLOW) << __FUNCTION__ << "device with type \"" << deviceType << "\" is not found!"; result = false; return DeviceInfoJsonParserCommandsInfo(); } return DeviceInfoJsonParserCommandsInfo{ &(it->second.commandDesription), jsonObject["Commands"].toVariant().toList()}; } static bool parseDeviceSimpleCommands(const QString& filePath, std::unordered_map& devicesInfo) { bool parseResult = true; DeviceInfoJsonParserCommandsInfo commandsInfo = parseCommandsInfo(filePath, devicesInfo, parseResult); if (!parseResult) { return false; } for (int i = 0; i < commandsInfo.commands.size(); i++) { SimpleCommandInfo commandInfo = parseSimpleCommand(commandsInfo.commands[i].toMap(), parseResult); if (!parseResult) { return false; } commandsInfo.commandInfo->simpleCommands.push_back(commandInfo); } // add special command for execute custom byte commands commandsInfo.commandInfo->simpleCommands.push_back(SimpleCommandInfo("Custom", "Custom byte command", 0, SimpleCommandData(ESourceType::Dynamic, EDataType::Binary, EDataType::Binary, -1, {}))); return true; } static bool parseComplexCommandInfo(const QString& filePath, std::unordered_map& devicesInfo) { bool parseResult = true; DeviceInfoJsonParserCommandsInfo commandsInfo = parseCommandsInfo(filePath, devicesInfo, parseResult); if (!parseResult) { return false; } for (int i = 0; i < commandsInfo.commands.size(); i++) { QVariantMap commandMap = commandsInfo.commands[i].toMap(); ComplexCommandInfo commandInfo = parseComplexCommand(commandMap, parseResult); if (!parseResult) { return false; } commandsInfo.commandInfo->complexCommands.push_back(commandInfo); } return true; } static ComplexCommandInfo parseComplexCommand(QVariantMap json, bool& result) { result = true; return ComplexCommandInfo(json["Name"].toString().toStdString(), json["Description"].toString().toStdString(), json["Handler"].toString().toStdString()); } static DeviceCommonInfo parseDeviceCommonInfo(QVariantMap json, bool& result) { uint16_t type = static_cast(json["Type"].toUInt(&result)); if (!result) { return DeviceCommonInfo(); } std::vector channelInfoList; auto channels = json["Channels"].toList(); for (auto it = channels.begin(); it != channels.end(); ++it) { auto channelInfo = it->toMap(); DeviceChannelTypeInfo typeInfo{ DeviceChannelTypeStringParser::parseChannelType(channelInfo["Type"].toString().toStdString()), DeviceChannelTypeStringParser::parseChannelSourceType(channelInfo["Source"].toString().toStdString()) }; if ((typeInfo.type != EDeviceChannelType::Unknown) && (typeInfo.source != EDeviceChannelSourceType::Unknown)) { channelInfoList.push_back(DeviceChannelCommonInfo{channelInfo["Name"].toString().toStdString(), typeInfo, static_cast(channelInfo["MaxSignalCount"].toUInt()) }); } } std::string deviceSeriesText = json["Series"].toString().toStdString(); DevicesInfo::EDeviceSeries deviceSeries = DeviceSeriesParser::parse(deviceSeriesText); if (deviceSeries == DevicesInfo::EDeviceSeries::Unknown) { return DeviceCommonInfo(); } return DeviceCommonInfo(type, json["Name"].toString().toStdString(), deviceSeries, json["FileNameTag"].toString().toStdString(), json["VoltageForStartWriting"].toFloat(), json["VisFrameFormat"].toString().toStdString(), channelInfoList); } static std::vector parseByteList(QStringList byteList, bool& result) { std::vector byteArray; result = true; for (int i = 0; i < byteList.size(); i++) { uint8_t byteValue = parseByte(byteList[i], result); if (!result) { return {}; } byteArray.push_back((char)byteValue); } return byteArray; } private: static SimpleCommandInfo parseSimpleCommand(QVariantMap json, bool& result) { std::string name = json["Name"].toString().toStdString(); std::string description = json["Description"].toString().toStdString(); uint8_t code = parseByte(json["Code"].toString(), result); if (!result) { return SimpleCommandInfo("", "", 0, SimpleCommandData(ESourceType::Fixed, EDataType::Binary, EDataType::Binary, 0, {})); } return SimpleCommandInfo(name, description, code, parseSimpleCommandData(json["Data"].toMap(), result)); } static SimpleCommandData parseSimpleCommandData(QVariantMap json, bool& result) { ESourceType sourceType = parseSimpleCommandSourceType(json["SourceType"].toString(), result); if (!result) { return SimpleCommandData(); } EDataType dataType = EDataType::Binary; if (sourceType == ESourceType::Dynamic) { dataType = parseCommandDataType(json["DataType"].toString(), result); if (!result) { return SimpleCommandData(); } } EDataType answerType = parseCommandDataType(json["AnswerType"].toString(), result); if (!result) { return SimpleCommandData(); } int32_t width = json["Width"].toInt(&result); if (!result) { return SimpleCommandData(); } QVariantList commandDataOptions = json["Options"].toList(); std::vector> options; for (int i = 0; i < commandDataOptions.size(); i++) { QStringList commandParamOptionJson = commandDataOptions[i].toStringList(); std::vector paramOption = parseByteList(commandParamOptionJson, result); if (!result) { return SimpleCommandData(); } options.push_back(paramOption); } return SimpleCommandData(sourceType, dataType, answerType, width, options); } static ESourceType parseSimpleCommandSourceType(QString sourceTypeText, bool& result) { result = true; if (sourceTypeText.compare("DYNAMIC", Qt::CaseInsensitive) == 0) { return ESourceType::Dynamic; } else if (sourceTypeText.compare("FIXED", Qt::CaseInsensitive) == 0) { return ESourceType::Fixed; } result = false; return ESourceType::Fixed; } static EDataType parseCommandDataType(QString dataTypeText, bool& result) { result = true; if (dataTypeText.compare("INT", Qt::CaseInsensitive) == 0) { return EDataType::Int; } else if (dataTypeText.compare("DOUBLE", Qt::CaseInsensitive) == 0) { return EDataType::Double; } else if (dataTypeText.compare("DATE", Qt::CaseInsensitive) == 0) { return EDataType::Date; } else if (dataTypeText.compare("TEXT", Qt::CaseInsensitive) == 0) { return EDataType::Text; } else if (dataTypeText.compare("BINARY", Qt::CaseInsensitive) == 0) { return EDataType::Binary; } result = false; return EDataType::Binary; } static uint8_t parseByte(QString text, bool& result) { if ((text.size() < 3) || (text.size() > 4) || (text[0] != '0') || (text[1] != 'x')) { result = false; return 0; } return text.mid(2).toUInt(&result, 16); } }; } // namespace Incart::DevicesInfo