/* * Copyright (c) 2020-2022 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. */ #include #include #include #include #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif /** @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 0x000000000100ULL /** @brief Maximum allowed value for object ID (except ID for directory listing) */ #define BT_OTS_OBJ_ID_MAX 0xFFFFFFFFFFFFULL /** @brief ID of the Directory Listing Object */ #define OTS_OBJ_ID_DIR_LIST 0x000000000000ULL /** @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 { /** @brief Current Size */ uint32_t cur; /** @brief Allocated Size */ uint32_t alloc; } __packed; /** @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, }; /* * @enum bt_ots_oacp_write_op_mode * @brief Mode Parameter for OACP Write Op Code. */ enum bt_ots_oacp_write_op_mode { BT_OTS_OACP_WRITE_OP_MODE_NONE = 0, BT_OTS_OACP_WRITE_OP_MODE_TRUNCATE = BIT(1), }; /** @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 Object metadata request bit field values */ enum { /** @brief Request object name */ BT_OTS_METADATA_REQ_NAME = BIT(0), /** @brief Request object type */ BT_OTS_METADATA_REQ_TYPE = BIT(1), /** @brief Request object size */ BT_OTS_METADATA_REQ_SIZE = BIT(2), /** @brief Request object first created time */ BT_OTS_METADATA_REQ_CREATED = BIT(3), /** @brief Request object last modified time */ BT_OTS_METADATA_REQ_MODIFIED = BIT(4), /** @brief Request object ID */ BT_OTS_METADATA_REQ_ID = BIT(5), /** @brief Request object properties */ BT_OTS_METADATA_REQ_PROPS = BIT(6), /** @brief Request all object metadata */ BT_OTS_METADATA_REQ_ALL = 0x7F, }; /** @brief Date and Time structure */ struct bt_ots_date_time { uint16_t year; uint8_t month; uint8_t day; uint8_t hours; uint8_t minutes; uint8_t seconds; }; #define BT_OTS_DATE_TIME_FIELD_SIZE 7 /** @brief Metadata of an OTS object * * Used by the server as a descriptor for OTS object initialization. * Used by the client to present object metadata to the application. */ struct bt_ots_obj_metadata { #if defined(CONFIG_BT_OTS) /** @brief Object Name */ char *name; #endif /* CONFIG_BT_OTS */ #if defined(CONFIG_BT_OTS_CLIENT) /* TODO: Unify client/server name */ /** @brief Object name (client) */ char name_c[CONFIG_BT_OTS_OBJ_MAX_NAME_LEN + 1]; #endif /* CONFIG_BT_OTS_CLIENT */ /** @brief Object Type */ struct bt_ots_obj_type type; /** @brief Object Size */ struct bt_ots_obj_size size; #if defined(CONFIG_BT_OTS_CLIENT) /** @brief Object first created time */ struct bt_ots_date_time first_created; /** @brief Object last modified time */ struct bt_ots_date_time modified; /** @brief Object ID */ uint64_t id; #endif /* CONFIG_BT_OTS_CLIENT */ /** @brief Object Properties */ uint32_t props; }; /** @brief Opaque OTS instance. */ struct bt_ots; /** @brief Descriptor for OTS object addition */ struct bt_ots_obj_add_param { /** @brief Object size to allocate */ uint32_t size; /** @brief Object type */ struct bt_ots_obj_type type; }; /** @brief Descriptor for OTS created object. * * Descriptor for OTS object created by the application. This descriptor is * returned by @ref bt_ots_cb.obj_created callback which contains further * documentation on distinguishing between server and client object creation. */ struct bt_ots_obj_created_desc { /** @brief Object name * * The object name as a NULL terminated string. * * When the server creates a new object the name * shall be > 0 and <= BT_OTS_OBJ_MAX_NAME_LEN * When the client creates a new object the name * shall be an empty string */ char *name; /** @brief Object size * * @ref bt_ots_obj_size.alloc shall be >= @ref bt_ots_obj_add_param.size * * When the server creates a new object @ref bt_ots_obj_size.cur * shall be <= @ref bt_ots_obj_add_param.size * When the client creates a new object @ref bt_ots_obj_size.cur * shall be 0 */ struct bt_ots_obj_size size; /** @brief Object properties */ uint32_t props; }; /** @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 bt_ots_obj_add(). * @param id Object ID. * @param add_param Object creation requested parameters. * @param created_desc Created object descriptor that shall be filled by the * receiver of this callback. * * @return 0 in case of success or negative value in case of error. * @return -ENOTSUP if object type is not supported * @return -ENOMEM if no available space for new object. * @return -EINVAL if an invalid parameter is provided * @return other negative values are treated as a generic operation failure */ int (*obj_created)(struct bt_ots *ots, struct bt_conn *conn, uint64_t id, const struct bt_ots_obj_add_param *add_param, struct bt_ots_obj_created_desc *created_desc); /** @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. * * @retval When an error is indicated by using a negative value, the * object delete procedure is aborted and a corresponding failed * status is returned to the client. * @return 0 in case of success. * @return -EBUSY if the object is locked. This is generally not expected * to be returned by the application as the OTS layer tracks object * accesses. An object locked status is returned to the client. * @return Other negative values in case of error. A generic operation * failed status is returned to the client. */ int (*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 * will be updated by the OTS service implementation. * * @param ots OTS instance. * @param conn The connection that wrote object name. * @param id Object ID. * @param cur_name Current object name. * @param new_name New object name. */ void (*obj_name_written)(struct bt_ots *ots, struct bt_conn *conn, uint64_t id, const char *cur_name, const char *new_name); /** @brief Object Calculate checksum callback * * This callback is called when the OACP Calculate Checksum procedure is performed. * Because object data is opaque to OTS, the application is the only one who * knows where data is and should return pointer of actual object data. * * @param[in] ots OTS instance. * @param[in] conn The connection that wrote object. * @param[in] id Object ID. * @param[in] offset The first octet of the object contents need to be calculated. * @param[in] len The length number of octets object name. * @param[out] data Pointer of actual object data. * * @return 0 to accept, or any negative value to reject. */ int (*obj_cal_checksum)(struct bt_ots *ots, struct bt_conn *conn, uint64_t id, off_t offset, size_t len, void **data); }; /** @brief Descriptor for OTS initialization. */ struct bt_ots_init_param { /* 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 param Object addition parameters. * * @return ID of created object in case of success. * @return negative value in case of error. */ int bt_ots_obj_add(struct bt_ots *ots, const struct bt_ots_obj_add_param *param); /** @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_param *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); #define BT_OTS_STOP 0 #define BT_OTS_CONTINUE 1 /* TODO: Merge server and client instance as opaque type */ /** @brief OTS client instance */ struct bt_ots_client { uint16_t start_handle; uint16_t end_handle; uint16_t feature_handle; uint16_t obj_name_handle; uint16_t obj_type_handle; uint16_t obj_size_handle; uint16_t obj_properties_handle; uint16_t obj_created_handle; uint16_t obj_modified_handle; uint16_t obj_id_handle; uint16_t oacp_handle; uint16_t olcp_handle; struct bt_gatt_subscribe_params oacp_sub_params; struct bt_gatt_discover_params oacp_sub_disc_params; struct bt_gatt_subscribe_params olcp_sub_params; struct bt_gatt_discover_params olcp_sub_disc_params; struct bt_gatt_write_params write_params; struct bt_gatt_read_params read_proc; struct bt_ots_client_cb *cb; struct bt_ots_feat features; struct bt_ots_obj_metadata cur_object; }; /** OTS client callback structure */ struct bt_ots_client_cb { /** @brief Callback function when a new object is selected. * * Called when the a new object is selected and the current * object has changed. The `cur_object` in `ots_inst` will * have been reset, and metadata should be read again with * bt_ots_client_read_object_metadata(). * * @param ots_inst Pointer to the OTC instance. * @param conn The connection to the peer device. * @param err Error code (bt_ots_olcp_res_code). */ void (*obj_selected)(struct bt_ots_client *ots_inst, struct bt_conn *conn, int err); /** @brief Callback function for the data of the selected * object. * * Called when the data of the selected object are read using * bt_ots_client_read_object_data(). * * @param ots_inst Pointer to the OTC instance. * @param conn The connection to the peer device. * @param offset Offset of the received data. * @param len Length of the received data. * @param data_p Pointer to the received data. * @param is_complete Indicate if the whole object has been received. * * @return int BT_OTS_STOP or BT_OTS_CONTINUE. BT_OTS_STOP can * be used to stop reading. */ int (*obj_data_read)(struct bt_ots_client *ots_inst, struct bt_conn *conn, uint32_t offset, uint32_t len, uint8_t *data_p, bool is_complete); /** @brief Callback function for metadata of the selected object. * * Called when metadata of the selected object are read using * bt_ots_client_read_object_metadata(). * Not all of the metadata may have been initialized. * * @param ots_inst Pointer to the OTC instance. * @param conn The connection to the peer device. * @param err Error value. 0 on success, * GATT error or ERRNO on fail. * @param metadata_read Bitfield of the metadata that was * successfully read. */ void (*obj_metadata_read)(struct bt_ots_client *ots_inst, struct bt_conn *conn, int err, uint8_t metadata_read); /** @brief Callback function for the data of the write object. * * Called when the data of the selected object is written using * bt_ots_client_write_object_data(). * * @param ots_inst Pointer to the OTC instance. * @param conn The connection to the peer device. * @param len Length of the written data. */ void (*obj_data_written)(struct bt_ots_client *ots_inst, struct bt_conn *conn, size_t len); /** @brief Callback function when checksum indication is received. * * Called when the oacp_ind_handler received response of * OP BT_GATT_OTS_OACP_PROC_CHECKSUM_CALC. * * @param ots_inst Pointer to the OTC instance. * @param conn The connection to the peer device. * @param err Error code (bt_gatt_ots_oacp_res_code). * @param checksum Checksum if error code is BT_GATT_OTS_OACP_RES_SUCCESS, * otherwise 0. */ void (*obj_checksum_calculated)(struct bt_ots_client *ots_inst, struct bt_conn *conn, int err, uint32_t checksum); }; /** @brief Register an Object Transfer Service Instance. * * Register an Object Transfer Service instance discovered on the peer. * Call this function when an OTS instance is discovered * (discovery is to be handled by the higher layer). * * @param[in] ots_inst Discovered OTS instance. * * @return int 0 if success, ERRNO on failure. */ int bt_ots_client_register(struct bt_ots_client *ots_inst); /** @brief Unregister an Object Transfer Service Instance. * * Unregister an Object Transfer Service instance when disconnect from the peer. * Call this function when an ACL using OTS instance is disconnected. * * @param[in] index Index of OTS instance. * * @return int 0 if success, ERRNO on failure. */ int bt_ots_client_unregister(uint8_t index); /** @brief OTS Indicate Handler function. * * Set this function as callback for indicate handler when discovering OTS. * * @param conn Connection object. May be NULL, indicating that the * peer is being unpaired. * @param params Subscription parameters. * @param data Attribute value data. If NULL then subscription was * removed. * @param length Attribute value length. */ uint8_t bt_ots_client_indicate_handler(struct bt_conn *conn, struct bt_gatt_subscribe_params *params, const void *data, uint16_t length); /** @brief Read the OTS feature characteristic. * * @param otc_inst Pointer to the OTC instance. * @param conn Pointer to the connection object. * * @return int 0 if success, ERRNO on failure. */ int bt_ots_client_read_feature(struct bt_ots_client *otc_inst, struct bt_conn *conn); /** @brief Select an object by its Object ID. * * @param otc_inst Pointer to the OTC instance. * @param conn Pointer to the connection object. * @param obj_id Object's ID. * * @return int 0 if success, ERRNO on failure. */ int bt_ots_client_select_id(struct bt_ots_client *otc_inst, struct bt_conn *conn, uint64_t obj_id); /** @brief Select the first object. * * @param otc_inst Pointer to the OTC instance. * @param conn Pointer to the connection object. * * @return int 0 if success, ERRNO on failure. */ int bt_ots_client_select_first(struct bt_ots_client *otc_inst, struct bt_conn *conn); /** @brief Select the last object. * * @param otc_inst Pointer to the OTC instance. * @param conn Pointer to the connection object. * * @return int 0 if success, ERRNO on failure. */ int bt_ots_client_select_last(struct bt_ots_client *otc_inst, struct bt_conn *conn); /** @brief Select the next object. * * @param otc_inst Pointer to the OTC instance. * @param conn Pointer to the connection object. * * @return int 0 if success, ERRNO on failure. */ int bt_ots_client_select_next(struct bt_ots_client *otc_inst, struct bt_conn *conn); /** @brief Select the previous object. * * @param otc_inst Pointer to the OTC instance. * @param conn Pointer to the connection object. * * @return int 0 if success, ERRNO on failure. */ int bt_ots_client_select_prev(struct bt_ots_client *otc_inst, struct bt_conn *conn); /** @brief Read the metadata of the current object. * * The metadata are returned in the obj_metadata_read() callback. * * @param otc_inst Pointer to the OTC instance. * @param conn Pointer to the connection object. * @param metadata Bitfield (`BT_OTS_METADATA_REQ_*`) of the metadata * to read. * * @return int 0 if success, ERRNO on failure. */ int bt_ots_client_read_object_metadata(struct bt_ots_client *otc_inst, struct bt_conn *conn, uint8_t metadata); /** @brief Read the data of the current selected object. * * This will trigger an OACP read operation for the current size of the object * with a 0 offset and then expect receiving the content via the L2CAP CoC. * * The data of the object are returned in the obj_data_read() callback. * * @param otc_inst Pointer to the OTC instance. * @param conn Pointer to the connection object. * * @return int 0 if success, ERRNO on failure. */ int bt_ots_client_read_object_data(struct bt_ots_client *otc_inst, struct bt_conn *conn); /** @brief Write the data of the current selected object. * * This will trigger an OACP write operation for the current object * with a specified offset and then expect transferring the content via the L2CAP CoC. * * The length of the data written to object is returned in the obj_data_written() callback. * * @param otc_inst Pointer to the OTC instance. * @param conn Pointer to the connection object. * @param buf Pointer to the data buffer to be written. * @param len Size of data. * @param offset Offset to write, usually 0. * @param mode Mode Parameter for OACP Write Op Code. See @ref bt_ots_oacp_write_op_mode. * * @return int 0 if success, ERRNO on failure. */ int bt_ots_client_write_object_data(struct bt_ots_client *otc_inst, struct bt_conn *conn, const void *buf, size_t len, off_t offset, enum bt_ots_oacp_write_op_mode mode); /** @brief Get the checksum of the current selected object. * * This will trigger an OACP calculate checksum operation for the current object * with a specified offset and length. * * The checksum goes to OACP IND and obj_checksum_calculated() callback. * * @param otc_inst Pointer to the OTC instance. * @param conn Pointer to the connection object. * @param offset Offset to calculate, usually 0. * @param len Len of data to calculate checksum for. May be less than the current object's * size, but shall not be larger. * * @return int 0 if success, ERRNO on failure. */ int bt_ots_client_get_object_checksum(struct bt_ots_client *otc_inst, struct bt_conn *conn, off_t offset, size_t len); /** @brief Directory listing object metadata callback * * If a directory listing is decoded using bt_ots_client_decode_dirlisting(), * this callback will be called for each object in the directory listing. * * @param meta The metadata of the decoded object * * @return int BT_OTS_STOP or BT_OTS_CONTINUE. BT_OTS_STOP can be used to * stop the decoding. */ typedef int (*bt_ots_client_dirlisting_cb)(struct bt_ots_obj_metadata *meta); /** @brief Decode Directory Listing object into object metadata. * * If the Directory Listing object contains multiple objects, then the * callback will be called for each of them. * * @param data The data received for the directory listing object. * @param length Length of the data. * @param cb The callback that will be called for each object. */ int bt_ots_client_decode_dirlisting(uint8_t *data, uint16_t length, bt_ots_client_dirlisting_cb cb); /** @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]); } /** @brief Displays one or more object metadata as text with LOG_INF. * * @param metadata Pointer to the first (or only) metadata in an array. * @param count Number of metadata objects to display information of. */ void bt_ots_metadata_display(struct bt_ots_obj_metadata *metadata, uint16_t count); /** * @brief Generate IEEE conform CRC32 checksum. * * To abstract IEEE implementation to service layer. * * @param data Pointer to data on which the CRC should be calculated. * @param len Data length. * * @return CRC32 value. * */ #if defined(CONFIG_BT_OTS_OACP_CHECKSUM_SUPPORT) static inline uint32_t bt_ots_client_calc_checksum(const uint8_t *data, size_t len) { return crc32_ieee(data, len); } #endif #ifdef __cplusplus } #endif /** * @} */ #endif /* ZEPHYR_INCLUDE_BLUETOOTH_SERVICES_OTS_H_ */