dm_hmi_test.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. /*
  2. * Copyright (c) 2006-2021, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2023-02-25 GuEe-GUI the first version
  9. */
  10. #include <rtthread.h>
  11. #include <rtdevice.h>
  12. #include <cpuport.h>
  13. #include <drivers/misc.h>
  14. #if defined(RT_USING_GRAPHIC) && defined(RT_USING_INPUT)
  15. #define CURSOR_WIDTH 64
  16. #define CURSOR_HEIGHT 64
  17. struct hmi_info
  18. {
  19. struct rt_device *gdev;
  20. struct rt_device *idev;
  21. struct rt_device_graphic_info info;
  22. struct rt_device_notify event_notify;
  23. struct rt_input_handler handler;
  24. rt_bool_t event;
  25. rt_bool_t vsync;
  26. rt_bool_t keydown;
  27. rt_uint32_t x, y;
  28. rt_uint32_t dx, dy;
  29. rt_uint32_t bytes_per_pixel;
  30. rt_ubase_t line[2];
  31. rt_ubase_t colors[4];
  32. void *backend_framebuffer;
  33. };
  34. static rt_bool_t hmi_working;
  35. static struct rt_input_device *to_input_device(struct rt_device *idev)
  36. {
  37. return rt_container_of(idev, struct rt_input_device, parent);
  38. }
  39. static rt_ubase_t to_color(rt_uint8_t color255, rt_ubase_t color_max)
  40. {
  41. return (rt_ubase_t)color255 * color_max / 255;
  42. }
  43. static void hmi_reset(struct hmi_info *hmi)
  44. {
  45. void *cursor;
  46. rt_ubase_t none_alpha;
  47. rt_ubase_t red_off, green_off, blue_off, alpha_off;
  48. rt_ubase_t red_mask, green_mask, blue_mask, alpha_mask;
  49. struct fb_var_screeninfo var;
  50. if (hmi->backend_framebuffer)
  51. {
  52. rt_free(hmi->backend_framebuffer);
  53. }
  54. rt_device_control(hmi->gdev, FBIOGET_VSCREENINFO, &var);
  55. rt_device_control(hmi->gdev, RTGRAPHIC_CTRL_GET_INFO, &hmi->info);
  56. hmi->backend_framebuffer = rt_malloc(hmi->info.smem_len);
  57. hmi->bytes_per_pixel = hmi->info.bits_per_pixel / 8;
  58. red_off = var.red.offset;
  59. red_mask = RT_GENMASK(var.red.length - 1, 0);
  60. green_off = var.green.offset;
  61. green_mask = RT_GENMASK(var.green.length - 1, 0);
  62. blue_off = var.blue.offset;
  63. blue_mask = RT_GENMASK(var.blue.length - 1, 0);
  64. if (var.transp.length)
  65. {
  66. alpha_off = var.transp.offset;
  67. alpha_mask = RT_GENMASK(var.transp.length - 1, 0);
  68. }
  69. else
  70. {
  71. alpha_off = 0;
  72. alpha_mask = 0;
  73. }
  74. if ((cursor = rt_malloc(CURSOR_WIDTH * CURSOR_HEIGHT * hmi->bytes_per_pixel)))
  75. {
  76. rt_uint8_t *stream = cursor;
  77. rt_ubase_t color = ((to_color(0x82, red_mask)) << red_off) |
  78. (to_color(0x50, green_mask) << green_off) |
  79. (to_color(0xdf, blue_mask) << blue_off) |
  80. (to_color(0xcc, alpha_mask) << alpha_off);
  81. for (int y = 0; y < CURSOR_HEIGHT; ++y)
  82. {
  83. for (int x = 0; x < CURSOR_WIDTH; ++x)
  84. {
  85. rt_memcpy(stream, &color, hmi->bytes_per_pixel);
  86. stream += hmi->bytes_per_pixel;
  87. }
  88. }
  89. rt_device_control(hmi->gdev, RT_DEVICE_CTRL_CURSOR_SET_TYPE, cursor);
  90. rt_free(cursor);
  91. }
  92. none_alpha = alpha_mask << alpha_off;
  93. hmi->line[0] = ~0UL;
  94. hmi->line[1] = none_alpha;
  95. hmi->colors[0] = ((to_color(0xff, red_mask)) << red_off) |
  96. (to_color(0x4b, green_mask) << green_off) |
  97. (to_color(0x00, blue_mask) << blue_off) | none_alpha;
  98. hmi->colors[1] = ((to_color(0x7f, red_mask)) << red_off) |
  99. (to_color(0xdb, green_mask) << green_off) |
  100. (to_color(0x3b, blue_mask) << blue_off) | none_alpha;
  101. hmi->colors[2] = ((to_color(0x00, red_mask)) << red_off) |
  102. (to_color(0xa4, green_mask) << green_off) |
  103. (to_color(0xef, blue_mask) << blue_off) | none_alpha;
  104. hmi->colors[3] = ((to_color(0xff, red_mask)) << red_off) |
  105. (to_color(0xb8, green_mask) << green_off) |
  106. (to_color(0x1c, blue_mask) << blue_off) | none_alpha;
  107. hmi->event = RT_FALSE;
  108. }
  109. static void hmi_graphic_notify(rt_device_t dev)
  110. {
  111. struct hmi_info *hmi = (void *)dev;
  112. hmi->event = RT_TRUE;
  113. }
  114. static rt_bool_t hmi_input_callback(struct rt_input_handler *handler,
  115. struct rt_input_event *ev)
  116. {
  117. struct hmi_info *hmi = handler->priv;
  118. if (ev->type == EV_ABS)
  119. {
  120. if (ev->code == 0)
  121. {
  122. hmi->dx = (ev->value * hmi->info.width) /
  123. (handler->idev->absinfo->maximum - handler->idev->absinfo->minimum);
  124. }
  125. else if (ev->code == 1)
  126. {
  127. hmi->dy = (ev->value * hmi->info.height) /
  128. (handler->idev->absinfo->maximum - handler->idev->absinfo->minimum);
  129. }
  130. }
  131. else if (ev->type == EV_KEY)
  132. {
  133. if (ev->code == BTN_LEFT)
  134. {
  135. if (hmi->keydown && ev->value == 0)
  136. {
  137. /* Swap lines color */
  138. hmi->line[0] ^= hmi->line[1];
  139. hmi->line[1] ^= hmi->line[0];
  140. hmi->line[0] ^= hmi->line[1];
  141. hmi->keydown = RT_FALSE;
  142. hmi->vsync = RT_FALSE;
  143. }
  144. else
  145. {
  146. hmi->keydown = RT_TRUE;
  147. }
  148. }
  149. }
  150. else if (ev->type == EV_SYN)
  151. {
  152. hmi->vsync = RT_FALSE;
  153. }
  154. return RT_TRUE;
  155. }
  156. static void hmi_loop(void *param)
  157. {
  158. struct hmi_info *hmi = param;
  159. struct rt_device_rect_info rect;
  160. struct rt_device_graphic_ops *gops;
  161. /* Graphic device event */
  162. hmi->event_notify.notify = &hmi_graphic_notify;
  163. hmi->event_notify.dev = (void *)hmi;
  164. rt_device_control(hmi->gdev, RT_DEVICE_CTRL_NOTIFY_SET, &hmi->event_notify);
  165. /* Input device event */
  166. hmi->handler.idev = to_input_device(hmi->idev);
  167. hmi->handler.identify = RT_NULL;
  168. hmi->handler.callback = &hmi_input_callback;
  169. hmi->handler.priv = hmi;
  170. rt_input_add_handler(&hmi->handler);
  171. hmi->backend_framebuffer = RT_NULL;
  172. hmi_reset(hmi);
  173. hmi->dx = hmi->info.width >> 1;
  174. hmi->dy = hmi->info.height >> 1;
  175. rect.x = 0;
  176. rect.y = 0;
  177. gops = rt_graphix_ops(hmi->gdev);
  178. rt_device_control(hmi->gdev, RTGRAPHIC_CTRL_POWERON, RT_NULL);
  179. while (hmi_working)
  180. {
  181. rt_ubase_t pos;
  182. /* Wait graphic change */
  183. if (hmi->event)
  184. {
  185. hmi_reset(hmi);
  186. }
  187. hmi->x = hmi->dx;
  188. hmi->y = hmi->dy;
  189. rect.width = hmi->info.width;
  190. rect.height = hmi->info.height;
  191. pos = RTGRAPHIC_PIXEL_POSITION(hmi->x, hmi->y);
  192. for (int i = 0; i < RT_ARRAY_SIZE(hmi->colors); ++i)
  193. {
  194. rt_uint32_t x1, y1, x2, y2;
  195. void *fb = hmi->backend_framebuffer ? : hmi->info.framebuffer;
  196. switch (i)
  197. {
  198. case 0:
  199. x1 = 0;
  200. y1 = 0;
  201. x2 = hmi->x;
  202. y2 = hmi->y;
  203. break;
  204. case 1:
  205. x1 = hmi->x;
  206. y1 = 0;
  207. x2 = hmi->info.width;
  208. y2 = hmi->y;
  209. break;
  210. case 2:
  211. x1 = 0;
  212. y1 = hmi->y;
  213. x2 = hmi->x;
  214. y2 = hmi->info.height;
  215. break;
  216. case 3:
  217. x1 = hmi->x;
  218. y1 = hmi->y;
  219. x2 = hmi->info.width;
  220. y2 = hmi->info.height;
  221. break;
  222. }
  223. fb += x1 * hmi->bytes_per_pixel + y1 * hmi->info.pitch;
  224. for (int y = y1; y < y2; ++y)
  225. {
  226. void *fb_entry = fb;
  227. for (int x = x1; x < x2; ++x)
  228. {
  229. rt_memcpy(fb, &hmi->colors[i], hmi->bytes_per_pixel);
  230. fb += hmi->bytes_per_pixel;
  231. }
  232. fb = fb_entry + hmi->info.pitch;
  233. }
  234. }
  235. if (hmi->backend_framebuffer)
  236. {
  237. rt_memcpy(hmi->info.framebuffer, hmi->backend_framebuffer, hmi->info.smem_len);
  238. }
  239. gops->draw_hline((void *)&hmi->line[0], 0, rect.width, hmi->y);
  240. gops->draw_vline((void *)&hmi->line[1], hmi->x, 0, rect.height);
  241. rt_device_control(hmi->gdev, RTGRAPHIC_CTRL_RECT_UPDATE, &rect);
  242. rt_device_control(hmi->gdev, RT_DEVICE_CTRL_CURSOR_SET_POSITION, (void *)pos);
  243. /* Next position */
  244. hmi->vsync = RT_TRUE;
  245. rt_hw_wmb();
  246. while (hmi_working && hmi->vsync)
  247. {
  248. rt_thread_mdelay(1);
  249. }
  250. }
  251. rt_device_control(hmi->gdev, RTGRAPHIC_CTRL_POWEROFF, RT_NULL);
  252. rt_memset(&hmi->event_notify, 0, sizeof(hmi->event_notify));
  253. rt_device_control(hmi->gdev, RT_DEVICE_CTRL_NOTIFY_SET, &hmi->event_notify);
  254. rt_input_del_handler(&hmi->handler);
  255. rt_device_close(hmi->gdev);
  256. rt_device_close(hmi->idev);
  257. if (hmi->backend_framebuffer)
  258. {
  259. rt_free(hmi->backend_framebuffer);
  260. }
  261. rt_free(hmi);
  262. rt_thread_delete(rt_thread_self());
  263. }
  264. rt_err_t hmi_start(const char *gdev, const char *idev)
  265. {
  266. rt_err_t err;
  267. struct hmi_info *hmi;
  268. struct rt_thread *loop;
  269. if (hmi_working)
  270. {
  271. rt_kprintf("HMI is running\n");
  272. return -RT_EBUSY;
  273. }
  274. hmi = rt_malloc(sizeof(*hmi));
  275. if (!hmi)
  276. {
  277. return -RT_ENOMEM;
  278. }
  279. hmi->gdev = rt_device_find(gdev);
  280. hmi->idev = rt_device_find(idev);
  281. if (!hmi->gdev || !hmi->idev)
  282. {
  283. rt_free(hmi);
  284. return -RT_EINVAL;
  285. }
  286. if (!rt_bitmap_test_bit(to_input_device(hmi->idev)->cap, EV_ABS))
  287. {
  288. rt_kprintf("%s is not a ABS input\n", idev);
  289. rt_free(hmi);
  290. return -RT_EINVAL;
  291. }
  292. if ((err = rt_device_open(hmi->gdev, 0)))
  293. {
  294. rt_free(hmi);
  295. return err;
  296. }
  297. if ((err = rt_device_open(hmi->idev, 0)))
  298. {
  299. rt_device_close(hmi->gdev);
  300. rt_free(hmi);
  301. return err;
  302. }
  303. loop = rt_thread_create("HMI", hmi_loop, hmi,
  304. DM_THREAD_STACK_SIZE,
  305. RT_THREAD_PRIORITY_MAX / 3,
  306. rt_tick_from_millisecond(RT_GRAPHIC_UPDATE_MS));
  307. if (!loop)
  308. {
  309. rt_device_close(hmi->gdev);
  310. rt_device_close(hmi->idev);
  311. rt_free(hmi);
  312. return -RT_ENOMEM;
  313. }
  314. hmi_working = RT_TRUE;
  315. rt_thread_startup(loop);
  316. return RT_EOK;
  317. }
  318. rt_err_t hmi_stop(void)
  319. {
  320. hmi_working = RT_FALSE;
  321. return RT_EOK;
  322. }
  323. #ifdef RT_USING_FINSH
  324. static int _hmi_start(int argc, char**argv)
  325. {
  326. const char *gdev = "fb0", *idev = "input0";
  327. if (argc == 3)
  328. {
  329. gdev = argv[1];
  330. idev = argv[2];
  331. }
  332. return (int)hmi_start(gdev, idev);
  333. }
  334. MSH_CMD_EXPORT_ALIAS(_hmi_start, hmi_start, e.g: hmi_start("fb0", "input0"));
  335. static int _hmi_stop(void)
  336. {
  337. return (int)hmi_stop();
  338. }
  339. MSH_CMD_EXPORT_ALIAS(_hmi_stop, hmi_stop, e.g: hmi_exit());
  340. #endif /* RT_USING_FINSH */
  341. #endif /* RT_USING_GRAPHIC && RT_USING_INPUT */