OPP
The purpose of this document is to give an overview of the Object Push Profile. The OPP defines the requirements for the protocols and procedures that shall be used by the applications providing the Object Push usage model. This profile makes use of the Generic Object Exchange Profile, to define the interoperability requirements for the protocols needed by applications. Common devices using these models are notebook PCs, PDAs, and mobile phones.
Terminology and Concepts
OPP Roles
OPP roles are typically defined as bellow.
OPP Profile Stack
Feature Set
The functions provided by OPP APIs are as below.
Connecting and Disconnecting: Including functions to connect/disconnect OPP.
Sending and Receiving Object: Including functions to send objects through OPP between devices.
Provided APIs
The table below shows a simple description of OPP APIs. OPP related APIs are provided in the sdk\inc\framework\bt\bt_opp.h
.
Header File |
Description |
API Reference |
---|---|---|
bt_opp.h |
Connect OPP, send object etc. |
Functions
OPP Init
Initialize OPP profile, and set RFCOMM channel number and L2CAP PSM.
void app_opp_init(void)
{
bt_sdp_record_add((void *)opp_sdp_record);
bt_opp_init(RFC_OPP_CHANN_NUM, L2CAP_OPP_PSM);
bt_mgr_cback_register(app_opp_bt_cback);
}
OPP Connect
bool bt_opp_connect_over_l2c_req()
Initiate OPP connection over L2CAP to a remote device , as shown below.
bool bt_opp_connect_over_rfc_req()
Initiate OPP connection over RFCOMM to a remote device , as shown below.
Request OPP disconnection, as shown below.
Accept or reject the incoming OPP connection from the remote device.
OPP Data Transfer
bool bt_opp_push_data_header_req()
OPP client request to push data header to OPP server. The type of data header is MIME type, which can be found in https://datatracker.ietf.org/doc/html/rfc6838.
OPP client request to push data to OPP server.
OPP server acknowledgment on receiving an OPP data Indication.
Request to terminate the push operation.
OPP data transfer between OPP client and OPP server is shown below.
Source Code Overview
The following sections describe important parts of OPP application.
As OPP client, after sending data, the next data cannot be sent until the BT_EVENT_OPP_DATA_RSP is received.
As server, after receiving data BT_EVENT_OPP_DATA_IND, application must use bt_opp_send_data_rsp to send response.
#define RFC_OPP_CHANN_NUM 24
#define L2CAP_OPP_PSM 0x1003
const uint8_t opp_sdp_record[] =
{
SDP_DATA_ELEM_SEQ_HDR,
0x50,
SDP_UNSIGNED_TWO_BYTE,
(uint8_t)(SDP_ATTR_SRV_CLASS_ID_LIST >> 8),
(uint8_t)SDP_ATTR_SRV_CLASS_ID_LIST,
SDP_DATA_ELEM_SEQ_HDR,
0x03,
SDP_UUID16_HDR,
(uint8_t)(UUID_OBEX_OBJECT_PUSH >> 8),
(uint8_t)(UUID_OBEX_OBJECT_PUSH),
SDP_UNSIGNED_TWO_BYTE,
(uint8_t)(SDP_ATTR_PROTO_DESC_LIST >> 8),
(uint8_t)SDP_ATTR_PROTO_DESC_LIST,
SDP_DATA_ELEM_SEQ_HDR,
0x11,
SDP_DATA_ELEM_SEQ_HDR,
0x03,
SDP_UUID16_HDR,
(uint8_t)(UUID_L2CAP >> 8),
(uint8_t)(UUID_L2CAP),
SDP_DATA_ELEM_SEQ_HDR,
0x05,
SDP_UUID16_HDR,
(uint8_t)(UUID_RFCOMM >> 8),
(uint8_t)(UUID_RFCOMM),
SDP_UNSIGNED_ONE_BYTE,
RFC_OPP_CHANN_NUM,
SDP_DATA_ELEM_SEQ_HDR,
0x03,
SDP_UUID16_HDR,
(uint8_t)(UUID_OBEX >> 8),
(uint8_t)(UUID_OBEX),
SDP_UNSIGNED_TWO_BYTE,
(uint8_t)(SDP_ATTR_PROFILE_DESC_LIST >> 8),
(uint8_t)SDP_ATTR_PROFILE_DESC_LIST,
SDP_DATA_ELEM_SEQ_HDR,
0x08,
SDP_DATA_ELEM_SEQ_HDR,
0x06,
SDP_UUID16_HDR,
(uint8_t)(UUID_OBEX_OBJECT_PUSH >> 8),
(uint8_t)UUID_OBEX_OBJECT_PUSH,
SDP_UNSIGNED_TWO_BYTE,
0x01,
0x02, /* version 1.2 */
SDP_UNSIGNED_TWO_BYTE,
(uint8_t)((SDP_ATTR_SRV_NAME + SDP_BASE_LANG_OFFSET) >> 8),
(uint8_t)(SDP_ATTR_SRV_NAME + SDP_BASE_LANG_OFFSET),
SDP_STRING_HDR,
0x0B,
'R', 'e', 'a', 'l', 't', 'e', 'k', '-', 'O', 'P', 'P',
SDP_UNSIGNED_TWO_BYTE,
(uint8_t)((SDP_ATTR_L2C_PSM) >> 8),
(uint8_t)(SDP_ATTR_L2C_PSM),
SDP_UNSIGNED_TWO_BYTE,
(uint8_t)(L2CAP_OPP_PSM >> 8),
(uint8_t)(L2CAP_OPP_PSM),
SDP_UNSIGNED_TWO_BYTE,
(uint8_t)((SDP_ATTR_SUPPORTED_FORMATS_LIST) >> 8),
(uint8_t)(SDP_ATTR_SUPPORTED_FORMATS_LIST),
SDP_DATA_ELEM_SEQ_HDR,
0x0a,
SDP_UNSIGNED_ONE_BYTE,
0x01, /* vCard 2.1 */
SDP_UNSIGNED_ONE_BYTE,
0x02, /* vCard 3.0 */
SDP_UNSIGNED_ONE_BYTE,
0x03, /* vCal 1.0 */
SDP_UNSIGNED_ONE_BYTE,
0x04, /* vCal 2.0 */
SDP_UNSIGNED_ONE_BYTE,
0xff, /* any type of object */
};
static void app_opp_bt_cback(T_BT_EVENT event_type, void *event_buf, uint16_t buf_len)
{
T_BT_EVENT_PARAM *param = event_buf;
bool handle = true;
switch (event_type)
{
case BT_EVENT_OPP_CONN_IND:
{
bt_opp_connect_cfm(param->opp_conn_ind.bd_addr, true);
}
break;
case BT_EVENT_OPP_CONN_CMPL:
{
// bt_opp_push_data_header_req(param->opp_conn_cmpl.bd_addr, total_len, name, sizeof(name), type, sizeof(type), false);
// data_idx += data_len;
}
break;
case BT_EVENT_OPP_DATA_HEADER_IND:
{
APP_PRINT_INFO5("app_opp_bt_cback: DATA_HEADER_IND %x, %s, %s, %x, %x",
param->opp_data_header_ind.total_len,
TRACE_STRING(param->opp_data_header_ind.name), TRACE_STRING(param->opp_data_header_ind.type),
param->opp_data_header_ind.name_len, param->opp_data_header_ind.type_len);
}
break;
case BT_EVENT_OPP_DATA_IND:
{
if (!param->opp_data_ind.data_end)
{
//bt_opp_send_data_rsp(param->opp_data_ind.bd_addr, BT_OPP_RSP_CONTINUE);
}
else
{
//bt_opp_send_data_rsp(param->opp_data_ind.bd_addr, BT_OPP_RSP_SUCCESS);
}
APP_PRINT_INFO3("app_opp_bt_cback: DATA_IND 0x%04x, end %x, first_data %x",
param->opp_data_ind.data_len,
param->opp_data_ind.data_end, *(uint8_t *)param->opp_data_ind.p_data);
}
break;
case BT_EVENT_OPP_DATA_RSP:
{
if (param->opp_data_rsp.cause == BT_OPP_RSP_CONTINUE)
{
if (data_idx != 0)
{
if (data_idx + data_len < total_len)
{
bt_opp_push_data_req(param->opp_data_rsp.bd_addr, &data[data_idx], data_len, true);
data_idx += data_len;
}
else
{
bt_opp_push_data_req(param->opp_data_rsp.bd_addr, &data[data_idx], total_len - data_idx, false);
data_idx = 0;
}
}
}
}
break;
case BT_EVENT_SDP_ATTR_INFO:
{
T_BT_SDP_ATTR_INFO *sdp_info = ¶m->sdp_attr_info.info;
if (sdp_info->srv_class_uuid_data.uuid_16 == UUID_OBEX_OBJECT_PUSH)
{
if (sdp_info->profile_version >= 0x0102)
{
bt_opp_connect_over_l2c_req(param->sdp_attr_info.bd_addr, sdp_info->l2c_psm);
}
else
{
bt_opp_connect_over_rfc_req(param->sdp_attr_info.bd_addr, sdp_info->server_channel);
}
}
}
break;
default:
handle = false;
break;
}
if (handle == true)
{
APP_PRINT_INFO1("app_opp_bt_cback: event_type 0x%04x", event_type);
}
}
bool app_opp_connect_req(uint8_t *bd_addr)
{
T_BT_SDP_UUID_DATA uuid;
uuid.uuid_16 = UUID_OBEX_OBJECT_PUSH;
return bt_sdp_discov_start(bd_addr, BT_SDP_UUID16, uuid);
}