奥特QT DDS 插件库
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
pirms 5 mēnešiem
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643
  1. #include "AQTSampleMachinePlug.hpp"
  2. #include <QDebug>
  3. #include <fastdds/dds/domain/DomainParticipantFactory.hpp>
  4. #include <QQmlComponent>
  5. #include <QQmlContext>
  6. #include <QUrl>
  7. #include <QCoreApplication>
  8. /**
  9. * @brief 构造函数
  10. * @param parent 父对象指针
  11. *
  12. * 初始化插件对象,包括:
  13. * - 初始化所有指针为空
  14. * - 创建DDS类型支持对象
  15. * - 初始化数据点信息
  16. */
  17. AQTSampleMachinePlug::AQTSampleMachinePlug(QObject *parent)
  18. : QObject(parent)
  19. , participant_(nullptr)
  20. , publisher_(nullptr)
  21. , subscriber_(nullptr)
  22. , commandTopic_(nullptr)
  23. , commandWriter_(nullptr)
  24. , statusTopic_(nullptr)
  25. , statusReader_(nullptr)
  26. , configTopic_(nullptr)
  27. , configWriter_(nullptr)
  28. , pointsTopic_(nullptr)
  29. , pointsWriter_(nullptr)
  30. , pointsReader_(nullptr)
  31. , m_configWindow(nullptr)
  32. , plcClient_(nullptr)
  33. , plcConnected_(false)
  34. {
  35. // 初始化类型支持
  36. commandType_ = TypeSupport(new SampleCommandPubSubType());
  37. statusType_ = TypeSupport(new SampleMachineInfoPubSubType());
  38. configType_ = TypeSupport(new SampleConfigPubSubType());
  39. pointsType_ = TypeSupport(new SamplePointsPubSubType());
  40. plcClient_ = new TS7Client();
  41. }
  42. /**
  43. * @brief 析构函数
  44. *
  45. * 清理插件对象,主要是清理所有DDS相关的资源。
  46. */
  47. AQTSampleMachinePlug::~AQTSampleMachinePlug()
  48. {
  49. // 清理DDS资源
  50. cleanupDDSEntities();
  51. if (m_configWindow) {
  52. m_configWindow->deleteLater();
  53. }
  54. if (plcConnected_) {
  55. disconnectPLC();
  56. }
  57. delete plcClient_;
  58. }
  59. /**
  60. * @brief 初始化插件
  61. * @param domainId DDS域ID
  62. * @param domainName DDS域名称
  63. * @return 初始化是否成功
  64. *
  65. * 初始化DDS通信环境,包括:
  66. * - 创建DDS参与者
  67. * - 初始化所有DDS实体
  68. */
  69. bool AQTSampleMachinePlug::init(uint32_t domainId, const QString& domainName)
  70. {
  71. // 创建DDS参与者
  72. DomainParticipantQos participantQos;
  73. participantQos.name(domainName.toStdString());
  74. participant_ = DomainParticipantFactory::get_instance()->create_participant(domainId, participantQos);
  75. if (!participant_) {
  76. qDebug() << "Failed to create participant";
  77. return false;
  78. }
  79. // 初始化其他DDS实体
  80. return initDDSEntities();
  81. }
  82. /**
  83. * @brief 获取数据点信息列表
  84. * @return 所有支持的数据点信息列表
  85. */
  86. QList<DataPointInfo> AQTSampleMachinePlug::getDataPoints()
  87. {
  88. // 在函数调用时创建并返回数据点列表
  89. return {
  90. // ===== SampleConfigData 相关数据点 (1-9) =====
  91. {1, "UnifiedDepth", "uint16"}, // 统一深度(全段面采样时使用)
  92. {2, "SampleOrder", "uint8"}, // 大车行进顺序(1:原点往外,2:往原点采)
  93. // ===== SampleCommand 相关数据点 (10-29) =====
  94. {10, "CommandMaskBits", "uint32"}, // 命令掩码,表示哪些字段被修改
  95. {11, "ControlType", "uint8"}, // 控制类型(1:就地,2:远程)
  96. {12, "StartSample", "int32"}, // 启动采样命令 (CommandState: STOP=0, START=1)
  97. {13, "StopSample", "int32"}, // 停止采样命令 (CommandState: STOP=0, START=1)
  98. {14, "Reset", "int32"}, // 系统复位命令 (CommandState: STOP=0, START=1)
  99. {15, "PositionCheck", "int32"}, // 位置确认命令 (CommandState: STOP=0, START=1)
  100. {16, "EmergencyUp", "int32"}, // 紧急提升命令 (CommandState: STOP=0, START=1)
  101. {17, "EmergencyStop", "int32"}, // 系统急停命令 (CommandState: STOP=0, START=1)
  102. {18, "ControlBelt1", "int32"}, // 启停皮带1 (CommandState: STOP=0, START=1)
  103. {19, "ControlBelt2", "int32"}, // 启停皮带2 (CommandState: STOP=0, START=1)
  104. {20, "ControlCrush1", "int32"}, // 启停破碎机1 (CommandState: STOP=0, START=1)
  105. {21, "ControlCrush2", "int32"}, // 启停破碎机2 (CommandState: STOP=0, START=1)
  106. {22, "ControlDivider", "int32"}, // 启停缩分器 (CommandState: STOP=0, START=1)
  107. {23, "ControlCoalDistributor", "int32"}, // 启停布煤器 (CommandState: STOP=0, START=1)
  108. {24, "ReductionRatio", "uint16"}, // 缩分比
  109. {25, "CommandVersion", "uint8"}, // 命令结构体版本号
  110. // ===== SampleInfo 相关数据点 (30-49) =====
  111. {30, "StatusMaskBits", "uint32"}, // 状态掩码,表示哪些字段被修改
  112. {31, "BigPoint", "uint16"}, // 大车位置
  113. {32, "SmallPoint", "uint16"}, // 小车位置
  114. {33, "DepthPoint", "uint16"}, // 深度位置
  115. {34, "HasToXY", "uint8"}, // 到达坐标点(0:未到达,1:已到达)
  116. {35, "HasSamplePoints", "uint8"}, // 已采样点数
  117. {36, "GameOver", "uint8"}, // 采样完成(0:未完成,1:完成)
  118. {37, "BackState", "uint16"}, // 采样状态返回
  119. {38, "SampleState", "int32"}, // 采样机状态 (DeviceState: OFF=0, ON=1, ERROR=2)
  120. {39, "Belt1State", "int32"}, // 皮带1状态 (DeviceState: OFF=0, ON=1, ERROR=2)
  121. {40, "Belt2State", "int32"}, // 皮带2状态 (DeviceState: OFF=0, ON=1, ERROR=2)
  122. {41, "Crush1State", "int32"}, // 破碎机1状态 (DeviceState: OFF=0, ON=1, ERROR=2)
  123. {42, "Crush2State", "int32"}, // 破碎机2状态 (DeviceState: OFF=0, ON=1, ERROR=2)
  124. {43, "DividerState", "int32"}, // 缩分器状态 (DeviceState: OFF=0, ON=1, ERROR=2)
  125. {44, "BigLimit", "uint8"}, // 大车限位(0:未限位,1:已限位)
  126. {45, "BigZeroLimit", "uint8"}, // 大车零点限位(0:未限位,1:已限位)
  127. {46, "SmallLimit", "uint8"}, // 小车限位(0:未限位,1:已限位)
  128. {47, "SmallZeroLimit", "uint8"}, // 小车零点限位(0:未限位,1:已限位)
  129. {48, "UpLimit", "uint8"}, // 升高限位(0:未限位,1:已限位)
  130. {49, "DownLimit", "uint8"}, // 降低限位(0:未限位,1:已限位)
  131. {50, "StatusVersion", "uint8"}, // 状态结构体版本号
  132. // ===== SamplePoints 相关数据点 (51-99) =====
  133. {51, "TotalPoints", "uint8"}, // 采样点数量
  134. // 点1
  135. {52, "Point1X", "uint16"}, // 采样点1 X坐标
  136. {53, "Point1Y", "uint16"}, // 采样点1 Y坐标
  137. {54, "Point1Z", "uint16"}, // 采样点1 Z坐标
  138. {55, "Point1Drop", "int32"}, // 采样点1 落料选择 (DropChoice: BYPASS=0, CRUSHER=1)
  139. // 点2
  140. {56, "Point2X", "uint16"}, // 采样点2 X坐标
  141. {57, "Point2Y", "uint16"}, // 采样点2 Y坐标
  142. {58, "Point2Z", "uint16"}, // 采样点2 Z坐标
  143. {59, "Point2Drop", "int32"}, // 采样点2 落料选择 (DropChoice: BYPASS=0, CRUSHER=1)
  144. // 点3
  145. {60, "Point3X", "uint16"}, // 采样点3 X坐标
  146. {61, "Point3Y", "uint16"}, // 采样点3 Y坐标
  147. {62, "Point3Z", "uint16"}, // 采样点3 Z坐标
  148. {63, "Point3Drop", "int32"}, // 采样点3 落料选择 (DropChoice: BYPASS=0, CRUSHER=1)
  149. // 点4
  150. {64, "Point4X", "uint16"}, // 采样点4 X坐标
  151. {65, "Point4Y", "uint16"}, // 采样点4 Y坐标
  152. {66, "Point4Z", "uint16"}, // 采样点4 Z坐标
  153. {67, "Point4Drop", "int32"}, // 采样点4 落料选择 (DropChoice: BYPASS=0, CRUSHER=1)
  154. // 点5
  155. {68, "Point5X", "uint16"}, // 采样点5 X坐标
  156. {69, "Point5Y", "uint16"}, // 采样点5 Y坐标
  157. {70, "Point5Z", "uint16"}, // 采样点5 Z坐标
  158. {71, "Point5Drop", "int32"}, // 采样点5 落料选择 (DropChoice: BYPASS=0, CRUSHER=1)
  159. // 点6
  160. {72, "Point6X", "uint16"}, // 采样点6 X坐标
  161. {73, "Point6Y", "uint16"}, // 采样点6 Y坐标
  162. {74, "Point6Z", "uint16"}, // 采样点6 Z坐标
  163. {75, "Point6Drop", "int32"} // 采样点6 落料选择 (DropChoice: BYPASS=0, CRUSHER=1)
  164. };
  165. }
  166. /**
  167. * @brief 发布数据到DDS网络
  168. * @param dataList 要发布的数据项列表
  169. * @return 发布是否成功
  170. *
  171. * 将数据项列表转换为相应的DDS消息并发布:
  172. * - 检查写入器是否可用
  173. * - 转换数据格式
  174. * - 发送数据
  175. */
  176. bool AQTSampleMachinePlug::publishData(const QList<DataItem>& dataList)
  177. {
  178. if (dataList.isEmpty()) {
  179. qDebug() << "Empty data list received";
  180. return false;
  181. }
  182. try {
  183. // 根据第一个数据项的ID判断主题类型
  184. int firstId = dataList.first().ID;
  185. if (firstId >= 1 && firstId <= 9) { // 配置数据
  186. if (!configWriter_) {
  187. qDebug() << "Config writer not initialized";
  188. return false;
  189. }
  190. auto config = dataItemsToConfig(dataList);
  191. return configWriter_->write(&config);
  192. }
  193. else if (firstId >= 10 && firstId <= 29) { // 命令数据
  194. if (!commandWriter_) {
  195. qDebug() << "Command writer not initialized";
  196. return false;
  197. }
  198. auto command = dataItemsToCommand(dataList);
  199. return commandWriter_->write(&command);
  200. }
  201. else if (firstId >= 51 && firstId <= 99) { // 采样点数据
  202. if (!pointsWriter_) {
  203. qDebug() << "Points writer not initialized";
  204. return false;
  205. }
  206. auto points = dataItemsToPoints(dataList);
  207. return pointsWriter_->write(&points);
  208. }
  209. else {
  210. qDebug() << "Invalid data ID range:" << firstId;
  211. return false;
  212. }
  213. }
  214. catch (const std::exception& e) {
  215. qDebug() << "Error publishing data:" << e.what();
  216. return false;
  217. }
  218. }
  219. /**
  220. * @brief 初始化DDS实体
  221. * @return 初始化是否成功
  222. *
  223. * 创建并初始化所有DDS通信所需的实体,包括:
  224. * - 注册数据类型
  225. * - 创建发布者和订阅者
  226. * - 创建主题
  227. * - 创建数据写入器和读取器
  228. * - 设置数据监听器
  229. */
  230. bool AQTSampleMachinePlug::initDDSEntities()
  231. {
  232. try {
  233. // 注册所有类型
  234. commandType_.register_type(participant_);
  235. statusType_.register_type(participant_);
  236. configType_.register_type(participant_);
  237. pointsType_.register_type(participant_);
  238. // 创建发布者和订阅者
  239. publisher_ = participant_->create_publisher(PUBLISHER_QOS_DEFAULT);
  240. subscriber_ = participant_->create_subscriber(SUBSCRIBER_QOS_DEFAULT);
  241. if (!publisher_ || !subscriber_) {
  242. qDebug() << "Failed to create publisher or subscriber";
  243. return false;
  244. }
  245. // 创建所有主题
  246. commandTopic_ = participant_->create_topic("SampleMachine/Command",
  247. commandType_.get_type_name(), TOPIC_QOS_DEFAULT);
  248. statusTopic_ = participant_->create_topic("SampleMachine/Status",
  249. statusType_.get_type_name(), TOPIC_QOS_DEFAULT);
  250. configTopic_ = participant_->create_topic("SampleMachine/Config",
  251. configType_.get_type_name(), TOPIC_QOS_DEFAULT);
  252. pointsTopic_ = participant_->create_topic("SampleMachine/Points",
  253. pointsType_.get_type_name(), TOPIC_QOS_DEFAULT);
  254. if (!commandTopic_ || !statusTopic_ || !configTopic_ || !pointsTopic_) {
  255. qDebug() << "Failed to create topics";
  256. return false;
  257. }
  258. // 创建写入器和读取器
  259. commandWriter_ = publisher_->create_datawriter(commandTopic_, DATAWRITER_QOS_DEFAULT);
  260. statusReader_ = subscriber_->create_datareader(statusTopic_, DATAREADER_QOS_DEFAULT);
  261. configWriter_ = publisher_->create_datawriter(configTopic_, DATAWRITER_QOS_DEFAULT);
  262. pointsWriter_ = publisher_->create_datawriter(pointsTopic_, DATAWRITER_QOS_DEFAULT);
  263. pointsReader_ = subscriber_->create_datareader(pointsTopic_, DATAREADER_QOS_DEFAULT);
  264. if (!commandWriter_ || !statusReader_ || !configWriter_ ||
  265. !pointsWriter_ || !pointsReader_) {
  266. qDebug() << "Failed to create writers or readers";
  267. return false;
  268. }
  269. // 设置状态和采样点的监听器
  270. statusReader_->set_listener(this, StatusMask::data_available());
  271. pointsReader_->set_listener(this, StatusMask::data_available());
  272. return true;
  273. }
  274. catch (const std::exception& e) {
  275. qDebug() << "Error initializing DDS entities:" << e.what();
  276. return false;
  277. }
  278. }
  279. /**
  280. * @brief 清理DDS实体
  281. *
  282. * 清理所有已创建的DDS资源,包括:
  283. * - 删除所有包含的实体(主题、读写器等)
  284. * - 删除参与者
  285. */
  286. void AQTSampleMachinePlug::cleanupDDSEntities()
  287. {
  288. // 清理所有DDS资源
  289. if (participant_) {
  290. participant_->delete_contained_entities();
  291. DomainParticipantFactory::get_instance()->delete_participant(participant_);
  292. }
  293. }
  294. /**
  295. * @brief 数据可用性回调函数
  296. * @param reader 触发回调的数据读取器
  297. *
  298. * 当订阅的主题收到新数据时被调用。根据读取器类型分别处理状态数据和采样点数据,
  299. * 将DDS数据转换为DataItem列表并通过信号和回调函数通知外部。
  300. */
  301. void AQTSampleMachinePlug::on_data_available(DataReader* reader)
  302. {
  303. // if (reader == statusReader_) {
  304. // SampleStatus status;
  305. // SampleInfo info; // 添加正确的SampleInfo声明
  306. // // 问题3: while循环中的info变量未声明
  307. // while (reader->take_next_sample(&status, &info) == ReturnCode_t::RETCODE_OK) {
  308. // if (info.valid_data) {
  309. // auto dataItems = convertStatusToDataItems(status);
  310. // emit onDataUpdated(dataItems);
  311. // }
  312. // }
  313. // }
  314. // else if (reader == pointsReader_) {
  315. // // 这部分代码正确
  316. // SamplePoints points;
  317. // SampleInfo info;
  318. // while (reader->take_next_sample(&points, &info) == ReturnCode_t::RETCODE_OK) {
  319. // if (info.valid_data) {
  320. // auto dataItems = convertPointsToDataItems(points);
  321. // emit onDataUpdated(dataItems);
  322. // }
  323. // }
  324. // }
  325. }
  326. /**
  327. * @brief 将采样机状态转换为数据项列表
  328. * @param infos 采样机状态数据
  329. * @return 转换后的数据项列表
  330. *
  331. * 按照预定义的数据点ID,将SampleInfo结构体中的状态信息转换为DataItem列表。
  332. * 包括设备状态、位置信息、限位信息等。
  333. */
  334. QList<DataItem> AQTSampleMachinePlug::infoToDataItems(const SampleMachineInfo& infos)
  335. {
  336. QList<DataItem> items;
  337. // 按照数据点定义的顺序转换状态数据
  338. items.append(DataItem(30, infos.maskBits()));
  339. items.append(DataItem(31, infos.bigPoint()));
  340. items.append(DataItem(32, infos.smallPoint()));
  341. items.append(DataItem(33, infos.depthPoint()));
  342. items.append(DataItem(34, infos.hasToXY()));
  343. items.append(DataItem(35, infos.hasSamplePoints()));
  344. items.append(DataItem(36, infos.gameOver()));
  345. items.append(DataItem(37, infos.backState()));
  346. items.append(DataItem(38, static_cast<int32_t>(infos.sampleState())));
  347. items.append(DataItem(39, static_cast<int32_t>(infos.belt1State())));
  348. items.append(DataItem(40, static_cast<int32_t>(infos.belt2State())));
  349. items.append(DataItem(41, static_cast<int32_t>(infos.crush1State())));
  350. items.append(DataItem(42, static_cast<int32_t>(infos.crush2State())));
  351. items.append(DataItem(43, static_cast<int32_t>(infos.dividerState())));
  352. items.append(DataItem(44, infos.bigLimit()));
  353. items.append(DataItem(45, infos.bigZeroLimit()));
  354. items.append(DataItem(46, infos.smallLimit()));
  355. items.append(DataItem(47, infos.smallZeroLimit()));
  356. items.append(DataItem(48, infos.upLimit()));
  357. items.append(DataItem(49, infos.downLimit()));
  358. items.append(DataItem(50, infos.version()));
  359. return items;
  360. }
  361. SampleCommand AQTSampleMachinePlug::dataItemsToCommand(const QList<DataItem>& items)
  362. {
  363. // 初始化命令对象
  364. SampleCommand command;
  365. command.maskBits(0); // 初始化掩码为0
  366. // 遍历输入的数据项列表
  367. for (const auto& item : items) {
  368. // 根据数据项的ID进行不同的处理
  369. switch (item.ID) {
  370. case 11: // 控制类型
  371. command.controlType(item.value.toUInt());
  372. command.maskBits(command.maskBits() | 0x00000002); // 设置对应的掩码位
  373. break;
  374. case 12: // 开始采样
  375. command.startSample(static_cast<SampleModule::CommandState>(item.value.toInt()));
  376. command.maskBits(command.maskBits() | 0x00000004);
  377. break;
  378. case 13: // 停止采样
  379. command.stopSample(static_cast<SampleModule::CommandState>(item.value.toInt()));
  380. command.maskBits(command.maskBits() | 0x00000008);
  381. break;
  382. case 14: // 复位
  383. command.reset(static_cast<SampleModule::CommandState>(item.value.toInt()));
  384. command.maskBits(command.maskBits() | 0x00000010);
  385. break;
  386. case 15: // 位置检查
  387. command.positionCheck(static_cast<SampleModule::CommandState>(item.value.toInt()));
  388. command.maskBits(command.maskBits() | 0x00000020);
  389. break;
  390. case 16: // 紧急上升
  391. command.emergencyUp(static_cast<SampleModule::CommandState>(item.value.toInt()));
  392. command.maskBits(command.maskBits() | 0x00000040);
  393. break;
  394. case 17: // 紧急停止
  395. command.emergencyStop(static_cast<SampleModule::CommandState>(item.value.toInt()));
  396. command.maskBits(command.maskBits() | 0x00000080);
  397. break;
  398. case 18: // 控制传送带1
  399. command.controlBelt1(static_cast<SampleModule::CommandState>(item.value.toInt()));
  400. command.maskBits(command.maskBits() | 0x00000100);
  401. break;
  402. case 19: // 控制传送带2
  403. command.controlBelt2(static_cast<SampleModule::CommandState>(item.value.toInt()));
  404. command.maskBits(command.maskBits() | 0x00000200);
  405. break;
  406. case 20: // 控制破碎机1
  407. command.controlCrush1(static_cast<SampleModule::CommandState>(item.value.toInt()));
  408. command.maskBits(command.maskBits() | 0x00000400);
  409. break;
  410. case 21: // 控制破碎机2
  411. command.controlCrush2(static_cast<SampleModule::CommandState>(item.value.toInt()));
  412. command.maskBits(command.maskBits() | 0x00000800);
  413. break;
  414. case 22: // 控制分流器
  415. command.controlDivider(static_cast<SampleModule::CommandState>(item.value.toInt()));
  416. command.maskBits(command.maskBits() | 0x00001000);
  417. break;
  418. case 23: // 控制分煤器
  419. command.controlCoalDistributor(static_cast<SampleModule::CommandState>(item.value.toInt()));
  420. command.maskBits(command.maskBits() | 0x00002000);
  421. break;
  422. case 24: // 减速比
  423. command.reductionRatio(item.value.toUInt());
  424. command.maskBits(command.maskBits() | 0x00004000);
  425. break;
  426. case 25: // 版本号
  427. command.version(item.value.toUInt());
  428. command.maskBits(command.maskBits() | 0x00008000);
  429. break;
  430. default: // 未知ID
  431. qWarning() << "Unknown command ID:" << item.ID;
  432. break;
  433. }
  434. }
  435. // 返回构建好的命令对象
  436. return command;
  437. }
  438. SampleConfig AQTSampleMachinePlug::dataItemsToConfig(const QList<DataItem>& items)
  439. {
  440. SampleConfig config;
  441. for (const auto& item : items) {
  442. switch (item.ID) {
  443. case 1: config.unifiedDepth(item.value.toUInt()); break;
  444. case 2: config.sampleOrder(item.value.toUInt()); break;
  445. // 添加其他配置项的转换
  446. default: break;
  447. }
  448. }
  449. return config;
  450. }
  451. SamplePoints AQTSampleMachinePlug::dataItemsToPoints(const QList<DataItem>& items)
  452. {
  453. SamplePoints points;
  454. for (const auto& item : items) {
  455. switch (item.ID) {
  456. // 从51开始添加新的数据项
  457. case 51: points.totalPoints(item.value.toUInt()); break;
  458. case 52: points.x1(item.value.toUInt()); break;
  459. case 53: points.y1(item.value.toUInt()); break;
  460. case 54: points.z1(item.value.toUInt()); break;
  461. case 55: points.o1(static_cast<SampleModule::DropChoice>(item.value.toInt())); break;
  462. case 56: points.x2(item.value.toUInt()); break;
  463. case 57: points.y2(item.value.toUInt()); break;
  464. case 58: points.z2(item.value.toUInt()); break;
  465. case 59: points.o2(static_cast<SampleModule::DropChoice>(item.value.toInt())); break;
  466. case 60: points.x3(item.value.toUInt()); break;
  467. case 61: points.y3(item.value.toUInt()); break;
  468. case 62: points.z3(item.value.toUInt()); break;
  469. case 63: points.o3(static_cast<SampleModule::DropChoice>(item.value.toInt())); break;
  470. case 64: points.x4(item.value.toUInt()); break;
  471. case 65: points.y4(item.value.toUInt()); break;
  472. case 66: points.z4(item.value.toUInt()); break;
  473. case 67: points.o4(static_cast<SampleModule::DropChoice>(item.value.toInt())); break;
  474. case 68: points.x5(item.value.toUInt()); break;
  475. case 69: points.y5(item.value.toUInt()); break;
  476. case 70: points.z5(item.value.toUInt()); break;
  477. case 71: points.o5(static_cast<SampleModule::DropChoice>(item.value.toInt())); break;
  478. case 72: points.x6(item.value.toUInt()); break;
  479. case 73: points.y6(item.value.toUInt()); break;
  480. case 74: points.z6(item.value.toUInt()); break;
  481. case 75: points.o6(static_cast<SampleModule::DropChoice>(item.value.toInt())); break;
  482. default:
  483. qWarning() << "Unknown command ID:" << item.ID;
  484. break;
  485. }
  486. }
  487. return points;
  488. }
  489. void AQTSampleMachinePlug::createConfigWindow()
  490. {
  491. if (!m_configWindow) {
  492. QQmlEngine *engine = new QQmlEngine(this);
  493. // 使用资源路径加载 QML
  494. QQmlComponent component(engine, QUrl("qrc:/AQTSampleMachinePlug/ConfigWindow.qml"));
  495. if (component.isError()) {
  496. qDebug() << "QML 加载错误:" << component.errors();
  497. return;
  498. }
  499. QObject *object = component.create();
  500. m_configWindow = qobject_cast<QQuickWindow*>(object);
  501. if (!m_configWindow) {
  502. qDebug() << "创建配置窗口失败";
  503. delete object;
  504. return;
  505. }
  506. // 设置窗口属性
  507. m_configWindow->setModality(Qt::ApplicationModal);
  508. }
  509. }
  510. bool AQTSampleMachinePlug::config()
  511. {
  512. createConfigWindow();
  513. if (m_configWindow) {
  514. m_configWindow->show();
  515. }
  516. return true;
  517. }
  518. bool AQTSampleMachinePlug::connectPLC(const QString& ipAddress, int rack, int slot)
  519. {
  520. if (plcConnected_) {
  521. return true;
  522. }
  523. //int result = plcClient_->ConnectTo(ipAddress.toStdString().c_str(), rack, slot);
  524. // if (result == 0) {
  525. // plcConnected_ = true;
  526. // qDebug() << "PLC connected successfully";
  527. // return true;
  528. // }
  529. //====qDebug() << "Failed to connect to PLC:" << TS7Client::ErrorText(result);
  530. return false;
  531. }
  532. bool AQTSampleMachinePlug::disconnectPLC()
  533. {
  534. if (!plcConnected_) {
  535. return true;
  536. }
  537. plcClient_->Disconnect();
  538. plcConnected_ = false;
  539. return true;
  540. }
  541. bool AQTSampleMachinePlug::readPLCData(int dbNumber, int start, int size, QByteArray& data)
  542. {
  543. // if (!plcConnected_) {
  544. // qDebug() << "PLC not connected";
  545. // return false;
  546. // }
  547. // data.resize(size);
  548. // int result = plcClient_->DBRead(dbNumber, start, size, data.data());
  549. // if (result == 0) {
  550. // return true;
  551. // }
  552. //====qDebug() << "Failed to read PLC data:" << TS7Client::ErrorText(result);
  553. return false;
  554. }
  555. bool AQTSampleMachinePlug::writePLCData(int dbNumber, int start, const QByteArray& data)
  556. {
  557. // if (!plcConnected_) {
  558. // qDebug() << "PLC not connected";
  559. // return false;
  560. // }
  561. // int result = plcClient_->DBWrite(dbNumber, start, data.size(), (void*)data.constData());
  562. // if (result == 0) {
  563. // return true;
  564. // }
  565. //====qDebug() << "Failed to write PLC data:" << TS7Client::ErrorText(result);
  566. return false;
  567. }