SPP (Serial Port Profile)
SPP stands for Serial Port Profile, which allows devices to wirelessly transfer data by simulating a serial port connection. Based on the RFCOMM communication layer, the SPP protocol is similar to the traditional RS-232 serial port standard, making it ideal for low-speed, short-range data transmission, such as communication between Android devices, sensors, and microcontrollers.
SPP defines two roles:
Device A (DevA) – The device that initiates the connection to another device.
Initiates requests through SDP to query DevB’s RFCOMM channel.
Can perform security authentication with the other device.
Can establish an L2CAP (RFCOMM) RFCOMM (DLC) channel with the other device through the queried RFCOMM channel.
Can send and receive data.
Can disconnect the connection.
Device B (DevB) – The device that waits for another device to initiate the connection.
Registers the SPP-related UUID in the SDP database so DevA can query it.
Can perform security authentication with the other device.
Receives the connection request from the other device.
Can send and receive data.
Can disconnect the connection.
This document mainly describes the basic functionality support for DevB in SPP based on the Sifli SDK. The relevant files are:
bts2_app_interface
bts2_app_spp_s
SPP Initialization
The SPP initialization function:
bt_spp_srv_init
, which initializes SPP-related states, flags, and registers the SPP UUID.
//step1: Users can override the bt_spp_srv_add_uuid_list function to register custom SPP UUIDs into the BR/EDR SDP database
//step2: When enabling the SPP profile, the SPP will register data into the SDP
//Note: Currently, a maximum of 7 custom UUIDs are supported
void bt_spp_srv_add_uuid_list(void)
{
U8 uuid_128[] =
{
0x30, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
};
U8 uuid_32[] =
{
0x30, 0x01, 0x02, 0x03
};
U8 uuid_16[] =
{
0x30, 0x01
};
spp_add_uuid_list_node(uuid_128, sizeof(uuid_128), "aaaa");
spp_add_uuid_list_node(uuid_32, sizeof(uuid_32), "bbbb");
spp_add_uuid_list_node(uuid_16, sizeof(uuid_16), "cccc");
}
void bt_spp_srv_init(bts2_app_stru *bts2_app_data)
{
U8 i = 0;
bts2_app_data->select_device_id = 0;
bts2_app_data->select_srv_chnl = 0;
bts2_app_data->spp_srv_conn_nums = 0;
bts2_app_data->spp_srv_inst_ptr = &bts2_app_data->spp_srv_inst[0];
for (i = 0; i < CFG_MAX_ACL_CONN_NUM; i++)
{
bts2_app_data->spp_srv_inst[i].device_id = 0xff;
bd_set_empty(&bts2_app_data->spp_srv_inst[i].bd_addr);
bts2_app_data->spp_srv_inst[i].cur_link_mode = 0;
bts2_app_data->spp_srv_inst[i].exit_sniff_pending = FALSE;
bts2_app_data->spp_srv_inst[i].cod = 0;
bts2_app_data->spp_srv_inst[i].service_list = 0;
bts2_app_data->spp_srv_inst[i].spp_service_list = NULL;
}
bt_spp_srv_add_uuid_list();
}
void bt_spp_srv_start_enb(bts2_app_stru *bts2_app_data)
{
U8 i;
for (i = 0; i < SPP_SRV_MAX_CONN_NUM; i++)
{
spp_srv_enb_req(i, SPP_DEFAULT_NAME);
}
USER_TRACE(">> SPP enabled
");
}
SPP Data Transmission and Reception
SPP, as a DevB feature, can only receive connection requests initiated by the other device.
SPP disconnect device interface:
bts2_app_interface
disconnect interface:bt_interface_dis_spp_by_addr_and_chl
bts2_app_spp_s
disconnect interface:bt_spp_srv_disc_req
SPP connection status callback events:
SPP connection successful:
BT_NOTIFY_SPP_PROFILE_CONNECTED
SPP connection failed:
BT_NOTIFY_SPP_PROFILE_DISCONNECTED
SPP connection received:
BT_NOTIFY_SPP_CONN_IND
SPP connection disconnected:
BT_NOTIFY_SPP_DISC_IND
SPP data transmission and reception interfaces and events:
Data sending:
bts2_app_interface
data send interface:bt_interface_spp_send_data
bts2_app_spp_s
data send interface:bt_spp_srv_sending_data_by_device_id_and_srv_chnl
Data send success event:
BT_NOTIFY_SPP_DATA_CFM
Data reception:
bts2_app_interface
data reception success response interface:bt_interface_spp_srv_data_rsp
bts2_app_spp_s
data reception success response interface:spp_srv_data_rsp_ext
Data received event:
BT_NOTIFY_SPP_DATA_IND
// step1: When receiving a connection from the other device, if only a single channel is connected, handle the events: BT_NOTIFY_SPP_PROFILE_CONNECTED and BT_NOTIFY_SPP_PROFILE_DISCONNECTED
// step2: When multiple channels are connected, handle the related connection events: BT_NOTIFY_SPP_CONN_IND and BT_NOTIFY_SPP_DISC_IND
// The difference between step1 and step2: In step1, the event only contains the address and connection reason of the other device. In step2, the event contains the UUID and service channel information.
// step3: After receiving data, you need to reply using bt_interface_spp_srv_data_rsp
// step4: Send data using the interface: bt_interface_spp_send_data
// step5: After data is successfully sent, the event BT_NOTIFY_SPP_DATA_CFM will be received
int bt_sifli_notify_spp_event_hdl(uint16_t event_id, uint8_t *data, uint16_t data_len)
{
switch (event_id)
{
case BT_NOTIFY_SPP_PROFILE_CONNECTED:
{
bt_notify_profile_state_info_t *profile_info = (bt_notify_profile_state_info_t *)data;
break;
}
case BT_NOTIFY_SPP_PROFILE_DISCONNECTED:
{
bt_notify_profile_state_info_t *profile_info = (bt_notify_profile_state_info_t *)data;
break;
}
case BT_NOTIFY_SPP_CONN_IND:
{
bt_notify_spp_conn_ind_t *conn_ind = (bt_notify_spp_conn_ind_t *)data;
break;
}
case BT_NOTIFY_SPP_DATA_IND:
{
bt_notify_spp_data_ind_t *data_info = (bt_notify_spp_data_ind_t *)data;
BTS2S_BD_ADDR bd_addr;
bt_addr_convert_to_bts((bd_addr_t *)data_info->mac.addr, &bd_addr);
bt_interface_spp_srv_data_rsp(&bd_addr, data_info->srv_chl);
break;
}
case BT_NOTIFY_SPP_DATA_CFM:
{
bt_notify_spp_data_cfm_t *data_cfm = (bt_notify_spp_data_cfm_t *)data;
break;
}
case BT_NOTIFY_SPP_DISC_IND:
{
bt_notify_spp_disc_ind_t *disc_ind = (bt_notify_spp_disc_ind_t *)data;
break;
}
default:
return -1;
}
return 0;
}
static int bt_sifli_notify_common_event_hdl(uint16_t event_id, uint8_t *data, uint16_t data_len)
{
switch (event_id)
{
case BT_NOTIFY_COMMON_BT_STACK_READY:
{
break;
}
case BT_NOTIFY_COMMON_CLOSE_COMPLETE:
{
break;
}
case BT_NOTIFY_COMMON_ACL_CONNECTED:
{
bt_notify_device_acl_conn_info_t *acl_info = (bt_notify_device_acl_conn_info_t *)data;
break;
}
case BT_NOTIFY_COMMON_ACL_DISCONNECTED:
{
bt_notify_device_base_info_t *device_info = (bt_notify_device_base_info_t *)data;
break;
}
default:
return -1;
}
return 0;
}
static int bt_notify_handle(uint16_t type, uint16_t event_id, uint8_t *data, uint16_t data_len)
{
int ret = -1;
switch (type)
{
case BT_NOTIFY_COMMON:
{
ret = bt_sifli_notify_common_event_hdl(event_id, data, data_len);
}
break;
case BT_NOTIFY_SPP:
{
bt_sifli_notify_spp_event_hdl(event_id, data, data_len);
}
break;
default:
break;
}
return 0;
}
int app_bt_notify_init(void)
{
bt_interface_register_bt_event_notify_callback(bt_notify_handle);
return 0;
}
INIT_ENV_EXPORT(app_bt_notify_init);
// Register notify event handle function end
This document provides an overview of SPP functionality, implementation details, and the necessary SDK files.