ots.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. /*
  2. * Copyright (c) 2020 Nordic Semiconductor ASA
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include <zephyr/types.h>
  7. #include <stddef.h>
  8. #include <string.h>
  9. #include <errno.h>
  10. #include <init.h>
  11. #include <sys/printk.h>
  12. #include <sys/byteorder.h>
  13. #include <zephyr.h>
  14. #include <acts_bluetooth/bluetooth.h>
  15. #include <acts_bluetooth/l2cap.h>
  16. #include <acts_bluetooth/conn.h>
  17. #include <acts_bluetooth/uuid.h>
  18. #include <acts_bluetooth/gatt.h>
  19. #include <acts_bluetooth/services/ots.h>
  20. #include "ots_internal.h"
  21. #include "ots_obj_manager_internal.h"
  22. #include <logging/log.h>
  23. LOG_MODULE_REGISTER(bt_ots, CONFIG_BT_OTS_LOG_LEVEL);
  24. #if defined(CONFIG_BT_OTS_OACP_READ_SUPPORT)
  25. #define OACP_FEAT_BIT_READ BIT(BT_OTS_OACP_FEAT_READ)
  26. #else
  27. #define OACP_FEAT_BIT_READ 0
  28. #endif
  29. /* OACP features supported by Kconfig */
  30. #define OACP_FEAT OACP_FEAT_BIT_READ
  31. #if defined(CONFIG_BT_OTS_OLCP_GO_TO_SUPPORT)
  32. #define OLCP_FEAT_BIT_GOTO BIT(BT_OTS_OLCP_FEAT_GO_TO)
  33. #else
  34. #define OLCP_FEAT_BIT_GOTO 0
  35. #endif
  36. /* OLCP features supported by Kconfig */
  37. #define OLCP_FEAT OLCP_FEAT_BIT_GOTO
  38. static ssize_t ots_feature_read(struct bt_conn *conn,
  39. const struct bt_gatt_attr *attr, void *buf,
  40. uint16_t len, uint16_t offset)
  41. {
  42. struct bt_ots *ots = (struct bt_ots *) attr->user_data;
  43. LOG_DBG("OTS Feature GATT Read Operation");
  44. return bt_gatt_attr_read(conn, attr, buf, len, offset, &ots->features,
  45. sizeof(ots->features));
  46. }
  47. static ssize_t ots_obj_name_read(struct bt_conn *conn,
  48. const struct bt_gatt_attr *attr, void *buf,
  49. uint16_t len, uint16_t offset)
  50. {
  51. struct bt_ots *ots = (struct bt_ots *) attr->user_data;
  52. LOG_DBG("OTS Object Name GATT Read Operation");
  53. if (!ots->cur_obj) {
  54. LOG_DBG("No Current Object selected in OTS!");
  55. return BT_GATT_ERR(BT_GATT_OTS_OBJECT_NOT_SELECTED);
  56. }
  57. return bt_gatt_attr_read(conn, attr, buf, len, offset,
  58. ots->cur_obj->metadata.name,
  59. strlen(ots->cur_obj->metadata.name));
  60. }
  61. static ssize_t ots_obj_type_read(struct bt_conn *conn,
  62. const struct bt_gatt_attr *attr, void *buf,
  63. uint16_t len, uint16_t offset)
  64. {
  65. struct bt_ots *ots = (struct bt_ots *) attr->user_data;
  66. struct bt_ots_obj_metadata *obj_meta;
  67. LOG_DBG("OTS Object Type GATT Read Operation");
  68. if (!ots->cur_obj) {
  69. LOG_DBG("No Current Object selected in OTS!");
  70. return BT_GATT_ERR(BT_GATT_OTS_OBJECT_NOT_SELECTED);
  71. }
  72. obj_meta = &ots->cur_obj->metadata;
  73. if (obj_meta->type.uuid.type == BT_UUID_TYPE_128) {
  74. return bt_gatt_attr_read(conn, attr, buf, len, offset,
  75. obj_meta->type.uuid_128.val,
  76. sizeof(obj_meta->type.uuid_128.val));
  77. } else {
  78. return bt_gatt_attr_read(conn, attr, buf, len, offset,
  79. &obj_meta->type.uuid_16.val,
  80. sizeof(obj_meta->type.uuid_16.val));
  81. }
  82. }
  83. static ssize_t ots_obj_size_read(struct bt_conn *conn,
  84. const struct bt_gatt_attr *attr, void *buf,
  85. uint16_t len, uint16_t offset)
  86. {
  87. struct bt_ots *ots = (struct bt_ots *) attr->user_data;
  88. LOG_DBG("OTS Object Size GATT Read Operation");
  89. if (!ots->cur_obj) {
  90. LOG_DBG("No Current Object selected in OTS!");
  91. return BT_GATT_ERR(BT_GATT_OTS_OBJECT_NOT_SELECTED);
  92. }
  93. return bt_gatt_attr_read(conn, attr, buf, len, offset,
  94. &ots->cur_obj->metadata.size,
  95. sizeof(ots->cur_obj->metadata.size));
  96. }
  97. static ssize_t ots_obj_id_read(struct bt_conn *conn,
  98. const struct bt_gatt_attr *attr, void *buf,
  99. uint16_t len, uint16_t offset)
  100. {
  101. struct bt_ots *ots = (struct bt_ots *) attr->user_data;
  102. uint8_t id[BT_OTS_OBJ_ID_SIZE];
  103. char id_str[BT_OTS_OBJ_ID_STR_LEN];
  104. LOG_DBG("OTS Object ID GATT Read Operation");
  105. if (!ots->cur_obj) {
  106. LOG_DBG("No Current Object selected in OTS!");
  107. return BT_GATT_ERR(BT_GATT_OTS_OBJECT_NOT_SELECTED);
  108. }
  109. sys_put_le48(ots->cur_obj->id, id);
  110. bt_ots_obj_id_to_str(ots->cur_obj->id, id_str,
  111. sizeof(id_str));
  112. LOG_DBG("Current Object ID: %s", log_strdup(id_str));
  113. return bt_gatt_attr_read(conn, attr, buf, len, offset, id, sizeof(id));
  114. }
  115. static ssize_t ots_obj_prop_read(struct bt_conn *conn,
  116. const struct bt_gatt_attr *attr, void *buf,
  117. uint16_t len, uint16_t offset)
  118. {
  119. struct bt_ots *ots = (struct bt_ots *) attr->user_data;
  120. LOG_DBG("OTS Object Properties GATT Read Operation");
  121. if (!ots->cur_obj) {
  122. LOG_DBG("No Current Object selected in OTS!");
  123. return BT_GATT_ERR(BT_GATT_OTS_OBJECT_NOT_SELECTED);
  124. }
  125. return bt_gatt_attr_read(conn, attr, buf, len, offset,
  126. &ots->cur_obj->metadata.props,
  127. sizeof(ots->cur_obj->metadata.props));
  128. }
  129. int bt_ots_obj_add(struct bt_ots *ots,
  130. struct bt_ots_obj_metadata *obj_init)
  131. {
  132. int err;
  133. struct bt_gatt_ots_object *obj;
  134. err = bt_gatt_ots_obj_manager_obj_add(ots->obj_manager, &obj);
  135. if (err) {
  136. LOG_ERR("No space available in the object manager");
  137. return err;
  138. }
  139. /* Initialize object. */
  140. memcpy(&obj->metadata, obj_init, sizeof(obj->metadata));
  141. /* Request object data. */
  142. if (ots->cb->obj_created) {
  143. err = ots->cb->obj_created(ots, NULL, obj->id, obj_init);
  144. if (err) {
  145. bt_gatt_ots_obj_manager_obj_delete(obj);
  146. return err;
  147. }
  148. }
  149. /* Make object the Current Object if this is the first one added. */
  150. if (!ots->cur_obj) {
  151. ots->cur_obj = obj;
  152. }
  153. return 0;
  154. }
  155. int bt_ots_obj_delete(struct bt_ots *ots, uint64_t id)
  156. {
  157. int err;
  158. struct bt_gatt_ots_object *obj;
  159. err = bt_gatt_ots_obj_manager_obj_get(ots->obj_manager, id, &obj);
  160. if (err) {
  161. return err;
  162. }
  163. if (ots->cur_obj == obj) {
  164. if (obj->state.type != BT_GATT_OTS_OBJECT_IDLE_STATE) {
  165. return -EBUSY;
  166. }
  167. ots->cur_obj = NULL;
  168. }
  169. err = bt_gatt_ots_obj_manager_obj_delete(obj);
  170. if (err) {
  171. return err;
  172. }
  173. if (ots->cb->obj_deleted) {
  174. ots->cb->obj_deleted(ots, NULL, obj->id);
  175. }
  176. return 0;
  177. }
  178. #if defined(CONFIG_BT_OTS_SECONDARY_SVC)
  179. void *bt_ots_svc_decl_get(struct bt_ots *ots)
  180. {
  181. return ots->service->attrs;
  182. }
  183. #endif
  184. int bt_ots_init(struct bt_ots *ots,
  185. struct bt_ots_init *ots_init)
  186. {
  187. int err;
  188. if (!ots || !ots_init || !ots_init->cb) {
  189. return -EINVAL;
  190. }
  191. __ASSERT(ots_init->cb->obj_created,
  192. "Callback for object creation is not set");
  193. __ASSERT(ots_init->cb->obj_read ||
  194. !BT_OTS_OACP_GET_FEAT_READ(ots_init->features.oacp),
  195. "Callback for object reading is not set");
  196. /* Set callback structure. */
  197. ots->cb = ots_init->cb;
  198. /* Check OACP supported features against Kconfig. */
  199. if (ots_init->features.oacp & (~((uint32_t) OACP_FEAT))) {
  200. return -ENOTSUP;
  201. }
  202. ots->features.oacp = ots_init->features.oacp;
  203. LOG_DBG("OACP features: 0x%04X", ots->features.oacp);
  204. /* Check OLCP supported features against Kconfig. */
  205. if (ots_init->features.olcp & (~((uint32_t) OLCP_FEAT))) {
  206. return -ENOTSUP;
  207. }
  208. ots->features.olcp = ots_init->features.olcp;
  209. LOG_DBG("OLCP features: 0x%04X", ots->features.olcp);
  210. /* Register L2CAP context. */
  211. err = bt_gatt_ots_l2cap_register(&ots->l2cap);
  212. if (err) {
  213. return err;
  214. }
  215. err = bt_gatt_service_register(ots->service);
  216. if (err) {
  217. bt_gatt_ots_l2cap_unregister(&ots->l2cap);
  218. return err;
  219. }
  220. LOG_DBG("Initialized OTS");
  221. return 0;
  222. }
  223. #if defined(CONFIG_BT_OTS_SECONDARY_SVC)
  224. #define BT_GATT_OTS_SERVICE BT_GATT_SECONDARY_SERVICE
  225. #else
  226. #define BT_GATT_OTS_SERVICE BT_GATT_PRIMARY_SERVICE
  227. #endif
  228. #define BT_GATT_OTS_ATTRS(_ots) { \
  229. BT_GATT_OTS_SERVICE(BT_UUID_OTS), \
  230. BT_GATT_CHARACTERISTIC(BT_UUID_OTS_FEATURE, \
  231. BT_GATT_CHRC_READ, BT_GATT_PERM_READ, \
  232. ots_feature_read, NULL, &_ots), \
  233. BT_GATT_CHARACTERISTIC(BT_UUID_OTS_NAME, \
  234. BT_GATT_CHRC_READ, BT_GATT_PERM_READ, \
  235. ots_obj_name_read, NULL, &_ots), \
  236. BT_GATT_CHARACTERISTIC(BT_UUID_OTS_TYPE, \
  237. BT_GATT_CHRC_READ, BT_GATT_PERM_READ, \
  238. ots_obj_type_read, NULL, &_ots), \
  239. BT_GATT_CHARACTERISTIC(BT_UUID_OTS_SIZE, \
  240. BT_GATT_CHRC_READ, BT_GATT_PERM_READ, \
  241. ots_obj_size_read, NULL, &_ots), \
  242. BT_GATT_CHARACTERISTIC(BT_UUID_OTS_ID, \
  243. BT_GATT_CHRC_READ, BT_GATT_PERM_READ, \
  244. ots_obj_id_read, NULL, &_ots), \
  245. BT_GATT_CHARACTERISTIC(BT_UUID_OTS_PROPERTIES, \
  246. BT_GATT_CHRC_READ, BT_GATT_PERM_READ, \
  247. ots_obj_prop_read, NULL, &_ots), \
  248. BT_GATT_CHARACTERISTIC(BT_UUID_OTS_ACTION_CP, \
  249. BT_GATT_CHRC_WRITE | BT_GATT_CHRC_INDICATE, \
  250. BT_GATT_PERM_WRITE, NULL, \
  251. bt_gatt_ots_oacp_write, &_ots), \
  252. BT_GATT_CCC_MANAGED(&_ots.oacp_ind.ccc, \
  253. BT_GATT_PERM_READ | BT_GATT_PERM_WRITE), \
  254. BT_GATT_CHARACTERISTIC(BT_UUID_OTS_LIST_CP, \
  255. BT_GATT_CHRC_WRITE | BT_GATT_CHRC_INDICATE, \
  256. BT_GATT_PERM_WRITE, NULL, \
  257. bt_gatt_ots_olcp_write, &_ots), \
  258. BT_GATT_CCC_MANAGED(&_ots.olcp_ind.ccc, \
  259. BT_GATT_PERM_READ | BT_GATT_PERM_WRITE) \
  260. }
  261. #define BT_GATT_OTS_INSTANCE_LIST_SIZE (ARRAY_SIZE(ots_instances))
  262. #define BT_GATT_OTS_INSTANCE_LIST_START ots_instances
  263. #define BT_GATT_OTS_INSTANCE_LIST_END \
  264. (&ots_instances[BT_GATT_OTS_INSTANCE_LIST_SIZE])
  265. #define BT_GATT_OTS_SERVICE_LIST_START ots_service_list
  266. static struct bt_ots ots_instances[CONFIG_BT_OTS_MAX_INST_CNT];
  267. static uint32_t instance_cnt;
  268. BT_GATT_SERVICE_INSTANCE_DEFINE(ots_service_list, ots_instances,
  269. CONFIG_BT_OTS_MAX_INST_CNT,
  270. BT_GATT_OTS_ATTRS);
  271. struct bt_ots *bt_ots_free_instance_get(void)
  272. {
  273. if (instance_cnt >= BT_GATT_OTS_INSTANCE_LIST_SIZE) {
  274. return NULL;
  275. }
  276. return &BT_GATT_OTS_INSTANCE_LIST_START[instance_cnt++];
  277. }
  278. int bt_gatt_ots_instances_prepare(void)
  279. {
  280. uint32_t index;
  281. struct bt_ots *instance;
  282. bt_gatt_ots_l2cap_init();
  283. for (instance = BT_GATT_OTS_INSTANCE_LIST_START, index = 0;
  284. instance != BT_GATT_OTS_INSTANCE_LIST_END;
  285. instance++, index++) {
  286. /* Assign an object pool to the OTS instance. */
  287. instance->obj_manager = bt_gatt_ots_obj_manager_assign();
  288. if (!instance->obj_manager) {
  289. LOG_ERR("OTS Object manager instance not available");
  290. return -ENOMEM;
  291. }
  292. /* Assign pointer to the service descriptor. */
  293. instance->service = &BT_GATT_OTS_SERVICE_LIST_START[index];
  294. /* Initialize CCC descriptors for characteristics with
  295. * indication properties.
  296. */
  297. instance->oacp_ind.ccc.cfg_changed =
  298. bt_gatt_ots_oacp_cfg_changed;
  299. instance->olcp_ind.ccc.cfg_changed =
  300. bt_gatt_ots_olcp_cfg_changed;
  301. }
  302. return 0;
  303. }