dfu_smp.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. /*
  2. * Copyright (c) 2019 Nordic Semiconductor ASA
  3. *
  4. * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
  5. */
  6. #include <zephyr/kernel.h>
  7. #include <zephyr/bluetooth/conn.h>
  8. #include <zephyr/bluetooth/uuid.h>
  9. #include <zephyr/bluetooth/gatt.h>
  10. #include <bluetooth/services/dfu_smp.h>
  11. #include <zephyr/logging/log.h>
  12. LOG_MODULE_REGISTER(dfu_smp, CONFIG_BT_DFU_SMP_LOG_LEVEL);
  13. /** @brief Notification callback function
  14. *
  15. * Internal function used to process the response from the SMP characteristic.
  16. *
  17. * @param conn Connection handler.
  18. * @param params Notification parameters structure - the pointer
  19. * to the structure provided to subscribe function.
  20. * @param data Pointer to the data buffer.
  21. * @param length The size of the received data.
  22. *
  23. * @retval BT_GATT_ITER_STOP Stop notification
  24. * @retval BT_GATT_ITER_CONTINUE Continue notification
  25. */
  26. static uint8_t notify_process(struct bt_conn *conn,
  27. struct bt_gatt_subscribe_params *params,
  28. const void *data, uint16_t length)
  29. {
  30. struct bt_dfu_smp *dfu_smp;
  31. dfu_smp = CONTAINER_OF(params,
  32. struct bt_dfu_smp,
  33. notification_params);
  34. if (!data) {
  35. /* Notification disabled */
  36. dfu_smp->cbs.rsp_part = NULL;
  37. params->notify = NULL;
  38. return BT_GATT_ITER_STOP;
  39. }
  40. if (dfu_smp->cbs.rsp_part) {
  41. dfu_smp->rsp_state.chunk_size = length;
  42. dfu_smp->rsp_state.data = data;
  43. if (dfu_smp->rsp_state.offset == 0) {
  44. /* First block */
  45. uint32_t total_len;
  46. const struct bt_dfu_smp_header *header;
  47. header = data;
  48. total_len = (((uint16_t)header->len_h8) << 8) |
  49. header->len_l8;
  50. total_len += sizeof(struct bt_dfu_smp_header);
  51. dfu_smp->rsp_state.total_size = total_len;
  52. }
  53. dfu_smp->cbs.rsp_part(dfu_smp);
  54. dfu_smp->rsp_state.offset += length;
  55. if (dfu_smp->rsp_state.offset >=
  56. dfu_smp->rsp_state.total_size) {
  57. /* Whole response has been received */
  58. dfu_smp->cbs.rsp_part = NULL;
  59. }
  60. } else {
  61. dfu_smp->cbs.error_cb(dfu_smp, -EIO);
  62. }
  63. return BT_GATT_ITER_CONTINUE;
  64. }
  65. int bt_dfu_smp_init(struct bt_dfu_smp *dfu_smp,
  66. const struct bt_dfu_smp_init_params *params)
  67. {
  68. if (!params->error_cb) {
  69. return -EINVAL;
  70. }
  71. memset(dfu_smp, 0, sizeof(*dfu_smp));
  72. dfu_smp->cbs.error_cb = params->error_cb;
  73. return 0;
  74. }
  75. int bt_dfu_smp_handles_assign(struct bt_gatt_dm *dm,
  76. struct bt_dfu_smp *dfu_smp)
  77. {
  78. const struct bt_gatt_dm_attr *gatt_service_attr =
  79. bt_gatt_dm_service_get(dm);
  80. const struct bt_gatt_service_val *gatt_service =
  81. bt_gatt_dm_attr_service_val(gatt_service_attr);
  82. const struct bt_gatt_dm_attr *gatt_chrc;
  83. const struct bt_gatt_dm_attr *gatt_desc;
  84. if (bt_uuid_cmp(gatt_service->uuid, BT_UUID_DFU_SMP_SERVICE)) {
  85. return -ENOTSUP;
  86. }
  87. LOG_DBG("Getting handles from DFU SMP service.");
  88. /* Characteristic discovery */
  89. gatt_chrc = bt_gatt_dm_char_by_uuid(dm, BT_UUID_DFU_SMP_CHAR);
  90. if (!gatt_chrc) {
  91. LOG_ERR("No SMP characteristic found.");
  92. return -EINVAL;
  93. }
  94. gatt_desc = bt_gatt_dm_desc_by_uuid(dm, gatt_chrc,
  95. BT_UUID_DFU_SMP_CHAR);
  96. if (!gatt_desc) {
  97. LOG_ERR("No characteristic value found.");
  98. return -EINVAL;
  99. }
  100. dfu_smp->handles.smp = gatt_desc->handle;
  101. gatt_desc = bt_gatt_dm_desc_by_uuid(dm, gatt_chrc, BT_UUID_GATT_CCC);
  102. if (!gatt_desc) {
  103. LOG_ERR("Missing characteristic CCC.");
  104. return -EINVAL;
  105. }
  106. dfu_smp->handles.smp_ccc = gatt_desc->handle;
  107. /* Save connection object */
  108. dfu_smp->conn = bt_gatt_dm_conn_get(dm);
  109. return 0;
  110. }
  111. int bt_dfu_smp_command(struct bt_dfu_smp *dfu_smp,
  112. bt_dfu_smp_rsp_part_cb rsp_cb,
  113. size_t cmd_size,
  114. const void *cmd_data)
  115. {
  116. uint16_t mtu;
  117. int ret;
  118. if (!dfu_smp || !rsp_cb || !cmd_data || cmd_size == 0) {
  119. return -EINVAL;
  120. }
  121. if (!dfu_smp->conn) {
  122. return -ENXIO;
  123. }
  124. // mtu = bt_gatt_get_mtu(dfu_smp->conn);
  125. // if (cmd_size > mtu) {
  126. // LOG_INF("Command size (%u) cannot fit MTU (%u)", cmd_size, mtu);
  127. // return -EMSGSIZE;
  128. // }
  129. if (dfu_smp->cbs.rsp_part) {
  130. return -EBUSY;
  131. }
  132. /* Sign into notification if not currently enabled */
  133. if (!dfu_smp->notification_params.notify) {
  134. dfu_smp->notification_params.value_handle =
  135. dfu_smp->handles.smp;
  136. dfu_smp->notification_params.ccc_handle =
  137. dfu_smp->handles.smp_ccc;
  138. dfu_smp->notification_params.notify =
  139. notify_process;
  140. dfu_smp->notification_params.value = BT_GATT_CCC_NOTIFY;
  141. atomic_set_bit(dfu_smp->notification_params.flags,
  142. BT_GATT_SUBSCRIBE_FLAG_VOLATILE);
  143. ret = bt_gatt_subscribe(dfu_smp->conn,
  144. &dfu_smp->notification_params);
  145. if (ret) {
  146. return ret;
  147. }
  148. }
  149. memset(&dfu_smp->rsp_state, 0, sizeof(dfu_smp->rsp_state));
  150. dfu_smp->cbs.rsp_part = rsp_cb;
  151. /* Send request */
  152. uint8_t i =0;
  153. for(; i < (cmd_size/240); i++)
  154. {
  155. ret = bt_gatt_write_without_response(dfu_smp->conn,
  156. dfu_smp->handles.smp,
  157. cmd_data + i*240,
  158. 240,
  159. false);
  160. if (ret) {
  161. dfu_smp->cbs.rsp_part = NULL;
  162. LOG_INF("bt_gatt_write_without_response%d: %d", i,ret);
  163. }
  164. }
  165. if(cmd_size%240)
  166. {
  167. ret = bt_gatt_write_without_response(dfu_smp->conn,
  168. dfu_smp->handles.smp,
  169. cmd_data + i*240,
  170. cmd_size - i*240,
  171. false);
  172. if (ret) {
  173. dfu_smp->cbs.rsp_part = NULL;
  174. LOG_INF("bt_gatt_write_without_response%d %d",i, ret);
  175. }
  176. }
  177. return ret;
  178. }
  179. struct bt_conn *bt_dfu_smp_conn(
  180. const struct bt_dfu_smp *dfu_smp)
  181. {
  182. return dfu_smp->conn;
  183. }
  184. const struct bt_dfu_smp_rsp_state *bt_dfu_smp_rsp_state(
  185. const struct bt_dfu_smp *dfu_smp)
  186. {
  187. return &(dfu_smp->rsp_state);
  188. }
  189. bool bt_dfu_smp_rsp_total_check(
  190. const struct bt_dfu_smp *dfu_smp)
  191. {
  192. return (dfu_smp->rsp_state.chunk_size + dfu_smp->rsp_state.offset
  193. >=
  194. dfu_smp->rsp_state.total_size);
  195. }