app_usbd_hid_mouse.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690
  1. /**
  2. * Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
  3. *
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without modification,
  7. * are permitted provided that the following conditions are met:
  8. *
  9. * 1. Redistributions of source code must retain the above copyright notice, this
  10. * list of conditions and the following disclaimer.
  11. *
  12. * 2. Redistributions in binary form, except as embedded into a Nordic
  13. * Semiconductor ASA integrated circuit in a product or a software update for
  14. * such product, must reproduce the above copyright notice, this list of
  15. * conditions and the following disclaimer in the documentation and/or other
  16. * materials provided with the distribution.
  17. *
  18. * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
  19. * contributors may be used to endorse or promote products derived from this
  20. * software without specific prior written permission.
  21. *
  22. * 4. This software, with or without modification, must only be used with a
  23. * Nordic Semiconductor ASA integrated circuit.
  24. *
  25. * 5. Any software provided in binary form under this license must not be reverse
  26. * engineered, decompiled, modified and/or disassembled.
  27. *
  28. * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
  29. * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  30. * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
  31. * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
  32. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  33. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
  34. * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  35. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  36. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  37. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  38. *
  39. */
  40. #include "sdk_common.h"
  41. #if NRF_MODULE_ENABLED(APP_USBD_HID_MOUSE)
  42. #include <string.h>
  43. #include "app_usbd_hid_mouse.h"
  44. #include "app_util_platform.h"
  45. /**
  46. * @defgroup app_usbd_hid_mouse_internal USBD HID Mouse internals
  47. * @{
  48. * @ingroup app_usbd_hid_mouse
  49. * @internal
  50. */
  51. /**
  52. * @brief Auxiliary function to access HID mouse context data.
  53. *
  54. * @param[in] p_inst class instance data.
  55. *
  56. * @return HID mouse instance data context.
  57. */
  58. static inline app_usbd_hid_mouse_ctx_t * hid_mouse_ctx_get(app_usbd_hid_mouse_t const * p_mouse)
  59. {
  60. ASSERT(p_mouse != NULL);
  61. ASSERT(p_mouse->specific.p_data != NULL);
  62. return &p_mouse->specific.p_data->ctx;
  63. }
  64. /**
  65. * @brief Auxiliary function to access HID mouse instance data.
  66. *
  67. * @param[in] p_inst class instance data.
  68. *
  69. * @return HID mouse instance.
  70. */
  71. static inline app_usbd_hid_mouse_t const * hid_mouse_get(app_usbd_class_inst_t const * p_inst)
  72. {
  73. ASSERT(p_inst != NULL);
  74. return (app_usbd_hid_mouse_t const *)p_inst;
  75. }
  76. /**
  77. * @brief Returns mouse report buffer handle.
  78. *
  79. * @param[in] p_kbd HID keyboard instance.
  80. *
  81. * @return HID report buffer.
  82. */
  83. static inline
  84. app_usbd_hid_report_buffer_t const * hid_mouse_rep_buffer_get(app_usbd_hid_mouse_t const * p_mouse)
  85. {
  86. ASSERT(p_mouse != NULL);
  87. app_usbd_hid_inst_t const * p_hinst = &p_mouse->specific.inst.hid_inst;
  88. app_usbd_hid_mouse_ctx_t * p_mouse_ctx = hid_mouse_ctx_get(p_mouse);
  89. app_usbd_hid_report_buffer_t * p_rep_buff = app_usbd_hid_rep_buff_in_get(p_hinst);
  90. p_rep_buff->p_buff = p_mouse_ctx->report_buff;
  91. p_rep_buff->size = sizeof(p_mouse_ctx->report_buff);
  92. /*Mouse has only one report input report buffer */
  93. return app_usbd_hid_rep_buff_in_get(p_hinst);
  94. }
  95. /**@brief Auxiliary function to get report value from internal accumulated value.
  96. *
  97. * @param[in] acc Accumulated XY axis or scroll.
  98. *
  99. * @return Offset value that could be written directly to report buffer.
  100. */
  101. static inline int8_t hid_mouse_axis_acc_get(int16_t acc)
  102. {
  103. if (acc > INT8_MAX)
  104. {
  105. return INT8_MAX;
  106. }
  107. if (acc < INT8_MIN)
  108. {
  109. return INT8_MIN;
  110. }
  111. return acc;
  112. }
  113. /**@brief Auxiliary function to prepare report transfer buffer to next transfer.
  114. *
  115. * @param[in] p_mouse_ctx Mouse internal context.
  116. *
  117. * @retval true Next transfer is required.
  118. * @retval false Next transfer is not required.
  119. */
  120. static inline bool hid_mouse_transfer_next(app_usbd_hid_mouse_t const * p_mouse)
  121. {
  122. app_usbd_hid_mouse_ctx_t * p_mouse_ctx = hid_mouse_ctx_get(p_mouse);
  123. app_usbd_hid_report_buffer_t const * p_rep_buffer = hid_mouse_rep_buffer_get(p_mouse);
  124. uint8_t * p_buff = p_rep_buffer->p_buff;
  125. /*Save last buttons state*/
  126. uint8_t last_button_state = p_buff[0];
  127. /*Button state*/
  128. p_buff[0] = p_mouse_ctx->button_state;
  129. /*Axis X*/
  130. int8_t val_x = hid_mouse_axis_acc_get(p_mouse_ctx->acc_x_axis);
  131. p_mouse_ctx->acc_x_axis -= val_x;
  132. p_buff[1] = val_x;
  133. /*Axis Y*/
  134. int8_t val_y = hid_mouse_axis_acc_get(p_mouse_ctx->acc_y_axis);
  135. p_mouse_ctx->acc_y_axis -= val_y;
  136. p_buff[2] = val_y;
  137. /*Scroll*/
  138. int8_t val_scroll = hid_mouse_axis_acc_get(p_mouse_ctx->acc_scroll);
  139. p_mouse_ctx->acc_scroll -= val_scroll;
  140. p_buff[3] = val_scroll;
  141. if (val_x || val_y || val_scroll)
  142. {
  143. /*New transfer is required if any of mouse relative position is not zero*/
  144. return true;
  145. }
  146. if (last_button_state != p_buff[0])
  147. {
  148. /*New transfer is required if button state has changed*/
  149. return true;
  150. }
  151. return false;
  152. }
  153. /**
  154. * @brief Triggers IN endpoint transfer.
  155. *
  156. * @param[in] p_mouse HID mouse instance.
  157. *
  158. * @return Standard error code.
  159. */
  160. static inline ret_code_t hid_mouse_transfer_set(app_usbd_hid_mouse_t const * p_mouse)
  161. {
  162. app_usbd_class_inst_t const * p_inst = (app_usbd_class_inst_t const *)p_mouse;
  163. app_usbd_hid_mouse_ctx_t * p_mouse_ctx = hid_mouse_ctx_get(p_mouse);
  164. nrf_drv_usbd_ep_t ep_addr = app_usbd_hid_epin_addr_get(p_inst);
  165. app_usbd_hid_state_flag_clr(&p_mouse_ctx->hid_ctx, APP_USBD_HID_STATE_FLAG_TRANS_IN_PROGRESS);
  166. if (!hid_mouse_transfer_next(p_mouse))
  167. {
  168. /* Transfer buffer hasn't changed since last transfer. No need to setup
  169. * next transfer.
  170. * */
  171. return NRF_SUCCESS;
  172. }
  173. app_usbd_hid_report_buffer_t const * p_rep_buffer = hid_mouse_rep_buffer_get(p_mouse);
  174. NRF_DRV_USBD_TRANSFER_IN(transfer, p_rep_buffer->p_buff, p_rep_buffer->size);
  175. ret_code_t ret;
  176. CRITICAL_REGION_ENTER();
  177. ret = app_usbd_ep_transfer(ep_addr, &transfer);
  178. if (ret == NRF_SUCCESS)
  179. {
  180. app_usbd_hid_state_flag_set(&p_mouse_ctx->hid_ctx,
  181. APP_USBD_HID_STATE_FLAG_TRANS_IN_PROGRESS);
  182. }
  183. CRITICAL_REGION_EXIT();
  184. return ret;
  185. }
  186. /**
  187. * @brief Checks if adding would cause 16 bit signed integer overflow.
  188. *
  189. * @param[in] acc Signed 16 bit accumulator to test.
  190. * @param[in] value Value to add to accumulator.
  191. *
  192. * @retval true Overflow detected.
  193. * @retval false No overflow detected.
  194. */
  195. static inline bool hid_mouse_acc_overflow_check(int16_t acc, int8_t val)
  196. {
  197. if (((int32_t)acc + val) > INT16_MAX)
  198. {
  199. return true;
  200. }
  201. if (((int32_t)acc + val) < INT16_MIN)
  202. {
  203. return true;
  204. }
  205. return false;
  206. }
  207. ret_code_t app_usbd_hid_mouse_x_move(app_usbd_hid_mouse_t const * p_mouse, int8_t offset)
  208. {
  209. app_usbd_hid_mouse_ctx_t * p_mouse_ctx = hid_mouse_ctx_get(p_mouse);
  210. if (!app_usbd_hid_state_valid(&p_mouse_ctx->hid_ctx))
  211. {
  212. return NRF_ERROR_INVALID_STATE;
  213. }
  214. if (offset == 0)
  215. {
  216. /*No position change*/
  217. return NRF_SUCCESS;
  218. }
  219. if (hid_mouse_acc_overflow_check(p_mouse_ctx->acc_y_axis, offset))
  220. {
  221. /*Overflow detected*/
  222. return NRF_ERROR_BUSY;
  223. }
  224. app_usbd_hid_access_lock(&p_mouse_ctx->hid_ctx);
  225. p_mouse_ctx->acc_x_axis += offset;
  226. app_usbd_hid_access_unlock(&p_mouse_ctx->hid_ctx);
  227. if (app_usbd_hid_trans_required(&p_mouse_ctx->hid_ctx))
  228. {
  229. /*New transfer need to be triggered*/
  230. return hid_mouse_transfer_set(p_mouse);
  231. }
  232. return NRF_SUCCESS;
  233. }
  234. ret_code_t app_usbd_hid_mouse_y_move(app_usbd_hid_mouse_t const * p_mouse, int8_t offset)
  235. {
  236. app_usbd_hid_mouse_ctx_t * p_mouse_ctx = hid_mouse_ctx_get(p_mouse);
  237. if (!app_usbd_hid_state_valid(&p_mouse_ctx->hid_ctx))
  238. {
  239. return NRF_ERROR_INVALID_STATE;
  240. }
  241. if (offset == 0)
  242. {
  243. /*No position change*/
  244. return NRF_SUCCESS;
  245. }
  246. if (hid_mouse_acc_overflow_check(p_mouse_ctx->acc_y_axis, offset))
  247. {
  248. /*Overflow detected*/
  249. return NRF_ERROR_BUSY;
  250. }
  251. app_usbd_hid_access_lock(&p_mouse_ctx->hid_ctx);
  252. p_mouse_ctx->acc_y_axis += offset;
  253. app_usbd_hid_access_unlock(&p_mouse_ctx->hid_ctx);
  254. if (app_usbd_hid_trans_required(&p_mouse_ctx->hid_ctx))
  255. {
  256. /*New transfer need to be triggered*/
  257. return hid_mouse_transfer_set(p_mouse);
  258. }
  259. return NRF_SUCCESS;
  260. }
  261. ret_code_t app_usbd_hid_mouse_scroll_move(app_usbd_hid_mouse_t const * p_mouse, int8_t offset)
  262. {
  263. app_usbd_hid_mouse_ctx_t * p_mouse_ctx = hid_mouse_ctx_get(p_mouse);
  264. if (!app_usbd_hid_state_valid(&p_mouse_ctx->hid_ctx))
  265. {
  266. return NRF_ERROR_INVALID_STATE;
  267. }
  268. if (offset == 0)
  269. {
  270. /*No position change*/
  271. return NRF_SUCCESS;
  272. }
  273. if (hid_mouse_acc_overflow_check(p_mouse_ctx->acc_scroll, offset))
  274. {
  275. /*Overflow detected*/
  276. return NRF_ERROR_BUSY;
  277. }
  278. app_usbd_hid_access_lock(&p_mouse_ctx->hid_ctx);
  279. p_mouse_ctx->acc_scroll += offset;
  280. app_usbd_hid_access_unlock(&p_mouse_ctx->hid_ctx);
  281. if (app_usbd_hid_trans_required(&p_mouse_ctx->hid_ctx))
  282. {
  283. /*New transfer need to be triggered*/
  284. return hid_mouse_transfer_set(p_mouse);
  285. }
  286. return NRF_SUCCESS;
  287. }
  288. ret_code_t app_usbd_hid_mouse_button_state(app_usbd_hid_mouse_t const * p_mouse,
  289. uint8_t button_id,
  290. bool state)
  291. {
  292. ASSERT(button_id < 8);
  293. app_usbd_hid_mouse_ctx_t * p_mouse_ctx = hid_mouse_ctx_get(p_mouse);
  294. if (button_id >= p_mouse->specific.inst.button_count)
  295. {
  296. return NRF_ERROR_INVALID_PARAM;
  297. }
  298. if (!app_usbd_hid_state_valid(&p_mouse_ctx->hid_ctx))
  299. {
  300. return NRF_ERROR_INVALID_STATE;
  301. }
  302. if (IS_SET(p_mouse_ctx->button_state, button_id) == (state ? 1 : 0))
  303. {
  304. return NRF_SUCCESS;
  305. }
  306. app_usbd_hid_access_lock(&p_mouse_ctx->hid_ctx);
  307. if (state)
  308. {
  309. SET_BIT(p_mouse_ctx->button_state, button_id);
  310. }
  311. else
  312. {
  313. CLR_BIT(p_mouse_ctx->button_state, button_id);
  314. }
  315. app_usbd_hid_access_unlock(&p_mouse_ctx->hid_ctx);
  316. if (app_usbd_hid_trans_required(&p_mouse_ctx->hid_ctx))
  317. {
  318. /*New transfer need to be triggered*/
  319. return hid_mouse_transfer_set(p_mouse);
  320. }
  321. return NRF_SUCCESS;
  322. }
  323. /**
  324. * @brief @ref app_usbd_hid_interface_t::on_get_report
  325. */
  326. static ret_code_t hid_mouse_on_get_report(app_usbd_class_inst_t const * p_inst,
  327. app_usbd_setup_evt_t const * p_setup_ev)
  328. {
  329. if (p_setup_ev->setup.wValue.hb != APP_USBD_HID_REPORT_TYPE_INPUT)
  330. {
  331. return NRF_ERROR_NOT_SUPPORTED;
  332. }
  333. app_usbd_hid_mouse_t const * p_mouse = hid_mouse_get(p_inst);
  334. app_usbd_hid_report_buffer_t const * p_rep_buffer = hid_mouse_rep_buffer_get(p_mouse);
  335. return app_usbd_core_setup_rsp(&(p_setup_ev->setup), p_rep_buffer->p_buff, p_rep_buffer->size);
  336. }
  337. /**
  338. * @brief @ref app_usbd_hid_interface_t::on_set_report
  339. */
  340. static ret_code_t hid_mouse_on_set_report(app_usbd_class_inst_t const * p_inst,
  341. app_usbd_setup_evt_t const * p_setup_ev)
  342. {
  343. return NRF_ERROR_NOT_SUPPORTED;
  344. }
  345. /**
  346. * @brief @ref app_usbd_hid_interface_t::ep_transfer_set
  347. */
  348. static ret_code_t hid_mouse_ep_transfer_in(app_usbd_class_inst_t const * p_inst)
  349. {
  350. return hid_mouse_transfer_set((app_usbd_hid_mouse_t const *)p_inst);
  351. }
  352. /**
  353. * @brief @ref app_usbd_class_interface_t::event_handler
  354. */
  355. static ret_code_t hid_mouse_event_handler(app_usbd_class_inst_t const * p_inst,
  356. app_usbd_complex_evt_t const * p_event)
  357. {
  358. ASSERT(p_inst != NULL);
  359. ASSERT(p_event != NULL);
  360. app_usbd_hid_mouse_t const * p_mouse = hid_mouse_get(p_inst);
  361. app_usbd_hid_inst_t const * p_hinst = &p_mouse->specific.inst.hid_inst;
  362. app_usbd_hid_mouse_ctx_t * p_mouse_ctx = hid_mouse_ctx_get(p_mouse);
  363. app_usbd_hid_ctx_t * p_hid_ctx = &p_mouse_ctx->hid_ctx;
  364. ret_code_t ret = NRF_SUCCESS;
  365. switch (p_event->app_evt.type)
  366. {
  367. default:
  368. ret = NRF_ERROR_NOT_SUPPORTED;
  369. break;
  370. }
  371. if (ret != NRF_ERROR_NOT_SUPPORTED)
  372. {
  373. /* Event was processed by specific handler */
  374. return ret;
  375. }
  376. /*Try handle event by generic HID event handler*/
  377. return app_usbd_hid_event_handler(p_inst, p_hinst, p_hid_ctx, p_event);
  378. }
  379. ret_code_t hid_mouse_clear_buffer(app_usbd_class_inst_t const * p_inst)
  380. {
  381. ASSERT(p_inst != NULL);
  382. app_usbd_hid_mouse_t const * p_mouse = hid_mouse_get(p_inst);
  383. app_usbd_hid_mouse_ctx_t * p_mouse_ctx = hid_mouse_ctx_get(p_mouse);
  384. app_usbd_hid_report_buffer_t const * p_rep_buffer = hid_mouse_rep_buffer_get(p_mouse);
  385. memset(p_rep_buffer->p_buff, 0, p_rep_buffer->size);
  386. memset(p_mouse_ctx->report_buff, 0, p_rep_buffer->size);
  387. memset(&p_mouse_ctx->acc_x_axis, 0, sizeof(p_mouse_ctx->acc_x_axis));
  388. memset(&p_mouse_ctx->acc_y_axis, 0, sizeof(p_mouse_ctx->acc_y_axis));
  389. memset(&p_mouse_ctx->acc_scroll, 0, sizeof(p_mouse_ctx->acc_scroll));
  390. memset(&p_mouse_ctx->button_state, 0, sizeof(p_mouse_ctx->button_state));
  391. CRITICAL_REGION_ENTER();
  392. nrf_drv_usbd_ep_t ep_addr = app_usbd_hid_epin_addr_get(p_inst);
  393. ASSERT(!NRF_USBD_EPISO_CHECK(ep_addr));
  394. if (NRF_USBD_EPIN_CHECK(ep_addr))
  395. {
  396. nrf_drv_usbd_ep_abort(ep_addr);
  397. }
  398. app_usbd_hid_state_flag_clr(&p_mouse_ctx->hid_ctx, APP_USBD_HID_STATE_FLAG_TRANS_IN_PROGRESS);
  399. CRITICAL_REGION_EXIT();
  400. return NRF_SUCCESS;
  401. }
  402. static uint8_t hid_mouse_get_class_descriptors_count(app_usbd_class_inst_t const * p_inst)
  403. {
  404. app_usbd_hid_mouse_t const * p_mouse = hid_mouse_get(p_inst);
  405. app_usbd_hid_inst_t const * p_hinst = &p_mouse->specific.inst.hid_inst;
  406. return p_hinst->subclass_desc_count;
  407. }
  408. static app_usbd_descriptor_t hid_mouse_get_class_descriptors_type(
  409. app_usbd_class_inst_t const * p_inst,
  410. uint8_t desc_num)
  411. {
  412. app_usbd_hid_mouse_t const * p_mouse = hid_mouse_get(p_inst);
  413. app_usbd_hid_inst_t const * p_hinst = &p_mouse->specific.inst.hid_inst;
  414. return p_hinst->p_subclass_desc[desc_num]->type;
  415. }
  416. static size_t hid_mouse_get_class_descriptors_length(app_usbd_class_inst_t const * p_inst,
  417. uint8_t desc_num)
  418. {
  419. app_usbd_hid_mouse_t const * p_mouse = hid_mouse_get(p_inst);
  420. app_usbd_hid_inst_t const * p_hinst = &p_mouse->specific.inst.hid_inst;
  421. return p_hinst->p_subclass_desc[desc_num]->size;
  422. }
  423. static const uint8_t * hid_mouse_get_class_descriptors_data(app_usbd_class_inst_t const * p_inst,
  424. uint8_t desc_num,
  425. uint32_t cur_byte)
  426. {
  427. app_usbd_hid_mouse_t const * p_mouse = hid_mouse_get(p_inst);
  428. app_usbd_hid_inst_t const * p_hinst = &p_mouse->specific.inst.hid_inst;
  429. const uint8_t * p_byte = &p_hinst->p_subclass_desc[desc_num]->p_data[cur_byte];
  430. return p_byte;
  431. }
  432. static bool hid_mouse_feed_descriptors(app_usbd_class_descriptor_ctx_t * p_ctx,
  433. app_usbd_class_inst_t const * p_inst,
  434. uint8_t * p_buff,
  435. size_t max_size)
  436. {
  437. static uint8_t ifaces = 0;
  438. ifaces = app_usbd_class_iface_count_get(p_inst);
  439. app_usbd_hid_mouse_t const * p_mouse = hid_mouse_get(p_inst);
  440. APP_USBD_CLASS_DESCRIPTOR_BEGIN(p_ctx, p_buff, max_size);
  441. static uint8_t i = 0;
  442. for (i = 0; i < ifaces; i++)
  443. {
  444. /* INTERFACE DESCRIPTOR */
  445. APP_USBD_CLASS_DESCRIPTOR_WRITE(0x09); // bLength
  446. APP_USBD_CLASS_DESCRIPTOR_WRITE(APP_USBD_DESCRIPTOR_INTERFACE); // bDescriptorType = Interface
  447. static app_usbd_class_iface_conf_t const * p_cur_iface = NULL;
  448. p_cur_iface = app_usbd_class_iface_get(p_inst, i);
  449. APP_USBD_CLASS_DESCRIPTOR_WRITE(app_usbd_class_iface_number_get(p_cur_iface)); // bInterfaceNumber
  450. APP_USBD_CLASS_DESCRIPTOR_WRITE(0x00); // bAlternateSetting
  451. APP_USBD_CLASS_DESCRIPTOR_WRITE(app_usbd_class_iface_ep_count_get(p_cur_iface)); // bNumEndpoints
  452. APP_USBD_CLASS_DESCRIPTOR_WRITE(APP_USBD_HID_CLASS); // bInterfaceClass = HID
  453. APP_USBD_CLASS_DESCRIPTOR_WRITE(p_mouse->specific.inst.hid_inst.subclass_boot); // bInterfaceSubclass (Boot Interface)
  454. APP_USBD_CLASS_DESCRIPTOR_WRITE(p_mouse->specific.inst.hid_inst.protocol); // bInterfaceProtocol
  455. APP_USBD_CLASS_DESCRIPTOR_WRITE(0x00); // iInterface
  456. /* HID DESCRIPTOR */
  457. APP_USBD_CLASS_DESCRIPTOR_WRITE(0x09); // bLength
  458. APP_USBD_CLASS_DESCRIPTOR_WRITE(APP_USBD_HID_DESCRIPTOR_HID); // bDescriptorType = HID
  459. APP_USBD_CLASS_DESCRIPTOR_WRITE(LSB_16(APP_USBD_HID_BCD_VER)); // bcdHID LSB
  460. APP_USBD_CLASS_DESCRIPTOR_WRITE(MSB_16(APP_USBD_HID_BCD_VER)); // bcdHID MSB
  461. APP_USBD_CLASS_DESCRIPTOR_WRITE(APP_USBD_HID_COUNTRY_NOT_SUPPORTED); // bCountryCode
  462. APP_USBD_CLASS_DESCRIPTOR_WRITE(hid_mouse_get_class_descriptors_count(p_inst)); // bNumDescriptors
  463. static uint8_t class_desc_cnt = 0;
  464. class_desc_cnt = hid_mouse_get_class_descriptors_count(p_inst);
  465. static uint8_t j = 0;
  466. static uint16_t class_desc_len = 0;
  467. for (j = 0; j < class_desc_cnt; j++)
  468. {
  469. APP_USBD_CLASS_DESCRIPTOR_WRITE(hid_mouse_get_class_descriptors_type(p_inst, j)); // bDescriptorType
  470. class_desc_len = hid_mouse_get_class_descriptors_length(p_inst, j);
  471. APP_USBD_CLASS_DESCRIPTOR_WRITE(LSB_16(class_desc_len)); // wDescriptorLength LSB
  472. APP_USBD_CLASS_DESCRIPTOR_WRITE(MSB_16(class_desc_len)); // wDescriptorLength MSB
  473. }
  474. static uint8_t endpoints = 0;
  475. endpoints = app_usbd_class_iface_ep_count_get(p_cur_iface);
  476. for (j = 0; j < endpoints; j++)
  477. {
  478. /* ENDPOINT DESCRIPTOR */
  479. APP_USBD_CLASS_DESCRIPTOR_WRITE(0x07); // bLength
  480. APP_USBD_CLASS_DESCRIPTOR_WRITE(APP_USBD_DESCRIPTOR_ENDPOINT); // bDescriptorType = Endpoint
  481. static app_usbd_class_ep_conf_t const * p_cur_ep = NULL;
  482. p_cur_ep = app_usbd_class_iface_ep_get(p_cur_iface, j);
  483. APP_USBD_CLASS_DESCRIPTOR_WRITE(app_usbd_class_ep_address_get(p_cur_ep)); // bEndpointAddress
  484. APP_USBD_CLASS_DESCRIPTOR_WRITE(APP_USBD_DESCRIPTOR_EP_ATTR_TYPE_INTERRUPT); // bmAttributes
  485. APP_USBD_CLASS_DESCRIPTOR_WRITE(LSB_16(NRF_DRV_USBD_EPSIZE)); // wMaxPacketSize LSB
  486. APP_USBD_CLASS_DESCRIPTOR_WRITE(MSB_16(NRF_DRV_USBD_EPSIZE)); // wMaxPacketSize MSB
  487. APP_USBD_CLASS_DESCRIPTOR_WRITE(p_mouse->specific.inst.hid_inst.p_ep_interval[j]); // bInterval
  488. }
  489. }
  490. APP_USBD_CLASS_DESCRIPTOR_END();
  491. }
  492. ret_code_t hid_mouse_on_set_protocol(app_usbd_hid_mouse_t const * p_mouse, app_usbd_hid_user_event_t ev)
  493. {
  494. app_usbd_hid_mouse_ctx_t * p_mouse_ctx = hid_mouse_ctx_get(p_mouse);
  495. if (ev == APP_USBD_HID_USER_EVT_SET_BOOT_PROTO)
  496. {
  497. p_mouse_ctx->hid_ctx.selected_protocol = APP_USBD_HID_PROTO_BOOT;
  498. }
  499. else if (ev == APP_USBD_HID_USER_EVT_SET_REPORT_PROTO)
  500. {
  501. p_mouse_ctx->hid_ctx.selected_protocol = APP_USBD_HID_PROTO_REPORT;
  502. }
  503. else
  504. {
  505. return NRF_ERROR_NOT_SUPPORTED;
  506. }
  507. return NRF_SUCCESS;
  508. }
  509. static ret_code_t hid_mouse_on_idle(app_usbd_class_inst_t const * p_inst, uint8_t report_id)
  510. {
  511. UNUSED_PARAMETER(report_id);
  512. app_usbd_hid_mouse_t const * p_mouse = (app_usbd_hid_mouse_t const *)p_inst;
  513. nrf_drv_usbd_ep_t ep_addr = app_usbd_hid_epin_addr_get(p_inst);
  514. app_usbd_hid_mouse_ctx_t * p_mouse_ctx = hid_mouse_ctx_get(p_mouse);
  515. app_usbd_hid_state_flag_clr(&p_mouse_ctx->hid_ctx, APP_USBD_HID_STATE_FLAG_TRANS_IN_PROGRESS);
  516. app_usbd_hid_report_buffer_t const * p_rep_buffer = hid_mouse_rep_buffer_get(p_mouse);
  517. uint8_t * p_buff = p_rep_buffer->p_buff;
  518. /* Button state */
  519. p_buff[0] = p_mouse_ctx->button_state;
  520. /* Axis movement is skipped in idle report */
  521. p_buff[1] = 0;
  522. p_buff[2] = 0;
  523. p_buff[3] = 0;
  524. NRF_DRV_USBD_TRANSFER_IN(transfer, p_rep_buffer->p_buff, p_rep_buffer->size);
  525. ret_code_t ret;
  526. CRITICAL_REGION_ENTER();
  527. ret = app_usbd_ep_transfer(ep_addr, &transfer);
  528. if (ret == NRF_SUCCESS)
  529. {
  530. app_usbd_hid_state_flag_set(&p_mouse_ctx->hid_ctx,
  531. APP_USBD_HID_STATE_FLAG_TRANS_IN_PROGRESS);
  532. }
  533. CRITICAL_REGION_EXIT();
  534. return NRF_SUCCESS;
  535. }
  536. /** @} */
  537. const app_usbd_hid_methods_t app_usbd_hid_mouse_methods = {
  538. .on_get_report = hid_mouse_on_get_report,
  539. .on_set_report = hid_mouse_on_set_report,
  540. .ep_transfer_in = hid_mouse_ep_transfer_in,
  541. .ep_transfer_out = NULL,
  542. .subclass_count = hid_mouse_get_class_descriptors_count,
  543. .subclass_length = hid_mouse_get_class_descriptors_length,
  544. .subclass_data = hid_mouse_get_class_descriptors_data,
  545. .on_idle = hid_mouse_on_idle,
  546. };
  547. const app_usbd_class_methods_t app_usbd_hid_mouse_class_methods = {
  548. .event_handler = hid_mouse_event_handler,
  549. .feed_descriptors = hid_mouse_feed_descriptors,
  550. };
  551. #endif //NRF_MODULE_ENABLED(APP_USBD_HID_MOUSE)