当前位置:   article > 正文

libusb的异步也有这样的问题_libusb异步传输

libusb异步传输

1. 最近一直在关注异步机制,不管是网络库asio,libuv,还是libusb库,其实异步机制都是差不多的,都是基于回调函数、系统轮询实现的。

2. 下面是对一款USB产品做得测试结果,Windows环境下,用libusb异步API写的程序:


说明:用 Bus Hound 抓包,查看返回数值发现上面三个命令只有R是成功的(即有返回值),却对应在了B命令上,导致调用了B的回调。这就是异步容易导致的问题,也就是如果不停地发送命令,其中有一条命令失败,而这条命令的超时未过,回来的结果如果没有别的区分,会认为是该条命令的返回数据,而导致调用失败指令的回调函数,而导致比较严重的后果。

  1. #include <errno.h>
  2. #include <pthread.h>
  3. #include <semaphore.h>
  4. #include <signal.h>
  5. #include <string.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <windows.h>
  9. #include "libusb.h"
  10. #define EP_IN (6 | LIBUSB_ENDPOINT_IN)
  11. #define EP_OUT (2 | LIBUSB_ENDPOINT_OUT)
  12. typedef enum {
  13. SAVE_IMAGE = 0x55,
  14. UPLOAD_IMAGE = 0xAA
  15. }BULK_REQCODE;
  16. typedef enum {
  17. SAVE_IMAGE_VAL = 0x00,
  18. UPLOAD_B_VAL = 0x00,
  19. UPLOAD_G_VAL = 0x01,
  20. UPLOAD_R_VAL = 0x02
  21. }BULK_VALUE;
  22. static struct libusb_device_handle *devh = NULL;
  23. static unsigned char imgbuf_save[8];
  24. static unsigned char imgbuf_upload[8];
  25. static unsigned char imgbuf_R[2048*240];
  26. static unsigned char imgbuf_G[2048*240];
  27. static unsigned char imgbuf_B[2048*240];
  28. static struct libusb_transfer *img_save = NULL;
  29. static struct libusb_transfer *img_R = NULL;
  30. static struct libusb_transfer *img_G = NULL;
  31. static struct libusb_transfer *img_B = NULL;
  32. static struct libusb_transfer *img_R_upload = NULL;
  33. static struct libusb_transfer *img_G_upload = NULL;
  34. static struct libusb_transfer *img_B_upload = NULL;
  35. static int img_idx = 0;
  36. static volatile sig_atomic_t do_exit = 0;
  37. static int ii=0;
  38. static pthread_t poll_thread;
  39. static sem_t exit_sem;
  40. static void request_exit(sig_atomic_t code)
  41. {
  42. do_exit = code;
  43. sem_post(&exit_sem);
  44. }
  45. static void *poll_thread_main(void *arg) //轮询是否main——thread结束
  46. {
  47. int r = 0;
  48. printf("poll thread running\n");
  49. while (!do_exit) {
  50. struct timeval tv = { 1, 0 };
  51. r = libusb_handle_events_timeout(NULL, &tv); //处理任何待以处理的事件
  52. if (r < 0) {
  53. request_exit(2);
  54. break;
  55. }
  56. }
  57. printf("poll thread shutting down\n");
  58. return NULL;
  59. }
  60. static int find_dpfp_device(void)
  61. {
  62. devh = libusb_open_device_with_vid_pid(NULL, 0x04b4, 0x8623);
  63. return devh ? 0 : -EIO;
  64. }
  65. static void LIBUSB_CALL cb_img(struct libusb_transfer *transfer)
  66. {
  67. if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
  68. fprintf(stderr, "img transfer status %d?\n", transfer->status);
  69. request_exit(2);
  70. return;
  71. }
  72. std::cout << "upload_img_R_over callback : " << transfer->status << std::endl;
  73. }
  74. static void LIBUSB_CALL save_img(struct libusb_transfer *transfer)
  75. {
  76. if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
  77. fprintf(stderr, "img transfer status %d?\n", transfer->status);
  78. request_exit(2);
  79. return;
  80. }
  81. std::cout << "save Image callback : " << transfer->status << std::endl;
  82. }
  83. static void LIBUSB_CALL upload_img_B(struct libusb_transfer *transfer)
  84. {
  85. if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
  86. fprintf(stderr, "img transfer status %d?\n", transfer->status);
  87. request_exit(2);
  88. return;
  89. }
  90. std::cout << "upload_img_B callback : " << transfer->status << std::endl;
  91. }
  92. static void LIBUSB_CALL upload_img_B_over(struct libusb_transfer *transfer)
  93. {
  94. if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
  95. fprintf(stderr, "img transfer status %d?\n", transfer->status);
  96. request_exit(2);
  97. return;
  98. }
  99. std::cout << "upload_img_B_over callback : " << transfer->status << std::endl;
  100. }
  101. static void LIBUSB_CALL upload_img_G(struct libusb_transfer *transfer)
  102. {
  103. if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
  104. fprintf(stderr, "img transfer status %d?\n", transfer->status);
  105. request_exit(2);
  106. return;
  107. }
  108. std::cout << "upload_img_G callback : " << transfer->status << std::endl;
  109. }
  110. static void LIBUSB_CALL upload_img_G_over(struct libusb_transfer *transfer)
  111. {
  112. if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
  113. fprintf(stderr, "img transfer status %d?\n", transfer->status);
  114. request_exit(2);
  115. return;
  116. }
  117. std::cout << "upload_img_G_over callback : " << transfer->status << std::endl;
  118. }
  119. static void LIBUSB_CALL upload_img_R(struct libusb_transfer *transfer)
  120. {
  121. if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
  122. fprintf(stderr, "img transfer status %d?\n", transfer->status);
  123. request_exit(2);
  124. return;
  125. }
  126. std::cout << "upload_img_R callback : " << transfer->status << std::endl;
  127. }
  128. //由于该设备处理多命令异步发送过来的时候,只处理最后一条
  129. static int LIBUSB_CALL submit_trans()
  130. {
  131. int r=0;
  132. r = libusb_submit_transfer(img_save); //提交一个传输并立即返回
  133. if (r < 0) {
  134. libusb_cancel_transfer(img_save); //异步取消之前提交传输
  135. printf("1");
  136. }
  137. r = libusb_submit_transfer(img_B_upload); //提交一个传输并立即返回
  138. if (r < 0) {
  139. libusb_cancel_transfer(img_B_upload); //异步取消之前提交传输
  140. printf("1");
  141. }
  142. r = libusb_submit_transfer(img_B); //提交一个传输并立即返回
  143. if (r < 0) {
  144. libusb_cancel_transfer(img_B); //异步取消之前提交传输
  145. printf("1");
  146. }
  147. r = libusb_submit_transfer(img_G_upload); //提交一个传输并立即返回
  148. if (r < 0) {
  149. libusb_cancel_transfer(img_G_upload); //异步取消之前提交传输
  150. printf("1");
  151. }
  152. r = libusb_submit_transfer(img_G); //提交一个传输并立即返回
  153. if (r < 0) {
  154. libusb_cancel_transfer(img_G); //异步取消之前提交传输
  155. printf("1");
  156. }
  157. r = libusb_submit_transfer(img_R_upload); //提交一个传输并立即返回
  158. if (r < 0) {
  159. libusb_cancel_transfer(img_R_upload); //异步取消之前提交传输
  160. printf("1");
  161. }
  162. r = libusb_submit_transfer(img_R); //提交一个传输并立即返回
  163. if (r < 0) {
  164. libusb_cancel_transfer(img_R); //异步取消之前提交传输
  165. printf("1");
  166. }
  167. return r;
  168. }
  169. static int alloc_transfers(void)
  170. {
  171. img_save = libusb_alloc_transfer(0); //0参数表明配置一个异步传输
  172. if (!img_save)
  173. return -ENOMEM;
  174. img_R = libusb_alloc_transfer(0); //0参数表明配置一个异步传输
  175. if (!img_R)
  176. return -ENOMEM;
  177. img_R_upload = libusb_alloc_transfer(0); //0参数表明配置一个异步传输
  178. if (!img_R_upload)
  179. return -ENOMEM;
  180. img_G = libusb_alloc_transfer(0); //0参数表明配置一个异步传输
  181. if (!img_G)
  182. return -ENOMEM;
  183. img_G_upload = libusb_alloc_transfer(0); //0参数表明配置一个异步传输
  184. if (!img_G_upload)
  185. return -ENOMEM;
  186. img_B = libusb_alloc_transfer(0); //0参数表明配置一个异步传输
  187. if (!img_B)
  188. return -ENOMEM;
  189. img_B_upload = libusb_alloc_transfer(0); //0参数表明配置一个异步传输
  190. if (!img_B_upload)
  191. return -ENOMEM;
  192. imgbuf_save[0] = (u_char)(SAVE_IMAGE);
  193. imgbuf_save[1] = 0x00;
  194. imgbuf_save[2] = 0x00;
  195. imgbuf_save[3] = 0x00;
  196. imgbuf_save[4] = (uchar)((0xff00 & 0x00f0)>>8);
  197. imgbuf_save[5] = (uchar)(0x00ff & 0x00f0);
  198. imgbuf_save[6] = 0x00;
  199. imgbuf_save[7] = (u_char)(SAVE_IMAGE_VAL);
  200. libusb_fill_bulk_transfer(img_save, devh, EP_OUT, imgbuf_save,
  201. sizeof(imgbuf_save), save_img, NULL, 5000); //该辅助函数来填充所需的libusb_transfer批量传输字段
  202. imgbuf_upload[0] = (u_char)UPLOAD_IMAGE;
  203. imgbuf_upload[1] = 0x00;
  204. imgbuf_upload[2] = 0x00;
  205. imgbuf_upload[3] = 0x00;
  206. imgbuf_upload[4] = (uchar)((0xff00 & 0x00f0)>>8);
  207. imgbuf_upload[5] = (uchar)(0x00ff & 0x00f0);
  208. imgbuf_upload[6] = 0x00;
  209. imgbuf_upload[7] = (u_char)UPLOAD_B_VAL;
  210. libusb_fill_bulk_transfer(img_B_upload, devh, EP_OUT, imgbuf_upload,
  211. sizeof(imgbuf_upload), upload_img_B, NULL, 5000); //该辅助函数来填充所需的libusb_transfer批量传输字段
  212. libusb_fill_bulk_transfer(img_B, devh, EP_IN, imgbuf_B,
  213. sizeof(imgbuf_B), upload_img_B_over, NULL, 5000); //该辅助函数来填充所需的libusb_transfer批量传输字段
  214. imgbuf_upload[0] = (u_char)UPLOAD_IMAGE;
  215. imgbuf_upload[1] = 0x00;
  216. imgbuf_upload[2] = 0x00;
  217. imgbuf_upload[3] = 0x00;
  218. imgbuf_upload[4] = (uchar)((0xff00 & 0x00f0)>>8);
  219. imgbuf_upload[5] = (uchar)(0x00ff & 0x00f0);
  220. imgbuf_upload[6] = 0x00;
  221. imgbuf_upload[7] = (u_char)UPLOAD_G_VAL;
  222. libusb_fill_bulk_transfer(img_G_upload, devh, EP_OUT, imgbuf_upload,
  223. sizeof(imgbuf_upload), upload_img_G, NULL, 5000); //该辅助函数来填充所需的libusb_transfer批量传输字段
  224. libusb_fill_bulk_transfer(img_G, devh, EP_IN, imgbuf_G,
  225. sizeof(imgbuf_G), upload_img_G_over, NULL, 5000); //该辅助函数来填充所需的libusb_transfer批量传输字段
  226. imgbuf_upload[0] = (u_char)UPLOAD_IMAGE;
  227. imgbuf_upload[1] = 0x00;
  228. imgbuf_upload[2] = 0x00;
  229. imgbuf_upload[3] = 0x00;
  230. imgbuf_upload[4] = (uchar)((0xff00 & 0x00f0)>>8);
  231. imgbuf_upload[5] = (uchar)(0x00ff & 0x00f0);
  232. imgbuf_upload[6] = 0x00;
  233. imgbuf_upload[7] = (u_char)UPLOAD_R_VAL;
  234. libusb_fill_bulk_transfer(img_R_upload, devh, EP_OUT, imgbuf_upload,
  235. sizeof(imgbuf_upload), upload_img_R, NULL, 5000); //该辅助函数来填充所需的libusb_transfer批量传输字段
  236. libusb_fill_bulk_transfer(img_R, devh, EP_IN, imgbuf_R,
  237. sizeof(imgbuf_R), cb_img, NULL, 5000); //该辅助函数来填充所需的libusb_transfer批量传输字段
  238. return 0;
  239. }
  240. int main(void)
  241. {
  242. libusb_init(NULL); //初始libusb库
  243. int r = find_dpfp_device();
  244. if(r!=0)
  245. {
  246. printf("%s\n", "not found dev" );
  247. return 0;
  248. }
  249. r = libusb_claim_interface(devh, 0); //声明设备接口
  250. if (r < 0) {
  251. fprintf(stderr, "usb_claim_interface error %d %s\n", r, strerror(-r));
  252. goto out;
  253. }
  254. std::cout << "claimed interface" << std::endl;
  255. r = pthread_create(&poll_thread, NULL, poll_thread_main, NULL); //子线程poll_thread_main用来处理USB事件
  256. if (r)
  257. goto out;
  258. r = alloc_transfers(); //配置一个异步bulk传输和一个中断传输,先alloc然后fill_XX_transfer
  259. if (r < 0) {
  260. request_exit(1);
  261. pthread_join(poll_thread, NULL); //函数pthread_join用来等待一个线程的结束
  262. goto out;
  263. }
  264. r = submit_trans(); //submit一个传输
  265. if (r < 0) {
  266. request_exit(1);
  267. pthread_join(poll_thread, NULL); //失败等待线程结束
  268. goto out;
  269. }
  270. while (!do_exit)
  271. sem_wait(&exit_sem); //等待退出信号量
  272. printf("shutting down...\n");
  273. pthread_join(poll_thread, NULL);
  274. out_release:
  275. libusb_release_interface(devh, 0);
  276. out:
  277. libusb_close(devh);
  278. libusb_exit(NULL);
  279. sem_destroy(&exit_sem);
  280. return r >= 0 ? r : -r;
  281. }


声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/711486
推荐阅读
相关标签
  

闽ICP备14008679号