Program.cs 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Data;
  4. using System.Diagnostics;
  5. using System.Linq;
  6. using System.Runtime.InteropServices;
  7. using System.Runtime.InteropServices.ComTypes;
  8. using System.Text;
  9. using System.Threading;
  10. using System.Threading.Tasks;
  11. using CCDCount.DLL.CanBus;
  12. namespace CanTest
  13. {
  14. internal class Program
  15. {
  16. static UInt32 m_devtype = 4;//USBCAN2
  17. static UInt32 m_devind = 0;
  18. static UInt32 m_canind = 0;
  19. unsafe static void Main(string[] args)
  20. {
  21. // 示例:运行CANopen主站程序
  22. //RunCanOpenMaster();
  23. ConnectCan();
  24. SendTest();
  25. //GetTest();
  26. //MessageTest();
  27. }
  28. /// <summary>
  29. /// 运行CANopen主站示例
  30. /// </summary>
  31. static void RunCanOpenMaster()
  32. {
  33. Console.WriteLine("=== CANopen主站示例 ===\n");
  34. // 创建主站
  35. using (CanOpenMaster master = new CanOpenMaster(4, 0, 0))
  36. {
  37. // 注册事件回调
  38. master.OnTpdoReceived += Master_OnTpdoReceived;
  39. master.OnHeartbeatReceived += Master_OnHeartbeatReceived;
  40. master.OnEmergencyReceived += Master_OnEmergencyReceived;
  41. master.OnLogMessage += Master_OnLogMessage;
  42. // 初始化主站(波特率500kbps)
  43. if (!master.Initialize(CanBaudRate.BaudRate_500K))
  44. {
  45. Console.WriteLine("主站初始化失败!");
  46. return;
  47. }
  48. Console.WriteLine("\n主站初始化成功!\n");
  49. // 方式1: 不使用EDS文件(直接添加节点)
  50. Console.WriteLine("=== 方式1: 不使用EDS文件 ===");
  51. master.AddNode(1, "IO_Module_1");
  52. //master.AddNode(2, "IO_Module_2");
  53. // 方式2: 使用EDS文件(推荐用于第三方设备)
  54. //Console.WriteLine("\n=== 方式2: 使用EDS文件 ===");
  55. //string edsPath1 = @"D:\EDS\servo_drive.eds";
  56. //string edsPath2 = @"D:\EDS\io_module.eds";
  57. // 如果EDS文件存在,加载它们
  58. //if (System.IO.File.Exists(edsPath1))
  59. //{
  60. // master.AddNode(3, "Servo_Drive", edsPath1);
  61. // // 自动配置PDO映射
  62. // master.AutoConfigurePdoFromEds(3);
  63. //}
  64. //else
  65. //{
  66. // master.AddNode(3, "Servo_Drive");
  67. // Console.WriteLine($"EDS文件不存在: {edsPath1}, 使用默认配置");
  68. //}
  69. //if (System.IO.File.Exists(edsPath2))
  70. //{
  71. // master.AddNode(5, "Custom_Device", edsPath2);
  72. // master.AutoConfigurePdoFromEds(5);
  73. //}
  74. //else
  75. //{
  76. // master.AddNode(5, "Custom_Device");
  77. // Console.WriteLine($"EDS文件不存在: {edsPath2}, 使用默认配置");
  78. //}
  79. Console.WriteLine($"\n已添加 {master.NodeIds.Count} 个节点\n");
  80. // 显示EDS信息
  81. foreach (var nodeId in master.NodeIds)
  82. {
  83. var edsInfo = master.GetEdsInfo(nodeId);
  84. if (edsInfo != null)
  85. {
  86. Console.WriteLine($"节点{nodeId}: {edsInfo}");
  87. }
  88. }
  89. Console.WriteLine();
  90. // 等待从站上线
  91. Console.WriteLine("等待从站心跳...\n");
  92. Thread.Sleep(2000);
  93. // 扫描所有节点的设备信息
  94. ScanAllNodes(master);
  95. // 启动所有节点
  96. Console.WriteLine("\n=== 启动所有节点 ===");
  97. master.StartAllNodes();
  98. Thread.Sleep(1000);
  99. // 启用周期性SYNC(10ms周期)
  100. Console.WriteLine("\n=== 启用SYNC ===");
  101. Console.WriteLine("注意: SYNC用于触发从站自动发送TPDO数据");
  102. Console.WriteLine(" RPDO仍可由主站手动发送(事件驱动模式)");
  103. master.EnableSync(10);
  104. // 主循环 - 处理PDO数据
  105. Console.WriteLine("\n=== 进入主循环 (按任意键退出) ===\n");
  106. Console.WriteLine("工作原理:");
  107. Console.WriteLine(" 1. SYNC每10ms发送一次 → 从站自动发送TPDO → OnTpdoReceived事件触发");
  108. Console.WriteLine(" 2. RPDO由主站主动调用SendRpdo()发送(不依赖SYNC)");
  109. Console.WriteLine(" 3. SDO读写用于配置和非实时数据传输\n");
  110. bool running = true;
  111. Task.Run(() =>
  112. {
  113. Console.ReadKey();
  114. running = false;
  115. });
  116. int loopCount = 0;
  117. while (running && master.IsRunning)
  118. {
  119. loopCount++;
  120. // 每100次循环打印一次状态
  121. if (loopCount % 100 == 0)
  122. {
  123. PrintNodeStatus(master);
  124. }
  125. // 示例:定期读取某个节点的SDO数据(非实时配置)
  126. if (loopCount % 500 == 0)
  127. {
  128. ReadNodeParameters(master, 1);
  129. }
  130. // 示例:向节点写入控制命令(SDO方式 - 低速但可靠)
  131. if (loopCount % 1000 == 0)
  132. {
  133. WriteControlCommand(master, 1);
  134. }
  135. // 示例:通过RPDO发送控制数据(PDO方式 - 高速实时控制)
  136. // 注意: 这里的RPDO发送是"事件驱动"模式,不依赖SYNC
  137. // 如果要实现同步RPDO,需要在从站配置RPDO为同步触发类型
  138. if (loopCount % 200 == 0)
  139. {
  140. SendRpdoControl(master, 1);
  141. }
  142. Thread.Sleep(10);
  143. }
  144. // 停止SYNC
  145. master.DisableSync();
  146. // 停止所有节点
  147. Console.WriteLine("\n=== 停止所有节点 ===");
  148. master.StopAllNodes();
  149. Console.WriteLine("\n主站程序结束");
  150. }
  151. }
  152. /// <summary>
  153. /// 演示如何使用EDS文件的完整示例
  154. /// </summary>
  155. static void EdsFileUsageExample()
  156. {
  157. Console.WriteLine("=== EDS文件使用示例 ===\n");
  158. using (CanOpenMaster master = new CanOpenMaster(4, 0, 0))
  159. {
  160. master.Initialize(CanBaudRate.BaudRate_500K);
  161. // 场景1: 加载伺服驱动器的EDS文件
  162. Console.WriteLine("场景1: 加载伺服驱动器EDS");
  163. string servoEds = @"C:\Devices\ServoDrive.eds";
  164. if (System.IO.File.Exists(servoEds))
  165. {
  166. master.AddNode(1, "Servo_X", servoEds);
  167. // 查看EDS信息
  168. var edsInfo = master.GetEdsInfo(1);
  169. if (edsInfo != null)
  170. {
  171. Console.WriteLine($" 厂商: {edsInfo.VendorName}");
  172. Console.WriteLine($" 产品: {edsInfo.ProductName}");
  173. Console.WriteLine($" TPDO映射数: {edsInfo.TpdoMappings.Count}");
  174. // 自动配置PDO
  175. master.AutoConfigurePdoFromEds(1);
  176. }
  177. }
  178. else
  179. {
  180. Console.WriteLine(" EDS文件不存在,跳过此场景");
  181. }
  182. // 场景2: 不使用EDS文件(硬编码方式)
  183. Console.WriteLine("\n场景2: 不使用EDS文件");
  184. master.AddNode(2, "Simple_IO");
  185. // 手动读写已知对象
  186. master.SdoWriteAndWait(2, 0x6200, 0x01, 0x000000FF);
  187. var response = master.SdoReadAndWait(2, 0x6000, 0x01);
  188. if (response != null)
  189. {
  190. uint value = BitConverter.ToUInt32(response, 4);
  191. Console.WriteLine($" 读取值: 0x{value:X8}");
  192. }
  193. // 场景3: 混合使用
  194. Console.WriteLine("\n场景3: 混合使用(部分节点用EDS,部分不用)");
  195. master.AddNode(3, "Device_A", servoEds); // 有EDS
  196. master.AddNode(4, "Device_B"); // 无EDS
  197. Console.WriteLine("\n完成!");
  198. }
  199. }
  200. /// <summary>
  201. /// 简单的CANopen主站测试
  202. /// </summary>
  203. static void SimpleCanOpenMasterTest()
  204. {
  205. Console.WriteLine("=== 简单CANopen主站测试 ===\n");
  206. using (CanOpenMaster master = new CanOpenMaster(4, 0, 0))
  207. {
  208. // 注册基本事件
  209. master.OnHeartbeatReceived += (nodeId, status) =>
  210. {
  211. Console.WriteLine($"[HB] 节点{nodeId}: 0x{status:X2}");
  212. };
  213. master.OnTpdoReceived += (nodeId, data) =>
  214. {
  215. string dataStr = BitConverter.ToString(data).Replace("-", " ");
  216. Console.WriteLine($"[TPDO] 节点{nodeId}: [{dataStr}]");
  217. };
  218. // 初始化
  219. if (!master.Initialize(CanBaudRate.BaudRate_500K))
  220. {
  221. Console.WriteLine("初始化失败");
  222. return;
  223. }
  224. // 添加一个节点
  225. master.AddNode(1);
  226. Console.WriteLine("等待2秒接收心跳...");
  227. Thread.Sleep(2000);
  228. // 尝试读取设备类型
  229. Console.WriteLine("\n读取设备类型...");
  230. uint deviceType = master.ReadDeviceType(1);
  231. Console.WriteLine($"设备类型: 0x{deviceType:X8}");
  232. // 启动节点
  233. Console.WriteLine("\n启动节点...");
  234. master.NmtStartNode(1);
  235. Thread.Sleep(500);
  236. // 发送几次SYNC
  237. Console.WriteLine("\n发送SYNC...");
  238. for (int i = 0; i < 5; i++)
  239. {
  240. master.SendSync((byte)(i + 1));
  241. Thread.Sleep(100);
  242. }
  243. Console.WriteLine("\n测试完成");
  244. }
  245. }
  246. /// <summary>
  247. /// TPDO接收事件处理
  248. /// </summary>
  249. private static void Master_OnTpdoReceived(byte nodeId, byte[] data)
  250. {
  251. string dataStr = BitConverter.ToString(data).Replace("-", " ");
  252. Console.WriteLine($"[TPDO] 节点{nodeId}: 数据=[{dataStr}]");
  253. }
  254. /// <summary>
  255. /// 心跳接收事件处理
  256. /// </summary>
  257. private static void Master_OnHeartbeatReceived(byte nodeId, byte status)
  258. {
  259. string statusStr = GetNodeStatusString(status);
  260. Console.WriteLine($"[Heartbeat] 节点{nodeId}: 状态={statusStr} (0x{status:X2})");
  261. }
  262. /// <summary>
  263. /// 紧急消息事件处理
  264. /// </summary>
  265. private static void Master_OnEmergencyReceived(byte nodeId, ushort errorCode)
  266. {
  267. Console.WriteLine($"[EMERGENCY] 节点{nodeId}: 错误代码=0x{errorCode:X4}");
  268. }
  269. /// <summary>
  270. /// 日志消息事件处理
  271. /// </summary>
  272. private static void Master_OnLogMessage(string message)
  273. {
  274. // 可以选择性地输出日志,避免过多输出
  275. // Console.WriteLine(message);
  276. }
  277. /// <summary>
  278. /// 扫描所有节点的设备信息
  279. /// </summary>
  280. static void ScanAllNodes(CanOpenMaster master)
  281. {
  282. Console.WriteLine("=== 扫描节点设备信息 ===");
  283. foreach (var nodeId in master.NodeIds)
  284. {
  285. Console.WriteLine($"\n--- 节点 {nodeId} ---");
  286. try
  287. {
  288. // 读取设备类型
  289. uint deviceType = master.ReadDeviceType(nodeId);
  290. Console.WriteLine($" 设备类型: 0x{deviceType:X8}");
  291. // 读取厂商ID
  292. uint vendorId = master.ReadVendorId(nodeId);
  293. Console.WriteLine($" 厂商ID: 0x{vendorId:X8}");
  294. // 读取产品代码
  295. uint productCode = master.ReadProductCode(nodeId);
  296. Console.WriteLine($" 产品代码: 0x{productCode:X8}");
  297. // 读取序列号
  298. uint serialNumber = master.ReadSerialNumber(nodeId);
  299. Console.WriteLine($" 序列号: 0x{serialNumber:X8}");
  300. // 更新节点信息
  301. var node = master.GetNode(nodeId);
  302. if (node != null)
  303. {
  304. Console.WriteLine($" 状态: {node.GetStateString()}");
  305. Console.WriteLine($" 在线: {(node.IsOnline() ? "是" : "否")}");
  306. }
  307. }
  308. catch (Exception ex)
  309. {
  310. Console.WriteLine($" 读取失败: {ex.Message}");
  311. }
  312. Thread.Sleep(50); // 避免总线拥塞
  313. }
  314. }
  315. /// <summary>
  316. /// 读取节点参数
  317. /// </summary>
  318. static void ReadNodeParameters(CanOpenMaster master, byte nodeId)
  319. {
  320. var node = master.GetNode(nodeId);
  321. if (node == null) return;
  322. // 示例:读取对象字典中的某个参数
  323. // 这里读取0x6000:01 (假设是数字输入状态)
  324. var response = master.SdoReadAndWait(nodeId, 0x6000, 0x01, 500);
  325. if (response != null && response.Length >= 5)
  326. {
  327. uint value = BitConverter.ToUInt32(response, 4);
  328. Console.WriteLine($"[SDO Read] 节点{nodeId}, 索引0x6000:01 = 0x{value:X8}");
  329. }
  330. }
  331. /// <summary>
  332. /// 写入控制命令(SDO方式)
  333. /// </summary>
  334. static void WriteControlCommand(CanOpenMaster master, byte nodeId)
  335. {
  336. var node = master.GetNode(nodeId);
  337. if (node == null) return;
  338. // 示例:写入对象字典中的某个参数
  339. // 这里写入0x6200:01 (假设是数字输出控制)
  340. uint controlValue = 0x00000001; // 设置第1位
  341. bool success = master.SdoWriteAndWait(nodeId, 0x6200, 0x01, controlValue, 500);
  342. if (success)
  343. {
  344. Console.WriteLine($"[SDO Write] 节点{nodeId}, 索引0x6200:01 = 0x{controlValue:X8} - 成功");
  345. }
  346. else
  347. {
  348. Console.WriteLine($"[SDO Write] 节点{nodeId}, 索引0x6200:01 = 0x{controlValue:X8} - 失败");
  349. }
  350. }
  351. /// <summary>
  352. /// 通过RPDO发送控制数据(PDO方式 - 高速)
  353. /// </summary>
  354. static int rpdoCount = 0;
  355. static void SendRpdoControl(CanOpenMaster master, byte nodeId)
  356. {
  357. var node = master.GetNode(nodeId);
  358. if (node == null) return;
  359. // 准备RPDO数据(根据映射配置)
  360. // 假设RPDO1映射: 0x6200:01 (DO1, 8位), 0x6200:02 (DO2, 8位)
  361. byte[] rpdoData = new byte[2];
  362. rpdoData[0] = 0xFF; // DO1全部置ON
  363. rpdoData[1] = 0x00; // DO2全部置OFF
  364. // 发送RPDO
  365. bool success = master.SendRpdo(nodeId, 1, rpdoData);
  366. if (success)
  367. {
  368. // 每50次打印一次,避免刷屏
  369. rpdoCount++;
  370. if (rpdoCount % 50 == 0)
  371. {
  372. Console.WriteLine($"[RPDO Write] 节点{nodeId}, RPDO1: DO1=0x{rpdoData[0]:X2}, DO2=0x{rpdoData[1]:X2}");
  373. }
  374. }
  375. }
  376. /// <summary>
  377. /// 演示PDO映射配置
  378. /// </summary>
  379. static void PdoMappingExample(CanOpenMaster master, byte nodeId)
  380. {
  381. Console.WriteLine($"\n=== 配置节点{nodeId}的PDO映射 ===");
  382. // 配置RPDO1映射
  383. var rpdo1Mapping = new List<MappedObject>
  384. {
  385. new MappedObject { Index = 0x6200, SubIndex = 0x01, BitLength = 8 }, // DO1
  386. new MappedObject { Index = 0x6200, SubIndex = 0x02, BitLength = 8 } // DO2
  387. };
  388. bool success = master.ConfigureRpdoMapping(nodeId, 1, rpdo1Mapping);
  389. Console.WriteLine($"RPDO1映射配置: {(success ? "成功" : "失败")}");
  390. // 配置TPDO1映射
  391. var tpdo1Mapping = new List<MappedObject>
  392. {
  393. new MappedObject { Index = 0x6400, SubIndex = 0x01, BitLength = 16 }, // AI1
  394. new MappedObject { Index = 0x6400, SubIndex = 0x02, BitLength = 16 } // AI2
  395. };
  396. success = master.ConfigureTpdoMapping(nodeId, 1, tpdo1Mapping);
  397. Console.WriteLine($"TPDO1映射配置: {(success ? "成功" : "失败")}");
  398. }
  399. /// <summary>
  400. /// 打印节点状态
  401. /// </summary>
  402. static void PrintNodeStatus(CanOpenMaster master)
  403. {
  404. Console.WriteLine("\n--- 节点状态 ---");
  405. foreach (var nodeId in master.NodeIds)
  406. {
  407. var node = master.GetNode(nodeId);
  408. if (node != null)
  409. {
  410. Console.WriteLine(node.ToString());
  411. }
  412. }
  413. Console.WriteLine();
  414. }
  415. /// <summary>
  416. /// 获取节点状态字符串
  417. /// </summary>
  418. static string GetNodeStatusString(byte status)
  419. {
  420. switch (status & 0x7F)
  421. {
  422. case 0x00: return "启动中";
  423. case 0x04: return "停止";
  424. case 0x05: return "运行";
  425. case 0x7F: return "预操作";
  426. default: return "未知";
  427. }
  428. }
  429. static void ConnectCan()
  430. {
  431. //string SendId = "0x0000000f";
  432. //开启设备
  433. if (CanLibraryClass.VCI_OpenDevice(m_devtype, m_devind, 0) == 0)
  434. {
  435. Console.WriteLine("打开设备失败,请检查设备类型和设备索引号是否正确");
  436. return;
  437. }
  438. //初始化CAN
  439. VCI_INIT_CONFIG config = new VCI_INIT_CONFIG();
  440. config.AccCode = Convert.ToUInt32("0x00000000", 16);
  441. config.AccMask = Convert.ToUInt32("0xFFFFFFFF", 16);
  442. config.Timing0 = Convert.ToByte("0x00", 16);
  443. config.Timing1 = Convert.ToByte("0x14", 16);
  444. config.Filter = (Byte)1;
  445. config.Mode = (Byte)0;
  446. if (CanLibraryClass.VCI_InitCAN(m_devtype, m_devind, m_canind, ref config) == 0)
  447. {
  448. Console.WriteLine("初始化Can失败");
  449. return;
  450. }
  451. if (CanLibraryClass.VCI_StartCAN(m_devtype, m_devind, m_canind) == 0)
  452. {
  453. Console.WriteLine("开启Can失败");
  454. return;
  455. }
  456. }
  457. unsafe static void SendTest()
  458. {
  459. int DataLen = 1;
  460. int SendCount = 0;
  461. int sendnum = 0;
  462. int InSendCount = 0;
  463. TimeSpan WhileSleepTime = TimeSpan.FromTicks(10000 * 4);
  464. Stopwatch SW = new Stopwatch();
  465. Stopwatch RunTime = new Stopwatch();
  466. Console.WriteLine("请输入循环次数");
  467. InSendCount = Convert.ToInt32(Console.ReadLine());
  468. RunTime.Start();
  469. while (SendCount < InSendCount)
  470. {
  471. SW.Restart();
  472. VCI_CAN_OBJ sendobj = new VCI_CAN_OBJ();
  473. sendobj.RemoteFlag = (byte)(0);
  474. sendobj.ExternFlag = (byte)(0);
  475. sendobj.ID = Convert.ToUInt32(Convert.ToString(2, 16), 16);
  476. sendobj.DataLen = Convert.ToByte(DataLen);
  477. for (int i = 1; i < DataLen + 1; i++)
  478. {
  479. sendobj.Data[i - 1] = BitConverter.GetBytes(sendnum % 256)[0];
  480. sendnum++;
  481. }
  482. if (CanLibraryClass.VCI_Transmit(m_devtype, m_devind, m_canind, ref sendobj, 1) == 0)
  483. {
  484. Console.WriteLine("发送失败");
  485. continue;
  486. }
  487. SendCount++;
  488. Console.WriteLine("运行时常:{0},帧ID:{1},帧发送耗时:{2}\n" +
  489. "Data0:{3},Data0:{4},Data0:{5},Data0:{6},\n" +
  490. "Data0:{7},Data0:{8},Data0:{9},Data0:{10},",
  491. RunTime.Elapsed, SendCount, SW.Elapsed,
  492. sendobj.Data[0], sendobj.Data[1], sendobj.Data[2], sendobj.Data[3],
  493. sendobj.Data[4], sendobj.Data[5], sendobj.Data[6], sendobj.Data[7]);
  494. while (SW.Elapsed <= WhileSleepTime)
  495. {
  496. }
  497. if (SendCount == InSendCount)
  498. {
  499. RunTime.Stop();
  500. Console.WriteLine("总耗时:{0}", RunTime.Elapsed);
  501. Console.WriteLine("输入新的循环数(输入0结束):");
  502. int newnum = Convert.ToInt32(Console.ReadLine());
  503. if (newnum != 0)
  504. {
  505. SendCount = 0;
  506. InSendCount = newnum;
  507. RunTime.Restart();
  508. }
  509. }
  510. }
  511. CanLibraryClass.VCI_ResetCAN(m_devtype, m_devind, m_canind);
  512. Console.WriteLine("流程完成");
  513. Console.ReadKey();
  514. }
  515. unsafe static void GetTest()
  516. {
  517. UInt32 res = new UInt32();
  518. VCI_CAN_OBJ[] m_recobj = new VCI_CAN_OBJ[1000];
  519. Console.WriteLine("请输入运行时长(单位:分钟)");
  520. int runtimeLength = Convert.ToInt32(Console.ReadLine());
  521. DateTime StartTime = DateTime.Now;
  522. int getCount = 0;
  523. Task SetTask = new Task(() =>
  524. {
  525. while ((DateTime.Now - StartTime).TotalMilliseconds < runtimeLength * 60 * 1000)
  526. {
  527. res = CanLibraryClass.VCI_Receive(m_devtype, m_devind, m_canind, ref m_recobj[0], 1000, 100);
  528. getCount++;
  529. if (res == 0xFFFFFFFF) res = 0;
  530. if (res != 0)
  531. {
  532. for (UInt32 i = 0; i < res; i++)
  533. {
  534. string str = "";
  535. str = "接收到数据: ";
  536. str += " 帧ID:0x" + System.Convert.ToString(m_recobj[i].ID, 16);
  537. str += " 帧格式:";
  538. if (m_recobj[i].RemoteFlag == 0)
  539. str += "数据帧 ";
  540. else
  541. str += "远程帧 ";
  542. if (m_recobj[i].ExternFlag == 0)
  543. str += "标准帧 ";
  544. else
  545. str += "扩展帧 ";
  546. if (m_recobj[i].RemoteFlag == 0)
  547. {
  548. fixed (VCI_CAN_OBJ* m_recobj1 = &m_recobj[i])
  549. {
  550. str += "数据:";
  551. for (byte k = 0; k < 8; k++)
  552. {
  553. str += " " + m_recobj1->Data[k].ToString("X2");
  554. }
  555. }
  556. }
  557. Console.WriteLine(str);
  558. }
  559. }
  560. }
  561. Console.WriteLine("运行结束,运行次数{0}", getCount);
  562. CanLibraryClass.VCI_ResetCAN(m_devtype, m_devind, m_canind);
  563. });
  564. SetTask.Start();
  565. Console.ReadKey();
  566. }
  567. unsafe static void MessageTest()
  568. {
  569. UInt32 res = new UInt32();
  570. VCI_CAN_OBJ[] m_recobj = new VCI_CAN_OBJ[1000];
  571. Console.WriteLine("请输入运行时长(单位:分钟)");
  572. int runtimeLength = Convert.ToInt32(Console.ReadLine());
  573. DateTime StartTime = DateTime.Now;
  574. int getCount = 0;
  575. int DataLen = 8;
  576. int SendCount = 0;
  577. //Stopwatch SW = new Stopwatch();
  578. Stopwatch InterValSW = new Stopwatch();
  579. TimeSpan WhileSleepTime = TimeSpan.FromTicks(10000 * 1);
  580. TimeSpan MaxTime = TimeSpan.MinValue;
  581. TimeSpan MinTime = TimeSpan.MaxValue;
  582. int num04 = 0;
  583. int num48 = 0;
  584. int num8p = 0;
  585. Task SetTask = new Task(() =>
  586. {
  587. int previousWriteDone = 0;
  588. while ((DateTime.Now - StartTime).TotalMilliseconds < runtimeLength * 60 * 1000)
  589. {
  590. //SW.Restart();
  591. InterValSW.Restart();
  592. res = CanLibraryClass.VCI_Receive(m_devtype, m_devind, m_canind, ref m_recobj[0], 1000, 100);
  593. if (res == 0xFFFFFFFF) res = 0;
  594. //if (res == 0) Console.WriteLine("res=0");
  595. if (res != 0)
  596. {
  597. for (UInt32 i = 0; i < res; i++)
  598. {
  599. string str = "";
  600. if (m_recobj[i].RemoteFlag == 0)
  601. {
  602. getCount++;
  603. int writeDone = -1;
  604. fixed (VCI_CAN_OBJ* m_recobj1 = &m_recobj[i])
  605. {
  606. writeDone = m_recobj1->Data[6] & 0x01;
  607. //if(true)
  608. if (writeDone != previousWriteDone)
  609. {
  610. str = DateTime.Now.ToString("HH mm ss ffffff:");
  611. str += "运行次数:" + getCount;
  612. str += "接收到数据: ";
  613. str += " 帧ID:0x" + System.Convert.ToString(m_recobj[i].ID, 16);
  614. str += " 帧格式:";
  615. if (m_recobj[i].RemoteFlag == 0)
  616. str += "数据帧 ";
  617. else
  618. str += "远程帧 ";
  619. if (m_recobj[i].ExternFlag == 0)
  620. str += "标准帧 ";
  621. else
  622. str += "扩展帧 ";
  623. str += "数据:";
  624. for (byte k = 0; k < 8; k++)
  625. {
  626. str += " " + m_recobj1->Data[k].ToString("X2");
  627. }
  628. }
  629. }
  630. if ((writeDone == 1 && previousWriteDone == 0) || (writeDone == 0 && previousWriteDone == 1))
  631. {
  632. VCI_CAN_OBJ sendobj = new VCI_CAN_OBJ();
  633. sendobj.RemoteFlag = (byte)(0);
  634. sendobj.ExternFlag = (byte)(0);
  635. sendobj.ID = Convert.ToUInt32(Convert.ToString(2, 16), 16);
  636. sendobj.DataLen = Convert.ToByte(DataLen);
  637. byte SendMessage0 = new byte();
  638. SendMessage0 |= (byte)(1 << SendCount % 8);
  639. //SendMessage0 |= (byte)(1 << 0);
  640. sendobj.Data[0] = SendMessage0;
  641. byte SendMessage1 = new byte();
  642. SendMessage1 |= (byte)(1 << SendCount % 8);
  643. //SendMessage1 |= (byte)(1 << 0);
  644. sendobj.Data[1] = SendMessage1;
  645. byte SendMessage6 = new byte();
  646. SendMessage6 = (byte)(1 << 0);
  647. sendobj.Data[6] = SendMessage6;
  648. byte SendMessage7 = new byte();
  649. if (SendCount % 10 == 0)
  650. SendMessage7 |= (byte)(1 << 0);
  651. if (SendCount % 11 == 0)
  652. SendMessage7 |= (byte)(1 << 1);
  653. sendobj.Data[7] = SendMessage7;
  654. str += "发送数据:";
  655. str += string.Format("byte0:{0},byte1:{1},byte6:{2},byte7:{3}",
  656. SendMessage0.ToString("000"), SendMessage1.ToString("000"),
  657. SendMessage6.ToString("000"), SendMessage7.ToString("000"));
  658. if (CanLibraryClass.VCI_Transmit(m_devtype, m_devind, m_canind, ref sendobj, 1) == 0)
  659. {
  660. Console.WriteLine("发送失败");
  661. continue;
  662. }
  663. InterValSW.Stop();
  664. if (SendCount != 0)
  665. {
  666. MaxTime = InterValSW.Elapsed > MaxTime ? InterValSW.Elapsed : MaxTime;
  667. MinTime = InterValSW.Elapsed < MinTime ? InterValSW.Elapsed : MinTime;
  668. if (InterValSW.Elapsed <= TimeSpan.FromMilliseconds(4))
  669. {
  670. num04++;
  671. }
  672. else if (InterValSW.Elapsed <= TimeSpan.FromMilliseconds(8))
  673. {
  674. num48++;
  675. }
  676. else
  677. {
  678. num8p++;
  679. }
  680. }
  681. SendCount++;
  682. }
  683. previousWriteDone = writeDone;
  684. }
  685. if (!string.IsNullOrEmpty(str))
  686. Console.WriteLine(str);
  687. }
  688. }
  689. //while (SW.Elapsed <= WhileSleepTime)
  690. //{
  691. //}
  692. }
  693. Console.WriteLine("运行结束,运行次数{0},发送次数{1},最小耗时{2},最大耗时{3}",
  694. getCount, SendCount, MinTime.TotalMilliseconds, MaxTime.TotalMilliseconds);
  695. Console.WriteLine("运行耗时统计,0-4:{0},4-8:{1},8+:{2}", num04, num48, num8p);
  696. CanLibraryClass.VCI_ResetCAN(m_devtype, m_devind, m_canind);
  697. });
  698. SetTask.Start();
  699. Console.ReadKey();
  700. }
  701. }
  702. }