/* * Copyright (c) 2020 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ #ifndef ZEPHYR_INCLUDE_BLUETOOTH_SERVICES_OTS_H_ #define ZEPHYR_INCLUDE_BLUETOOTH_SERVICES_OTS_H_ /** * @brief Object Transfer Service (OTS) * @defgroup bt_ots Object Transfer Service (OTS) * @ingroup bluetooth * @{ * * [Experimental] Users should note that the APIs can change * as a part of ongoing development. */ #ifdef __cplusplus extern "C" { #endif #include #include #include #include #include #include /** @brief Size of OTS object ID (in bytes). */ #define BT_OTS_OBJ_ID_SIZE 6 /** @brief Minimum allowed value for object ID (except ID for directory listing) */ #define BT_OTS_OBJ_ID_MIN 0x000000000100 /** @brief Maximum allowed value for object ID (except ID for directory listing) */ #define BT_OTS_OBJ_ID_MAX 0xFFFFFFFFFFFF /** @brief ID of the Directory Listing Object */ #define OTS_OBJ_ID_DIR_LIST 0x000000000000 /** @brief Mask for OTS object IDs, preserving the 48 bits */ #define BT_OTS_OBJ_ID_MASK BIT64_MASK(48) /** @brief Length of OTS object ID string (in bytes). */ #define BT_OTS_OBJ_ID_STR_LEN 15 /** @brief Type of an OTS object. */ struct bt_ots_obj_type { union { /* Used to indicate UUID type */ struct bt_uuid uuid; /* 16-bit UUID value */ struct bt_uuid_16 uuid_16; /* 128-bit UUID value */ struct bt_uuid_128 uuid_128; }; }; /** @brief Properties of an OTS object. */ enum { /** Bit 0 Deletion of this object is permitted */ BT_OTS_OBJ_PROP_DELETE = 0, /** Bit 1 Execution of this object is permitted */ BT_OTS_OBJ_PROP_EXECUTE = 1, /** Bit 2 Reading this object is permitted */ BT_OTS_OBJ_PROP_READ = 2, /** Bit 3 Writing data to this object is permitted */ BT_OTS_OBJ_PROP_WRITE = 3, /** @brief Bit 4 Appending data to this object is permitted. * * Appending data increases its Allocated Size. */ BT_OTS_OBJ_PROP_APPEND = 4, /** Bit 5 Truncation of this object is permitted */ BT_OTS_OBJ_PROP_TRUNCATE = 5, /** @brief Bit 6 Patching this object is permitted * * Patching this object overwrites some of * the object's existing contents. */ BT_OTS_OBJ_PROP_PATCH = 6, /** Bit 7 This object is a marked object */ BT_OTS_OBJ_PROP_MARKED = 7, }; /** @brief Set @ref BT_OTS_OBJ_PROP_DELETE property. * * @param prop Object properties. */ #define BT_OTS_OBJ_SET_PROP_DELETE(prop) \ WRITE_BIT(prop, BT_OTS_OBJ_PROP_DELETE, 1) /** @brief Set @ref BT_OTS_OBJ_PROP_EXECUTE property. * * @param prop Object properties. */ #define BT_OTS_OBJ_SET_PROP_EXECUTE(prop) \ WRITE_BIT(prop, BT_OTS_OBJ_PROP_EXECUTE, 1) /** @brief Set @ref BT_OTS_OBJ_PROP_READ property. * * @param prop Object properties. */ #define BT_OTS_OBJ_SET_PROP_READ(prop) \ WRITE_BIT(prop, BT_OTS_OBJ_PROP_READ, 1) /** @brief Set @ref BT_OTS_OBJ_PROP_WRITE property. * * @param prop Object properties. */ #define BT_OTS_OBJ_SET_PROP_WRITE(prop) \ WRITE_BIT(prop, BT_OTS_OBJ_PROP_WRITE, 1) /** @brief Set @ref BT_OTS_OBJ_PROP_APPEND property. * * @param prop Object properties. */ #define BT_OTS_OBJ_SET_PROP_APPEND(prop) \ WRITE_BIT(prop, BT_OTS_OBJ_PROP_APPEND, 1) /** @brief Set @ref BT_OTS_OBJ_PROP_TRUNCATE property. * * @param prop Object properties. */ #define BT_OTS_OBJ_SET_PROP_TRUNCATE(prop) \ WRITE_BIT(prop, BT_OTS_OBJ_PROP_TRUNCATE, 1) /** @brief Set @ref BT_OTS_OBJ_PROP_PATCH property. * * @param prop Object properties. */ #define BT_OTS_OBJ_SET_PROP_PATCH(prop) \ WRITE_BIT(prop, BT_OTS_OBJ_PROP_PATCH, 1) /** @brief Set @ref BT_OTS_OBJ_SET_PROP_MARKED property. * * @param prop Object properties. */ #define BT_OTS_OBJ_SET_PROP_MARKED(prop) \ WRITE_BIT(prop, BT_OTS_OBJ_PROP_MARKED, 1) /** @brief Get @ref BT_OTS_OBJ_PROP_DELETE property. * * @param prop Object properties. */ #define BT_OTS_OBJ_GET_PROP_DELETE(prop) \ ((prop) & BIT(BT_OTS_OBJ_PROP_DELETE)) /** @brief Get @ref BT_OTS_OBJ_PROP_EXECUTE property. * * @param prop Object properties. */ #define BT_OTS_OBJ_GET_PROP_EXECUTE(prop) \ ((prop) & BIT(BT_OTS_OBJ_PROP_EXECUTE)) /** @brief Get @ref BT_OTS_OBJ_PROP_READ property. * * @param prop Object properties. */ #define BT_OTS_OBJ_GET_PROP_READ(prop) \ ((prop) & BIT(BT_OTS_OBJ_PROP_READ)) /** @brief Get @ref BT_OTS_OBJ_PROP_WRITE property. * * @param prop Object properties. */ #define BT_OTS_OBJ_GET_PROP_WRITE(prop) \ ((prop) & BIT(BT_OTS_OBJ_PROP_WRITE)) /** @brief Get @ref BT_OTS_OBJ_PROP_APPEND property. * * @param prop Object properties. */ #define BT_OTS_OBJ_GET_PROP_APPEND(prop) \ ((prop) & BIT(BT_OTS_OBJ_PROP_APPEND)) /** @brief Get @ref BT_OTS_OBJ_PROP_TRUNCATE property. * * @param prop Object properties. */ #define BT_OTS_OBJ_GET_PROP_TRUNCATE(prop) \ ((prop) & BIT(BT_OTS_OBJ_PROP_TRUNCATE)) /** @brief Get @ref BT_OTS_OBJ_PROP_PATCH property. * * @param prop Object properties. */ #define BT_OTS_OBJ_GET_PROP_PATCH(prop) \ ((prop) & BIT(BT_OTS_OBJ_PROP_PATCH)) /** @brief Get @ref BT_OTS_OBJ_PROP_MARKED property. * * @param prop Object properties. */ #define BT_OTS_OBJ_GET_PROP_MARKED(prop) \ ((prop) & BIT(BT_OTS_OBJ_PROP_MARKED)) /** @brief Descriptor for OTS Object Size parameter. */ struct bt_ots_obj_size { /* Current Size */ uint32_t cur; /* Allocated Size */ uint32_t alloc; } __packed; /** @brief Descriptor for OTS object initialization. */ struct bt_ots_obj_metadata { /* Object Name */ char *name; /* Object Type */ struct bt_ots_obj_type type; /* Object Size */ struct bt_ots_obj_size size; /* Object Properties */ uint32_t props; }; /** @brief Object Action Control Point Feature bits. */ enum { /** Bit 0 OACP Create Op Code Supported */ BT_OTS_OACP_FEAT_CREATE = 0, /** Bit 1 OACP Delete Op Code Supported */ BT_OTS_OACP_FEAT_DELETE = 1, /** Bit 2 OACP Calculate Checksum Op Code Supported */ BT_OTS_OACP_FEAT_CHECKSUM = 2, /** Bit 3 OACP Execute Op Code Supported */ BT_OTS_OACP_FEAT_EXECUTE = 3, /** Bit 4 OACP Read Op Code Supported */ BT_OTS_OACP_FEAT_READ = 4, /** Bit 5 OACP Write Op Code Supported */ BT_OTS_OACP_FEAT_WRITE = 5, /** Bit 6 Appending Additional Data to Objects Supported */ BT_OTS_OACP_FEAT_APPEND = 6, /** Bit 7 Truncation of Objects Supported */ BT_OTS_OACP_FEAT_TRUNCATE = 7, /** Bit 8 Patching of Objects Supported */ BT_OTS_OACP_FEAT_PATCH = 8, /** Bit 9 OACP Abort Op Code Supported */ BT_OTS_OACP_FEAT_ABORT = 9, }; /** @brief Set @ref BT_OTS_OACP_SET_FEAT_CREATE feature. * * @param feat OTS features. */ #define BT_OTS_OACP_SET_FEAT_CREATE(feat) \ WRITE_BIT(feat, BT_OTS_OACP_FEAT_CREATE, 1) /** @brief Set @ref BT_OTS_OACP_FEAT_DELETE feature. * * @param feat OTS features. */ #define BT_OTS_OACP_SET_FEAT_DELETE(feat) \ WRITE_BIT(feat, BT_OTS_OACP_FEAT_DELETE, 1) /** @brief Set @ref BT_OTS_OACP_FEAT_CHECKSUM feature. * * @param feat OTS features. */ #define BT_OTS_OACP_SET_FEAT_CHECKSUM(feat) \ WRITE_BIT(feat, BT_OTS_OACP_FEAT_CHECKSUM, 1) /** @brief Set @ref BT_OTS_OACP_FEAT_EXECUTE feature. * * @param feat OTS features. */ #define BT_OTS_OACP_SET_FEAT_EXECUTE(feat) \ WRITE_BIT(feat, BT_OTS_OACP_FEAT_EXECUTE, 1) /** @brief Set @ref BT_OTS_OACP_FEAT_READ feature. * * @param feat OTS features. */ #define BT_OTS_OACP_SET_FEAT_READ(feat) \ WRITE_BIT(feat, BT_OTS_OACP_FEAT_READ, 1) /** @brief Set @ref BT_OTS_OACP_FEAT_WRITE feature. * * @param feat OTS features. */ #define BT_OTS_OACP_SET_FEAT_WRITE(feat) \ WRITE_BIT(feat, BT_OTS_OACP_FEAT_WRITE, 1) /** @brief Set @ref BT_OTS_OACP_FEAT_APPEND feature. * * @param feat OTS features. */ #define BT_OTS_OACP_SET_FEAT_APPEND(feat) \ WRITE_BIT(feat, BT_OTS_OACP_FEAT_APPEND, 1) /** @brief Set @ref BT_OTS_OACP_FEAT_TRUNCATE feature. * * @param feat OTS features. */ #define BT_OTS_OACP_SET_FEAT_TRUNCATE(feat) \ WRITE_BIT(feat, BT_OTS_OACP_FEAT_TRUNCATE, 1) /** @brief Set @ref BT_OTS_OACP_FEAT_PATCH feature. * * @param feat OTS features. */ #define BT_OTS_OACP_SET_FEAT_PATCH(feat) \ WRITE_BIT(feat, BT_OTS_OACP_FEAT_PATCH, 1) /** @brief Set @ref BT_OTS_OACP_FEAT_ABORT feature. * * @param feat OTS features. */ #define BT_OTS_OACP_SET_FEAT_ABORT(feat) \ WRITE_BIT(feat, BT_OTS_OACP_FEAT_ABORT, 1) /** @brief Get @ref BT_OTS_OACP_FEAT_CREATE feature. * * @param feat OTS features. */ #define BT_OTS_OACP_GET_FEAT_CREATE(feat) \ ((feat) & BIT(BT_OTS_OACP_FEAT_CREATE)) /** @brief Get @ref BT_OTS_OACP_FEAT_DELETE feature. * * @param feat OTS features. */ #define BT_OTS_OACP_GET_FEAT_DELETE(feat) \ ((feat) & BIT(BT_OTS_OACP_FEAT_DELETE)) /** @brief Get @ref BT_OTS_OACP_FEAT_CHECKSUM feature. * * @param feat OTS features. */ #define BT_OTS_OACP_GET_FEAT_CHECKSUM(feat) \ ((feat) & BIT(BT_OTS_OACP_FEAT_CHECKSUM)) /** @brief Get @ref BT_OTS_OACP_FEAT_EXECUTE feature. * * @param feat OTS features. */ #define BT_OTS_OACP_GET_FEAT_EXECUTE(feat) \ ((feat) & BIT(BT_OTS_OACP_FEAT_EXECUTE)) /** @brief Get @ref BT_OTS_OACP_FEAT_READ feature. * * @param feat OTS features. */ #define BT_OTS_OACP_GET_FEAT_READ(feat) \ ((feat) & BIT(BT_OTS_OACP_FEAT_READ)) /** @brief Get @ref BT_OTS_OACP_FEAT_WRITE feature. * * @param feat OTS features. */ #define BT_OTS_OACP_GET_FEAT_WRITE(feat) \ ((feat) & BIT(BT_OTS_OACP_FEAT_WRITE)) /** @brief Get @ref BT_OTS_OACP_FEAT_APPEND feature. * * @param feat OTS features. */ #define BT_OTS_OACP_GET_FEAT_APPEND(feat) \ ((feat) & BIT(BT_OTS_OACP_FEAT_APPEND)) /** @brief Get @ref BT_OTS_OACP_FEAT_TRUNCATE feature. * * @param feat OTS features. */ #define BT_OTS_OACP_GET_FEAT_TRUNCATE(feat) \ ((feat) & BIT(BT_OTS_OACP_FEAT_TRUNCATE)) /** @brief Get @ref BT_OTS_OACP_FEAT_PATCH feature. * * @param feat OTS features. */ #define BT_OTS_OACP_GET_FEAT_PATCH(feat) \ ((feat) & BIT(BT_OTS_OACP_FEAT_PATCH)) /** @brief Get @ref BT_OTS_OACP_FEAT_ABORT feature. * * @param feat OTS features. */ #define BT_OTS_OACP_GET_FEAT_ABORT(feat) \ ((feat) & BIT(BT_OTS_OACP_FEAT_ABORT)) /** @brief Object List Control Point Feature bits. */ enum { /** Bit 0 OLCP Go To Op Code Supported */ BT_OTS_OLCP_FEAT_GO_TO = 0, /** Bit 1 OLCP Order Op Code Supported */ BT_OTS_OLCP_FEAT_ORDER = 1, /** Bit 2 OLCP Request Number of Objects Op Code Supported */ BT_OTS_OLCP_FEAT_NUM_REQ = 2, /** Bit 3 OLCP Clear Marking Op Code Supported*/ BT_OTS_OLCP_FEAT_CLEAR = 3, }; /** @brief Set @ref BT_OTS_OLCP_FEAT_GO_TO feature. * * @param feat OTS features. */ #define BT_OTS_OLCP_SET_FEAT_GO_TO(feat) \ WRITE_BIT(feat, BT_OTS_OLCP_FEAT_GO_TO, 1) /** @brief Set @ref BT_OTS_OLCP_FEAT_ORDER feature. * * @param feat OTS features. */ #define BT_OTS_OLCP_SET_FEAT_ORDER(feat) \ WRITE_BIT(feat, BT_OTS_OLCP_FEAT_ORDER, 1) /** @brief Set @ref BT_OTS_OLCP_FEAT_NUM_REQ feature. * * @param feat OTS features. */ #define BT_OTS_OLCP_SET_FEAT_NUM_REQ(feat) \ WRITE_BIT(feat, BT_OTS_OLCP_FEAT_NUM_REQ, 1) /** @brief Set @ref BT_OTS_OLCP_FEAT_CLEAR feature. * * @param feat OTS features. */ #define BT_OTS_OLCP_SET_FEAT_CLEAR(feat) \ WRITE_BIT(feat, BT_OTS_OLCP_FEAT_CLEAR, 1) /** @brief Get @ref BT_OTS_OLCP_GET_FEAT_GO_TO feature. * * @param feat OTS features. */ #define BT_OTS_OLCP_GET_FEAT_GO_TO(feat) \ ((feat) & BIT(BT_OTS_OLCP_FEAT_GO_TO)) /** @brief Get @ref BT_OTS_OLCP_GET_FEAT_ORDER feature. * * @param feat OTS features. */ #define BT_OTS_OLCP_GET_FEAT_ORDER(feat) \ ((feat) & BIT(BT_OTS_OLCP_FEAT_ORDER)) /** @brief Get @ref BT_OTS_OLCP_GET_FEAT_NUM_REQ feature. * * @param feat OTS features. */ #define BT_OTS_OLCP_GET_FEAT_NUM_REQ(feat) \ ((feat) & BIT(BT_OTS_OLCP_FEAT_NUM_REQ)) /** @brief Get @ref BT_OTS_OLCP_GET_FEAT_CLEAR feature. * * @param feat OTS features. */ #define BT_OTS_OLCP_GET_FEAT_CLEAR(feat) \ ((feat) & BIT(BT_OTS_OLCP_FEAT_CLEAR)) /**@brief Features of the OTS. */ struct bt_ots_feat { /* OACP Features */ uint32_t oacp; /* OLCP Features */ uint32_t olcp; } __packed; /** @brief Opaque OTS instance. */ struct bt_ots; /** @brief OTS callback structure. */ struct bt_ots_cb { /** @brief Object created callback * * This callback is called whenever a new object is created. * Application can reject this request by returning an error * when it does not have necessary resources to hold this new * object. This callback is also triggered when the server * creates a new object with bt_ots_obj_add() API. * * @param ots OTS instance. * @param conn The connection that is requesting object creation or * NULL if object is created by the following function: * bt_ots_obj_add(). * @param id Object ID. * @param init Object initialization metadata. * * @return 0 in case of success or negative value in case of error. * Possible return values: * -ENOMEM if no available space for new object. */ int (*obj_created)(struct bt_ots *ots, struct bt_conn *conn, uint64_t id, const struct bt_ots_obj_metadata *init); /** @brief Object deleted callback * * This callback is called whenever an object is deleted. It is * also triggered when the server deletes an object with * bt_ots_obj_delete() API. * * @param ots OTS instance. * @param conn The connection that deleted the object or NULL if * this request came from the server. * @param id Object ID. */ void (*obj_deleted)(struct bt_ots *ots, struct bt_conn *conn, uint64_t id); /** @brief Object selected callback * * This callback is called on successful object selection. * * @param ots OTS instance. * @param conn The connection that selected new object. * @param id Object ID. */ void (*obj_selected)(struct bt_ots *ots, struct bt_conn *conn, uint64_t id); /** @brief Object read callback * * This callback is called multiple times during the Object read * operation. OTS module will keep requesting successive Object * fragments from the application until the read operation is * completed. The end of read operation is indicated by NULL data * parameter. * * @param ots OTS instance. * @param conn The connection that read object. * @param id Object ID. * @param data In: NULL once the read operations is completed. * Out: Next chunk of data to be sent. * @param len Remaining length requested by the client. * @param offset Object data offset. * * @return Data length to be sent via data parameter. This value * shall be smaller or equal to the len parameter. * @return Negative value in case of an error. */ ssize_t (*obj_read)(struct bt_ots *ots, struct bt_conn *conn, uint64_t id, void **data, size_t len, off_t offset); /** @brief Object write callback * * This callback is called multiple times during the Object write * operation. OTS module will keep providing successive Object * fragments to the application until the write operation is * completed. The offset and length of each write fragment is * validated by the OTS module to be within the allocated size * of the object. The remaining length indicates data length * remaining to be written and will decrease each write iteration * until it reaches 0 in the last write fragment. * * @param ots OTS instance. * @param conn The connection that wrote object. * @param id Object ID. * @param data Next chunk of data to be written. * @param len Length of the current chunk of data in the buffer. * @param offset Object data offset. * @param rem Remaining length in the write operation. * * @return Number of bytes written in case of success, if the number * of bytes written does not match len, -EIO is returned to * the L2CAP layer. * @return A negative value in case of an error. * @return -EINPROGRESS has a special meaning and is unsupported at * the moment. It should not be returned. */ ssize_t (*obj_write)(struct bt_ots *ots, struct bt_conn *conn, uint64_t id, const void *data, size_t len, off_t offset, size_t rem); /** @brief Object name written callback * * This callback is called when the object name is written. * This is a notification to the application that the object name * has been updated by the OTS service implementation. * * @param ots OTS instance. * @param conn The connection that wrote object name. * @param id Object ID. * @param name Object name. */ void (*obj_name_written)(struct bt_ots *ots, struct bt_conn *conn, uint64_t id, const char *name); }; /** @brief Descriptor for OTS initialization. */ struct bt_ots_init { /* OTS features */ struct bt_ots_feat features; /* Callbacks */ struct bt_ots_cb *cb; }; /** @brief Add an object to the OTS instance. * * This function adds an object to the OTS database. When the * object is being added, a callback obj_created() is called * to notify the user about a new object ID. * * @param ots OTS instance. * @param obj_init Meta data of the object. * * @return 0 in case of success or negative value in case of error. */ int bt_ots_obj_add(struct bt_ots *ots, struct bt_ots_obj_metadata *obj_init); /** @brief Delete an object from the OTS instance. * * This function deletes an object from the OTS database. When the * object is deleted a callback obj_deleted() is called * to notify the user about this event. At this point, it is possible * to free allocated buffer for object data. * * @param ots OTS instance. * @param id ID of the object to be deleted (uint48). * * @return 0 in case of success or negative value in case of error. */ int bt_ots_obj_delete(struct bt_ots *ots, uint64_t id); /** @brief Get the service declaration attribute. * * This function is enabled for CONFIG_BT_OTS_SECONDARY_SVC configuration. * The first service attribute can be included in any other GATT service. * * @param ots OTS instance. * * @return The first OTS attribute instance. */ void *bt_ots_svc_decl_get(struct bt_ots *ots); /** @brief Initialize the OTS instance. * * @param ots OTS instance. * @param ots_init OTS initialization descriptor. * * @return 0 in case of success or negative value in case of error. */ int bt_ots_init(struct bt_ots *ots, struct bt_ots_init *ots_init); /** @brief Get a free instance of OTS from the pool. * * @return OTS instance in case of success or NULL in case of error. */ struct bt_ots *bt_ots_free_instance_get(void); /** @brief Converts binary OTS Object ID to string. * * @param obj_id Object ID. * @param str Address of user buffer with enough room to store * formatted string containing binary Object ID. * @param len Length of data to be copied to user string buffer. * Refer to BT_OTS_OBJ_ID_STR_LEN about * recommended value. * * @return Number of successfully formatted bytes from binary ID. */ static inline int bt_ots_obj_id_to_str(uint64_t obj_id, char *str, size_t len) { uint8_t id[6]; sys_put_le48(obj_id, id); return snprintk(str, len, "0x%02X%02X%02X%02X%02X%02X", id[5], id[4], id[3], id[2], id[1], id[0]); } #ifdef __cplusplus } #endif /** * @} */ #endif /* ZEPHYR_INCLUDE_BLUETOOTH_SERVICES_OTS_H_ */