TKHS_SD.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596
  1. // TKHS_SD.cpp : 定义 DLL 的初始化例程。
  2. //
  3. #include "stdafx.h"
  4. #include "TKHS_SD.h"
  5. #include "UdpClientSocket.h"
  6. #include <queue>
  7. #include <math.h>
  8. #include <algorithm>
  9. struct DataBuf
  10. {
  11. int TestType;
  12. BYTE pbTimeBuf[15];
  13. int TimeLen;
  14. BYTE *pbHJdataBuf;
  15. int HJdataLen;
  16. BYTE *pbYQdataBuf;
  17. int YQdataLen;
  18. };
  19. /*加油枪数据
  20. 内容 长度 数据说明
  21. A/L 1字节 1字节整型数据,单位%
  22. 回收油气浓度 2字节 2字节无符号整型,最后1位表示小数点后第1位,单位%
  23. 回收油气温度 2字节 2字节有符号整型,最后1位表示小数点后第1位,单位℃
  24. 油气流速 2字节 2字节整型数据,单位L/min
  25. 加油流速 2字节 2字节整型数据,单位L/min
  26. 油气流量 2字节 2字节整型数据,单位L
  27. 燃油流量 2字节 2字节整型数据,单位L
  28. 加油持续时间 2字节 2字节整型数据,单位S
  29. ex:
  30. 数据项目 真实数据值 表示数值
  31. A/L 62% 用整型数据62表示
  32. 回收油气浓度 21.6% 用整型数据216表示,个位实际表示小数点后第1位
  33. 回收油气温度 26.4℃ 用整型数据264表示,个位实际表示小数点后第1位
  34. 油气流速 70L/min 用整型数据70表示
  35. 加油流速 112L/min 用整型数据112表示
  36. 油气流量 50L 用整型数据50表示
  37. 燃油流量 81L 用整型数据81表示
  38. 加油持续时间 33S 用整型数据33表示
  39. 字节位置 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
  40. 数据(Hex) 3e 00 d8 01 08 00 46 00 70 00 32 00 51 00 21*/
  41. struct StructYQ
  42. {
  43. BYTE al; //A/L 62% 用整型数据62表示
  44. BYTE concentration[2]; //回收油气浓度 21.6% 用整型数据216表示,个位实际表示小数点后第1位
  45. BYTE temperature[2]; //回收油气温度 26.4℃ 用整型数据264表示,个位实际表示小数点后第1位
  46. BYTE vapflow[2]; //油气流速 70L/min 用整型数据70表示
  47. BYTE liqflow[2]; //加油流速 112L/min 用整型数据112表示
  48. BYTE vapvol[2]; //油气流量 50L 用整型数据50表示
  49. BYTE liqvol[2]; //燃油流量 81L 用整型数据81表示
  50. BYTE timespan[2]; //加油持续时间 33S 用整型数据33表示
  51. };
  52. /*
  53. int TestType 测试类型:1符合性测试,2报警测试
  54. BYTE *pbTimeBuf 时间数据
  55. int TimeLen 时间数据长度
  56. BYTE *pbHJdataBuf 环境数据
  57. int HJdataLen 环境数据长度
  58. BYTE *pbYQdataBuf 加油枪数据
  59. int YQdataLen 加油枪数据长度
  60. 时间数据 14字节 时间(24小时制)格式为:yyyyMMddhhmmss
  61. 用十进制数的ASCII表示
  62. ex:
  63. 2015年06月26日19时03分16秒。
  64. 字节位置 0 1 2 3 4 5 6 7 8 9 10 11 12 13
  65. 数据(Hex) 32 30 31 35 30 36 32 36 31 39 30 33 31 36
  66. 环境数据
  67. 内容 长度 数据说明
  68. 储罐压力 4字节 4字节有符号整型,个位实际表示小数点后第1位,单位Pa
  69. ex: 105.6Pa HEX BUFFER: 00 00 04 20
  70. */
  71. struct StructRecv
  72. {
  73. BYTE TestType;
  74. BYTE pbTimeBuf[14];
  75. BYTE pbHJdataBuf[4];
  76. StructYQ pbYQdataBuf;
  77. };
  78. /*(下传协议测试数据)
  79. 油机上送:(length: 23)
  80. 长度(2Byte) + 命令字 + 加油点(1byte) + 枪 + 加油结束时间(7) + 总油量(3)
  81. + 最大油流速(2) + 总气量(3) + 最大气流速(2) + 气液比(2) + 测试类型(1)
  82. 模拟数据:01 01 00 01 01 00 17 11 01 01 20 17 05 22 16 39 30 00 07 D0 00 15 00 03 e8 00 14 04 4c 01
  83. */
  84. struct StructSend
  85. {
  86. byte dest[2];
  87. byte source[2];
  88. byte frame;
  89. byte length[2];
  90. byte cmd;
  91. byte fip;
  92. byte noz;
  93. byte time[7];
  94. byte liqvol[3]; //油体积;
  95. byte liqflow[2]; //油流速;
  96. byte vapvol[3]; //气体积;
  97. byte vapflow[2]; //气流速;
  98. byte vlr[2]; //气液比;
  99. byte testtag;
  100. };
  101. #ifdef _DEBUG
  102. #define new DEBUG_NEW
  103. #endif
  104. //
  105. //TODO: 如果此 DLL 相对于 MFC DLL 是动态链接的,
  106. // 则从此 DLL 导出的任何调入
  107. // MFC 的函数必须将 AFX_MANAGE_STATE 宏添加到
  108. // 该函数的最前面。
  109. //
  110. // 例如:
  111. //
  112. // extern "C" BOOL PASCAL EXPORT ExportedFunction()
  113. // {
  114. // AFX_MANAGE_STATE(AfxGetStaticModuleState());
  115. // // 此处为普通函数体
  116. // }
  117. //
  118. // 此宏先于任何 MFC 调用
  119. // 出现在每个函数中十分重要。 这意味着
  120. // 它必须作为函数中的第一个语句
  121. // 出现,甚至先于所有对象变量声明,
  122. // 这是因为它们的构造函数可能生成 MFC
  123. // DLL 调用。
  124. //
  125. // 有关其他详细信息,
  126. // 请参阅 MFC 技术说明 33 和 58。
  127. //
  128. // CTKHS_SDApp
  129. BEGIN_MESSAGE_MAP(CTKHS_SDApp, CWinApp)
  130. END_MESSAGE_MAP()
  131. int sendUDPData(CString strData, UINT nPort, LPCTSTR lpszAddress);
  132. DWORD __stdcall ThreadRecv(LPVOID lparam);
  133. DWORD __stdcall ThreadTimer(LPVOID lparam);
  134. CString strIP = "127.0.0.1";//"192.168.1.10";////"166.166.16.16";
  135. //CUdpClientSocket m_udpClient;
  136. std::queue<CString> que;
  137. DWORD m_id;
  138. DWORD m_recvid;
  139. CRITICAL_SECTION lock;
  140. CUdpClientSocket* pUdp;
  141. int count1 = 0;
  142. int count2 = 0;
  143. int count3 = 0;
  144. BOOL waittag = FALSE;
  145. int sendtimes = 0;
  146. long tickcount = 0;
  147. int failedtimes = 0;
  148. int g_recvflag = FALSE;
  149. long g_timerTick = 0;
  150. //发送线程
  151. DWORD __stdcall ThreadHandle(LPVOID lparam)
  152. {
  153. MSG msg;
  154. while (GetMessage(&msg, 0, 0, 0))
  155. {
  156. while (!que.empty())
  157. {
  158. EnterCriticalSection(&lock);
  159. CString szInfo = que.front();
  160. if (waittag == FALSE) //第一次发送
  161. {
  162. que.pop();
  163. LeaveCriticalSection(&lock);
  164. waittag = TRUE;
  165. sendtimes = 1;
  166. tickcount = GetTickCount();
  167. //BYTE buff[1024];
  168. //memset(buff, 0, 1024);
  169. //CTime tm = CTime::GetCurrentTime();
  170. //CString strTime = tm.Format("%Y%m%d%H%M%S");
  171. //CString szInfo;
  172. //szInfo = "010100010100";
  173. //szInfo += "17";
  174. //szInfo += "11";
  175. //szInfo += "01";
  176. //szInfo += "01";
  177. //szInfo += strTime;
  178. //szInfo += "0003e8"; //1000 / 100.0
  179. //szInfo += "0015"; //21 / 10.0
  180. //szInfo += "0003e8"; //1000 / 100.0
  181. //szInfo += "0014"; //20 / 10.0
  182. //szInfo += "03e8"; //1000 / 1000.0
  183. //szInfo += "01";
  184. int rtn = sendUDPData(szInfo, 10000, strIP);
  185. if (rtn == 0)
  186. {
  187. //AfxMessageBox(_T("send error!"));
  188. }
  189. count2++;
  190. CString str;
  191. str.Format(_T("\ncount2: %d\n"), count2);
  192. TRACE(str);
  193. }
  194. else //没收到,发三次
  195. {
  196. LeaveCriticalSection(&lock);
  197. if (failedtimes > 30) //总失败次数超过30则放弃重传机制
  198. {
  199. waittag = FALSE;
  200. continue;
  201. }
  202. if (sendtimes < 3 && GetTickCount() - tickcount > 1000)
  203. {
  204. sendtimes++;
  205. failedtimes++;
  206. //BYTE buff[1024];
  207. //memset(buff, 0, 1024);
  208. //CTime tm = CTime::GetCurrentTime();
  209. //CString strTime = tm.Format("%Y%m%d%H%M%S");
  210. //CString szInfo;
  211. //szInfo = "010100010100";
  212. //szInfo += "17";
  213. //szInfo += "11";
  214. //szInfo += "01";
  215. //szInfo += "01";
  216. //szInfo += strTime;
  217. //szInfo += "0003e8"; //1000 / 100.0
  218. //szInfo += "0015"; //21 / 10.0
  219. //szInfo += "0003e8"; //1000 / 100.0
  220. //szInfo += "0014"; //20 / 10.0
  221. //szInfo += "03e8"; //1000 / 1000.0
  222. //szInfo += "01";
  223. sendUDPData(szInfo, 10000, strIP);
  224. Sleep(10);
  225. tickcount = GetTickCount();
  226. }
  227. else if (sendtimes >= 3) //发送三次都不会则不再管
  228. {
  229. g_recvflag = FALSE;
  230. waittag = FALSE;
  231. }
  232. }
  233. }
  234. }
  235. return 1;
  236. }
  237. /*
  238. DWORD __stdcall ThreadHandle(LPVOID lparam)
  239. {
  240. MSG msg;
  241. while (GetMessage(&msg, 0, 0, 0))
  242. {
  243. if (msg.message == WM_THREAD_HANDLE)
  244. {
  245. EnterCriticalSection(&lock);
  246. if (!que.empty())
  247. {
  248. que.front();
  249. que.pop();
  250. LeaveCriticalSection(&lock);
  251. BYTE buff[1024];
  252. memset(buff, 0, 1024);
  253. CTime tm = CTime::GetCurrentTime();
  254. CString strTime = tm.Format("%Y%m%d%H%M%S");
  255. CString szInfo;
  256. szInfo = "010100010100";
  257. szInfo += "17";
  258. szInfo += "11";
  259. szInfo += "01";
  260. szInfo += "01";
  261. szInfo += strTime;
  262. szInfo += "0003e8"; //1000 / 100.0
  263. szInfo += "0015"; //21 / 10.0
  264. szInfo += "0003e8"; //1000 / 100.0
  265. szInfo += "0014"; //20 / 10.0
  266. szInfo += "03e8"; //1000 / 1000.0
  267. szInfo += "01";
  268. sendUDPData(szInfo, 10000, strIP);
  269. //count2++;
  270. //CString str;
  271. //str.Format(_T("\ncount2: %d\n"), count2);
  272. //TRACE(str);
  273. }
  274. else
  275. {
  276. LeaveCriticalSection(&lock);
  277. }
  278. }
  279. else if (msg.message == WM_THREAD_CLOSE)
  280. {
  281. pUdp->Close();
  282. }
  283. }
  284. return 1;
  285. }
  286. */
  287. // CTKHS_SDApp 构造
  288. CTKHS_SDApp::CTKHS_SDApp()
  289. {
  290. // TODO: 在此处添加构造代码,
  291. // 将所有重要的初始化放置在 InitInstance 中
  292. }
  293. CTKHS_SDApp::~CTKHS_SDApp()
  294. {
  295. ::PostThreadMessage(m_id, WM_THREAD_CLOSE, 0, 0);
  296. }
  297. // 唯一的一个 CTKHS_SDApp 对象
  298. CTKHS_SDApp theApp;
  299. // CTKHS_SDApp 初始化
  300. BOOL CTKHS_SDApp::InitInstance()
  301. {
  302. CWinApp::InitInstance();
  303. if (!AfxSocketInit())
  304. {
  305. AfxMessageBox(IDP_SOCKETS_INIT_FAILED);
  306. return FALSE;
  307. }
  308. InitializeCriticalSection(&lock);
  309. HANDLE h = ::CreateThread(NULL, 0, ThreadHandle, (LPVOID)this, NULL, &m_id);
  310. HANDLE hr = ::CreateThread(NULL, 0, ThreadRecv, (LPVOID)this, NULL, &m_recvid);
  311. HANDLE htimer = ::CreateThread(NULL, 0, ThreadTimer, (LPVOID)this, NULL, NULL);
  312. pUdp = new CUdpClientSocket();
  313. pUdp->Create(0, SOCK_DGRAM, NULL);
  314. //pUdp->SetDialog(this);
  315. g_timerTick = GetTickCount();
  316. return TRUE;
  317. }
  318. //计时器线程
  319. //通过发送心跳命令看有没有收到回复来判断有没有连接成功,这样在dll接口被调用时就可以返回相应的值
  320. //在Socket接收线程ThreadRecv收到回复后关闭
  321. DWORD __stdcall ThreadTimer(LPVOID lparam)
  322. {
  323. while (!g_recvflag)
  324. {
  325. if (GetTickCount() - g_timerTick > 100)
  326. {
  327. sendUDPData("010100010100080620170428170030", 10000, strIP);
  328. g_timerTick = GetTickCount();
  329. }
  330. }
  331. return 1;
  332. }
  333. //Socket接收线程
  334. DWORD __stdcall ThreadRecv(LPVOID lparam)
  335. {
  336. MSG msg;
  337. while (GetMessage(&msg, 0, 0, 0))
  338. {
  339. BYTE pBuffer2[1024] = { 0 };
  340. CString straddr;
  341. UINT port;
  342. pUdp->GetPeerName(straddr, port);
  343. int nRecvNum = pUdp->ReceiveFrom(pBuffer2, 1024, straddr, port);
  344. if (nRecvNum != -1)
  345. {
  346. waittag = FALSE;
  347. g_recvflag = TRUE;
  348. count3++;
  349. CString str;
  350. str.Format(_T("\ncount3: %d\n"), count3);
  351. TRACE(str);
  352. }
  353. }
  354. return 1;
  355. }
  356. int sendUDPData(CString strData, UINT nPort, LPCTSTR lpszAddress)
  357. {
  358. CString str;
  359. CString str1 = "";
  360. BYTE buff[1024];
  361. memset(buff, 0, 1024);
  362. str = strData;
  363. int interval = 2;
  364. if (strData.GetLength() > 3)
  365. {
  366. if (strData[2] == ' ')
  367. {
  368. interval = 3;
  369. }
  370. else
  371. {
  372. interval = 2;
  373. }
  374. }
  375. int extra = interval - 2;
  376. int len = (strData.GetLength() + extra) / interval;
  377. for (int i = 0; i < len; ++i)
  378. {
  379. CString str2 = strData.Mid(i*interval, 2);
  380. sscanf_s(str2, "%2x", &buff[i]);
  381. }
  382. int rtn = pUdp->SendTo(buff, len, nPort, lpszAddress);
  383. return rtn;
  384. }
  385. //srclen:源字节数 , times:相差倍数, dsclen: 目标字节数
  386. CString convert(BYTE* src, int srclen, int times,int dsclen)
  387. {
  388. int val = 0;
  389. for (int i = 0; i < srclen; ++i)
  390. {
  391. val += src[i] * pow(256, srclen - i - 1);
  392. }
  393. val *= times;
  394. CString str;
  395. str.Format("%x", val);
  396. while (str.GetLength() < dsclen * 2)
  397. {
  398. str = "0" + str;
  399. }
  400. return str;
  401. }
  402. time_t FormatTime2(char * szTime)
  403. {
  404. struct tm tm1;
  405. time_t time1;
  406. sscanf_s(szTime, "%4d%2d%2d%2d%2d%2d",
  407. &tm1.tm_year,
  408. &tm1.tm_mon,
  409. &tm1.tm_mday,
  410. &tm1.tm_hour,
  411. &tm1.tm_min,
  412. &tm1.tm_sec);
  413. tm1.tm_year -= 1900;
  414. tm1.tm_mon--;
  415. tm1.tm_isdst = -1;
  416. time1 = mktime(&tm1);
  417. return time1;
  418. }
  419. /*
  420. 方法名称:测试数据发送接口
  421. 功能描述 检测软件通过该接口向被测系统下发测试数据
  422. 输入 参数 说明
  423. int TestType 测试类型:1符合性测试,2报警测试
  424. BYTE *pbTimeBuf 时间数据
  425. int TimeLen 时间数据长度
  426. BYTE *pbHJdataBuf 环境数据
  427. int HJdataLen 环境数据长度
  428. BYTE *pbYQdataBuf 加油枪数据
  429. int YQdataLen 加油枪数据长度
  430. 返回值 0 :成功 1 :输入数据错误 2 :数据发送失败
  431. */
  432. extern "C" __declspec(dllexport) int TKHS_SendData(int TestType, BYTE *pbTimeBuf, int TimeLen, BYTE *pbHJdataBuf, int HJdataLen, BYTE *pbYQdataBuf, int YQdataLen)
  433. {
  434. EnterCriticalSection(&lock);
  435. StructRecv RecvBuf;
  436. RecvBuf.TestType = TestType;
  437. memcpy(RecvBuf.pbTimeBuf, pbTimeBuf, TimeLen);
  438. //buf.TimeLen = TimeLen;
  439. memcpy(RecvBuf.pbHJdataBuf, pbHJdataBuf, HJdataLen);
  440. //buf.HJdataLen = HJdataLen;
  441. memcpy(&RecvBuf.pbYQdataBuf, pbYQdataBuf, YQdataLen);
  442. //buf.YQdataLen = YQdataLen;
  443. CString szInfo;
  444. szInfo = "010100010100";
  445. szInfo += "22";
  446. szInfo += "11";
  447. szInfo += "01";
  448. szInfo += "01";
  449. szInfo += CString(pbTimeBuf);
  450. int time = RecvBuf.pbYQdataBuf.timespan[0]*256 + RecvBuf.pbYQdataBuf.timespan[1];
  451. time_t begtime = FormatTime2((char*)(pbTimeBuf));
  452. begtime += time;
  453. tm tm1;
  454. localtime_s(&tm1, &begtime);
  455. char chEndTime[15];
  456. sprintf_s(chEndTime, "%04d%02d%02d%02d%02d%02d",
  457. tm1.tm_year + 1900,
  458. tm1.tm_mon + 1,
  459. tm1.tm_mday,
  460. tm1.tm_hour,
  461. tm1.tm_min,
  462. tm1.tm_sec);
  463. szInfo += CString(chEndTime);
  464. //szInfo += "0003e8"; //1000 / 100.0 总油量(3) 下传协议: liqvol 2 燃油流量 81L 用整型数据81表示
  465. szInfo += convert(RecvBuf.pbYQdataBuf.liqvol, 2, 100,3);
  466. //szInfo += "0015"; //21 / 10.0 最大油流速(2) 下传协议: liqflow 2 加油流速 112L/min 用整型数据112表示
  467. szInfo += convert(RecvBuf.pbYQdataBuf.liqflow, 2, 10,2);
  468. //szInfo += "0003e8"; //1000 / 100.0 总气量(3) 下传协议: vapvol 2 油气流量 50L 用整型数据50表示
  469. szInfo += convert(RecvBuf.pbYQdataBuf.vapvol, 2, 100,3);
  470. //szInfo += "0014"; //20 / 10.0 最大气流速(2) 下传协议: vapflow 油气流速 70L/min 用整型数据70表示
  471. szInfo += convert(RecvBuf.pbYQdataBuf.vapflow, 2, 10,2);
  472. //szInfo += "03e8"; //1000 / 1000.0 气液比(2) 下传协议: al A/L 62% 用整型数据62表示
  473. szInfo += convert(&RecvBuf.pbYQdataBuf.al, 1, 10,2);
  474. //油罐压力(4) "000493e0" 300000 / 100.0 下传协议: 储罐压力 4字节 4字节有符号整型,个位实际表示小数点后第1位,单位Pa 00 00 04 20 --- 105.6Pa
  475. szInfo += convert(RecvBuf.pbHJdataBuf, 4, 10, 4);
  476. //szInfo += "01";
  477. szInfo += convert(&RecvBuf.TestType, 1, 1,1);
  478. que.push(szInfo);
  479. LeaveCriticalSection(&lock);
  480. ::PostThreadMessage(m_id, WM_THREAD_HANDLE, 0, 0);
  481. if ((TestType != 1 && TestType != 2)
  482. || ( TimeLen != 14 && TimeLen != 0)
  483. || (HJdataLen != 4 && HJdataLen != 0)
  484. || (YQdataLen != 15 && YQdataLen != 0))
  485. {
  486. return 1;
  487. }
  488. if (g_recvflag == 1)
  489. {
  490. return 0; //数据发送失败
  491. }
  492. else
  493. {
  494. return 2;
  495. }
  496. }