serialworker.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539
  1. #include "serialworker.h"
  2. #include "QDebug"
  3. #include <QCoreApplication>
  4. #include <QDateTime>
  5. #include <QElapsedTimer>
  6. #include <QtMath>
  7. #include <QSerialPortInfo>
  8. #include <QTimer>
  9. #include <QRegularExpression>
  10. #include <QSettings>
  11. #include <QThread>
  12. //#define FRAME_LEN 66
  13. #define CHANNEL_COUNT 24
  14. #define MAX_STEP 9
  15. SerialWorker::SerialWorker(QObject *parent) : QObject(parent)
  16. {
  17. }
  18. SerialWorker::~SerialWorker()
  19. {
  20. if(m_portBMC && m_portBMC->isOpen())
  21. {
  22. m_portBMC->close();
  23. }
  24. if(m_portCPLD && m_portCPLD->isOpen())
  25. {
  26. m_portCPLD->close();
  27. }
  28. }
  29. void SerialWorker::initFrame()
  30. {
  31. memset(txFrame, 0, sizeof(txFrame));
  32. txFrame[0] = 0xA5;
  33. txFrame[1] = 0x5A;
  34. txFrame[2] = 0x02;
  35. txFrame[3] = 0x04;
  36. txFrame[4] = 0x07;
  37. txFrame[5] = 0x00;
  38. txFrame[6] = 0x00;
  39. txFrame[7] = 0x00;
  40. txFrame[8] = 0x00;
  41. txFrame[9] = 0x00;
  42. txFrame[10] = 0x00;
  43. txFrame[11] = 0x00;
  44. txFrame[12] = 0x00;
  45. txFrame[13] = 0x22;
  46. txFrame[14] = 0x2A;
  47. txFrame[15] = 0x00;
  48. txFrame[44] = 0x00;
  49. txFrame[45] = 0x00;
  50. txFrame[46] = 0x00;
  51. txFrame[47] = 0x00;
  52. }
  53. void SerialWorker::start()
  54. {
  55. m_pid.resize(4);
  56. initFrame();
  57. QString path = QCoreApplication::applicationDirPath() + "/motor.ini";
  58. QSettings settings(path, QSettings::IniFormat);
  59. // 读取保存的位置,没有则默认0
  60. m_position = settings.value("Motor/Position", 0).toInt();
  61. qDebug()<<m_position;
  62. static int a = 0;
  63. preTimer = new QTimer(this);
  64. connect(preTimer,&QTimer::timeout,this,[=](){
  65. a++;
  66. qDebug()<<"a = "<<a;
  67. QByteArray data = QByteArray::fromHex(
  68. "A55A020405000000000000000004280000009E0C"
  69. );
  70. m_portCPLD->write(data);
  71. m_portCPLD->flush();
  72. sendDownCmd();
  73. for(int fan = 0; fan < 24; fan++)
  74. {
  75. txFrame[16 + fan] = (uint8_t)100;
  76. }
  77. for(int fan = 0; fan < 4; fan++)
  78. {
  79. txFrame[40 + fan] = (uint8_t)30;
  80. }
  81. sendSnapshot();
  82. });
  83. pidTimer = new QTimer(this);
  84. connect(pidTimer,&QTimer::timeout,this,[=](){
  85. m_portBMC->write("ipmitool raw 0x36 0x6c 0xdf 0xdd 0x00 0x03\r");
  86. m_portBMC->flush();
  87. });
  88. }
  89. void SerialWorker::openBMCSerial(const QString &portname)
  90. {
  91. m_portBMC = new QSerialPort(this);
  92. m_portBMC->setPortName(portname);
  93. m_portBMC->setBaudRate(115200);
  94. m_portBMC->setDataBits(QSerialPort::Data8);
  95. m_portBMC->setParity(QSerialPort::NoParity);
  96. m_portBMC->setStopBits(QSerialPort::OneStop);
  97. m_portBMC->setFlowControl(QSerialPort::NoFlowControl);
  98. if(!m_portBMC->open(QIODevice::ReadWrite))
  99. {
  100. qDebug()<<"bmc串口打开失败";
  101. return;
  102. }
  103. else
  104. {
  105. m_portBMC->write("stty -echo\r");
  106. m_portBMC->flush();
  107. qDebug()<<"bmc串口打开成功";
  108. }
  109. }
  110. void SerialWorker::openCPLDSerial(const QString &portname)
  111. {
  112. m_portCPLD = new QSerialPort(this);
  113. m_portCPLD->setPortName(portname);
  114. m_portCPLD->setBaudRate(921600);
  115. m_portCPLD->setDataBits(QSerialPort::Data8);
  116. m_portCPLD->setParity(QSerialPort::NoParity);
  117. m_portCPLD->setStopBits(QSerialPort::OneStop);
  118. m_portCPLD->setFlowControl(QSerialPort::NoFlowControl);
  119. if(!m_portCPLD->open(QIODevice::ReadWrite))
  120. {
  121. qDebug()<<"cpld串口打开失败";
  122. return;
  123. }
  124. else
  125. {
  126. connect(m_portCPLD,&QSerialPort::readyRead,this,&SerialWorker::onReadyReadCPLD);
  127. qDebug()<<"cpld串口打开成功";
  128. }
  129. }
  130. uint16_t SerialWorker::crc16(const uint8_t *data, uint16_t len)
  131. {
  132. uint16_t crc = 0xFFFF;
  133. for(uint16_t i = 0; i < len; i++)
  134. {
  135. crc ^= ((uint16_t)data[i] << 8);
  136. for(uint8_t j = 0; j < 8; j++)
  137. {
  138. if(crc & 0x8000)
  139. {
  140. crc = (crc << 1) ^ 0x1021;
  141. }
  142. else
  143. {
  144. crc <<= 1;
  145. }
  146. }
  147. }
  148. return crc;
  149. }
  150. void SerialWorker::onStartTest(int index)
  151. {
  152. m_tempIndex = index;
  153. preTimer->start(1000);
  154. }
  155. void SerialWorker::onReadyReadBMC()
  156. {
  157. m_buffer += m_portBMC->readAll();
  158. QString text = QString::fromUtf8(m_buffer);
  159. QRegularExpression re("root@[^#]*#");
  160. QRegularExpressionMatch match = re.match(text);
  161. if (!match.hasMatch())
  162. return;
  163. // 前面的HEX字符串
  164. QString hex = text.left(match.capturedStart());
  165. // 删除已经处理的数据
  166. m_buffer.remove(0, match.capturedEnd());
  167. // 去掉所有空白
  168. hex.remove(QRegularExpression("\\s+"));
  169. // 转二进制
  170. QByteArray data = QByteArray::fromHex(hex.toLatin1());
  171. if(data.size() != 48)
  172. {
  173. return;
  174. }
  175. parsePIDData(data);
  176. }
  177. void SerialWorker::onReadyReadCPLD()
  178. {
  179. m_cpldBuffer.append(m_portCPLD->readAll());
  180. while(m_cpldBuffer.size() >= 6)
  181. {
  182. // 找帧头
  183. int index = m_cpldBuffer.indexOf(
  184. QByteArray::fromHex("A55A"));
  185. if(index < 0)
  186. {
  187. m_cpldBuffer.clear();
  188. return;
  189. }
  190. // 删除前面的垃圾
  191. if(index > 0)
  192. m_cpldBuffer.remove(0,index);
  193. // 不够判断类型
  194. if(m_cpldBuffer.size() < 6)
  195. return;
  196. // 判断帧类型
  197. uint8_t cmd1 = (uint8_t)m_cpldBuffer[4];
  198. uint8_t cmd2 = (uint8_t)m_cpldBuffer[5];
  199. // 只处理温度帧
  200. if(cmd1 != 0x10 || cmd2 != 0x1B)
  201. {
  202. // 不是温度帧,丢掉这一帧
  203. m_cpldBuffer.remove(0,2);
  204. continue;
  205. }
  206. // 等待完整35字节
  207. if(m_cpldBuffer.size() < 35)
  208. return;
  209. QByteArray data =
  210. m_cpldBuffer.left(35);
  211. m_cpldBuffer.remove(0,35);
  212. qDebug()<<"温度帧:"
  213. <<data.toHex();
  214. //--------------------
  215. // CRC
  216. //--------------------
  217. uint16_t recvCrc =
  218. ((uint8_t)data[34]<<8)
  219. |
  220. (uint8_t)data[33];
  221. uint16_t calcCrc =
  222. crc16((uint8_t*)data.data()+2,31);
  223. if(recvCrc != calcCrc)
  224. {
  225. qDebug()<<"CRC错误";
  226. continue;
  227. }
  228. int temp=(uint8_t)data[25];
  229. qDebug()<<"sensor温度:"
  230. <<temp;
  231. if(temp >=40 && m_tempIndex==0)
  232. {
  233. preTimer->stop();
  234. QTimer::singleShot(200,this,[=](){
  235. connect(m_portBMC,&QSerialPort::readyRead,this,&SerialWorker::onReadyReadBMC);
  236. pidTimer->start(500);
  237. });
  238. }
  239. else if(temp>=70 && m_tempIndex==1)
  240. {
  241. preTimer->stop();
  242. QTimer::singleShot(200,this,[=](){
  243. connect(m_portBMC,&QSerialPort::readyRead,this,&SerialWorker::onReadyReadBMC);
  244. pidTimer->start(500);
  245. });
  246. }
  247. }
  248. }
  249. void SerialWorker::parsePIDData(const QByteArray &data)
  250. {
  251. QVector<double> temps;
  252. temps.reserve(CHANNEL_COUNT);
  253. for(int i = 0; i < CHANNEL_COUNT; ++i)
  254. {
  255. quint8 intPart = static_cast<quint8>(data[i * 2]);
  256. //quint8 decPart = static_cast<quint8>(data[i * 2 + 1]);
  257. if(intPart == 0xFF /*&& decPart == 0xFF*/)
  258. {
  259. temps.append(qQNaN());
  260. }
  261. else
  262. {
  263. temps.append(intPart/* + decPart / 100.0*/);
  264. }
  265. }
  266. qDebug()<<"temps"<<temps;
  267. emit signalNewTemps(temps); //发送给数据给主界面绘制
  268. if(m_tempIndex == 0)
  269. {
  270. controlHeat40(temps); //控温核心代码
  271. }
  272. else if(m_tempIndex == 1)
  273. {
  274. controlHeat(temps); //控温核心代码
  275. }
  276. }
  277. void SerialWorker::controlHeat(const QVector<double> &temps)
  278. {
  279. double target = 70.0;
  280. double sumTemp = 0.0;
  281. int count = 0;
  282. for(int i = 0; i < 6; i++)
  283. {
  284. double temp = temps[i];
  285. if(qIsNaN(temp))
  286. continue;
  287. sumTemp += temp;
  288. count++;
  289. }
  290. double fanDuty = 0.0;
  291. double duty = 0.0;
  292. double avgTemp = 0.0;
  293. if(count > 0)
  294. {
  295. avgTemp = sumTemp / count;
  296. // 第一组计算风扇
  297. fanDuty = m_pid[0].calculateFanDuty(avgTemp);
  298. // PID计算加热
  299. duty = m_pid[0].calculate(target, avgTemp);
  300. if(avgTemp > target)
  301. {
  302. sendUpCmd();
  303. }
  304. else
  305. {
  306. sendDownCmd();
  307. }
  308. for(int fan = 0; fan < 24; fan++)
  309. {
  310. txFrame[16 + fan] = (uint8_t)duty;
  311. }
  312. for(int fan = 0; fan < 4; fan++)
  313. {
  314. txFrame[40 + fan] = (uint8_t)fanDuty;
  315. }
  316. sendSnapshot();
  317. qDebug()<<"duty = "<<duty<<"fanDuty = "<<fanDuty;
  318. }
  319. }
  320. void SerialWorker::controlHeat40(const QVector<double> &temps)
  321. {
  322. double sumTemp = 0.0;
  323. int count = 0;
  324. for(int i = 0; i < 6; i++)
  325. {
  326. double temp = temps[i];
  327. if(qIsNaN(temp))
  328. continue;
  329. sumTemp += temp;
  330. count++;
  331. }
  332. double fanDuty = 0.0;
  333. double duty = 0.0;
  334. double avgTemp = 0.0;
  335. if(count > 0)
  336. {
  337. avgTemp = sumTemp / count;
  338. // 第一组计算风扇
  339. fanDuty = m_pid[0].calculateFanDuty1(avgTemp);
  340. if(avgTemp >= 40)
  341. {
  342. sendUpCmd();
  343. }
  344. else
  345. {
  346. sendDownCmd();
  347. }
  348. for(int fan = 0; fan < 24; fan++)
  349. {
  350. txFrame[16 + fan] = (uint8_t)duty;
  351. }
  352. for(int fan = 0; fan < 4; fan++)
  353. {
  354. txFrame[40 + fan] = (uint8_t)fanDuty;
  355. }
  356. sendSnapshot();
  357. qDebug()<<"duty = "<<duty<<"fanDuty = "<<fanDuty;
  358. }
  359. }
  360. void SerialWorker::sendSnapshot()
  361. {
  362. uint16_t crc = crc16(txFrame + 2,46);
  363. txFrame[48] = crc & 0xff;
  364. txFrame[49] = (crc >> 8)&0xff;
  365. QByteArray frame((char*)txFrame,50);
  366. m_portCPLD->write(frame);
  367. m_portCPLD->flush();
  368. }
  369. void SerialWorker::sendDownCmd()
  370. {
  371. if (m_position <= 0)
  372. {
  373. qDebug()<<m_position;
  374. return; // 已经到底了
  375. }
  376. QByteArray dataX = QByteArray::fromHex(
  377. "A55A02041100000000000000000835000103C20100001C32"
  378. );
  379. QByteArray dataY = QByteArray::fromHex(
  380. "A55A02041100000000000000000835010003C2010000DDCF"
  381. );
  382. m_portCPLD->write(dataX);
  383. m_portCPLD->write(dataY);
  384. m_portCPLD->flush();
  385. --m_position;
  386. qDebug()<<m_position;
  387. saveMotorPosition();
  388. }
  389. void SerialWorker::sendUpCmd()
  390. {
  391. if (m_position >= MAX_STEP)
  392. {
  393. qDebug()<<m_position;
  394. return; // 已经到顶了
  395. }
  396. QByteArray dataX = QByteArray::fromHex(
  397. "A55A02041100000000000000000835000003C2010000BC77"
  398. );
  399. QByteArray dataY = QByteArray::fromHex(
  400. "A55A02041100000000000000000835010103C20100007D8A"
  401. );
  402. m_portCPLD->write(dataX);
  403. m_portCPLD->write(dataY);
  404. m_portCPLD->flush();
  405. ++m_position;
  406. qDebug()<<m_position;
  407. saveMotorPosition();
  408. }
  409. void SerialWorker::saveMotorPosition()
  410. {
  411. QString path = QCoreApplication::applicationDirPath() + "/motor.ini";
  412. QSettings settings(path, QSettings::IniFormat);
  413. settings.setValue("Motor/Position", m_position);
  414. settings.sync();
  415. }