mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-03-14 01:27:41 +00:00
add LE Data Channel Events (L2CAP_EVENT_LE_*). implement can send now logic
This commit is contained in:
parent
cab29d481b
commit
4427624894
@ -426,6 +426,53 @@ typedef uint8_t sm_key_t[16];
|
||||
*/
|
||||
#define L2CAP_EVENT_CAN_SEND_NOW 0x78
|
||||
|
||||
// LE Data Channels
|
||||
|
||||
/**
|
||||
* @format 1BH2222
|
||||
* @param address_type
|
||||
* @param address
|
||||
* @param handle
|
||||
* @param psm
|
||||
* @param local_cid
|
||||
* @param remote_cid
|
||||
* @param remote_mtu
|
||||
*/
|
||||
#define L2CAP_EVENT_LE_INCOMING_CONNECTION 0x79
|
||||
|
||||
/**
|
||||
* @format 11BH22222
|
||||
* @param status
|
||||
* @param address_type
|
||||
* @param address
|
||||
* @param handle
|
||||
* @param psm
|
||||
* @param local_cid
|
||||
* @param remote_cid
|
||||
* @param local_mtu
|
||||
* @param remote_mtu
|
||||
*/
|
||||
#define L2CAP_EVENT_LE_CHANNEL_OPENED 0x7a
|
||||
|
||||
/*
|
||||
* @format 2
|
||||
* @param local_cid
|
||||
*/
|
||||
#define L2CAP_EVENT_LE_CHANNEL_CLOSED 0x7b
|
||||
|
||||
/*
|
||||
* @format 2
|
||||
* @param local_cid
|
||||
*/
|
||||
#define L2CAP_EVENT_LE_CAN_SEND_NOW 0x7c
|
||||
|
||||
/*
|
||||
* @format 2
|
||||
* @param local_cid
|
||||
*/
|
||||
#define L2CAP_EVENT_LE_PACKET_SENT 0x7d
|
||||
|
||||
|
||||
// RFCOMM EVENTS
|
||||
|
||||
/**
|
||||
|
@ -1157,6 +1157,182 @@ static inline uint16_t l2cap_event_can_send_now_get_local_cid(const uint8_t * ev
|
||||
return little_endian_read_16(event, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get field address_type from event L2CAP_EVENT_LE_INCOMING_CONNECTION
|
||||
* @param event packet
|
||||
* @return address_type
|
||||
* @note: btstack_type 1
|
||||
*/
|
||||
static inline uint8_t l2cap_event_le_incoming_connection_get_address_type(const uint8_t * event){
|
||||
return event[2];
|
||||
}
|
||||
/**
|
||||
* @brief Get field address from event L2CAP_EVENT_LE_INCOMING_CONNECTION
|
||||
* @param event packet
|
||||
* @param Pointer to storage for address
|
||||
* @note: btstack_type B
|
||||
*/
|
||||
static inline void l2cap_event_le_incoming_connection_get_address(const uint8_t * event, bd_addr_t address){
|
||||
reverse_bd_addr(&event[3], address);
|
||||
}
|
||||
/**
|
||||
* @brief Get field handle from event L2CAP_EVENT_LE_INCOMING_CONNECTION
|
||||
* @param event packet
|
||||
* @return handle
|
||||
* @note: btstack_type H
|
||||
*/
|
||||
static inline hci_con_handle_t l2cap_event_le_incoming_connection_get_handle(const uint8_t * event){
|
||||
return little_endian_read_16(event, 9);
|
||||
}
|
||||
/**
|
||||
* @brief Get field psm from event L2CAP_EVENT_LE_INCOMING_CONNECTION
|
||||
* @param event packet
|
||||
* @return psm
|
||||
* @note: btstack_type 2
|
||||
*/
|
||||
static inline uint16_t l2cap_event_le_incoming_connection_get_psm(const uint8_t * event){
|
||||
return little_endian_read_16(event, 11);
|
||||
}
|
||||
/**
|
||||
* @brief Get field local_cid from event L2CAP_EVENT_LE_INCOMING_CONNECTION
|
||||
* @param event packet
|
||||
* @return local_cid
|
||||
* @note: btstack_type 2
|
||||
*/
|
||||
static inline uint16_t l2cap_event_le_incoming_connection_get_local_cid(const uint8_t * event){
|
||||
return little_endian_read_16(event, 13);
|
||||
}
|
||||
/**
|
||||
* @brief Get field remote_cid from event L2CAP_EVENT_LE_INCOMING_CONNECTION
|
||||
* @param event packet
|
||||
* @return remote_cid
|
||||
* @note: btstack_type 2
|
||||
*/
|
||||
static inline uint16_t l2cap_event_le_incoming_connection_get_remote_cid(const uint8_t * event){
|
||||
return little_endian_read_16(event, 15);
|
||||
}
|
||||
/**
|
||||
* @brief Get field remote_mtu from event L2CAP_EVENT_LE_INCOMING_CONNECTION
|
||||
* @param event packet
|
||||
* @return remote_mtu
|
||||
* @note: btstack_type 2
|
||||
*/
|
||||
static inline uint16_t l2cap_event_le_incoming_connection_get_remote_mtu(const uint8_t * event){
|
||||
return little_endian_read_16(event, 17);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get field status from event L2CAP_EVENT_LE_CHANNEL_OPENED
|
||||
* @param event packet
|
||||
* @return status
|
||||
* @note: btstack_type 1
|
||||
*/
|
||||
static inline uint8_t l2cap_event_le_channel_opened_get_status(const uint8_t * event){
|
||||
return event[2];
|
||||
}
|
||||
/**
|
||||
* @brief Get field address_type from event L2CAP_EVENT_LE_CHANNEL_OPENED
|
||||
* @param event packet
|
||||
* @return address_type
|
||||
* @note: btstack_type 1
|
||||
*/
|
||||
static inline uint8_t l2cap_event_le_channel_opened_get_address_type(const uint8_t * event){
|
||||
return event[3];
|
||||
}
|
||||
/**
|
||||
* @brief Get field address from event L2CAP_EVENT_LE_CHANNEL_OPENED
|
||||
* @param event packet
|
||||
* @param Pointer to storage for address
|
||||
* @note: btstack_type B
|
||||
*/
|
||||
static inline void l2cap_event_le_channel_opened_get_address(const uint8_t * event, bd_addr_t address){
|
||||
reverse_bd_addr(&event[4], address);
|
||||
}
|
||||
/**
|
||||
* @brief Get field handle from event L2CAP_EVENT_LE_CHANNEL_OPENED
|
||||
* @param event packet
|
||||
* @return handle
|
||||
* @note: btstack_type H
|
||||
*/
|
||||
static inline hci_con_handle_t l2cap_event_le_channel_opened_get_handle(const uint8_t * event){
|
||||
return little_endian_read_16(event, 10);
|
||||
}
|
||||
/**
|
||||
* @brief Get field psm from event L2CAP_EVENT_LE_CHANNEL_OPENED
|
||||
* @param event packet
|
||||
* @return psm
|
||||
* @note: btstack_type 2
|
||||
*/
|
||||
static inline uint16_t l2cap_event_le_channel_opened_get_psm(const uint8_t * event){
|
||||
return little_endian_read_16(event, 12);
|
||||
}
|
||||
/**
|
||||
* @brief Get field local_cid from event L2CAP_EVENT_LE_CHANNEL_OPENED
|
||||
* @param event packet
|
||||
* @return local_cid
|
||||
* @note: btstack_type 2
|
||||
*/
|
||||
static inline uint16_t l2cap_event_le_channel_opened_get_local_cid(const uint8_t * event){
|
||||
return little_endian_read_16(event, 14);
|
||||
}
|
||||
/**
|
||||
* @brief Get field remote_cid from event L2CAP_EVENT_LE_CHANNEL_OPENED
|
||||
* @param event packet
|
||||
* @return remote_cid
|
||||
* @note: btstack_type 2
|
||||
*/
|
||||
static inline uint16_t l2cap_event_le_channel_opened_get_remote_cid(const uint8_t * event){
|
||||
return little_endian_read_16(event, 16);
|
||||
}
|
||||
/**
|
||||
* @brief Get field local_mtu from event L2CAP_EVENT_LE_CHANNEL_OPENED
|
||||
* @param event packet
|
||||
* @return local_mtu
|
||||
* @note: btstack_type 2
|
||||
*/
|
||||
static inline uint16_t l2cap_event_le_channel_opened_get_local_mtu(const uint8_t * event){
|
||||
return little_endian_read_16(event, 18);
|
||||
}
|
||||
/**
|
||||
* @brief Get field remote_mtu from event L2CAP_EVENT_LE_CHANNEL_OPENED
|
||||
* @param event packet
|
||||
* @return remote_mtu
|
||||
* @note: btstack_type 2
|
||||
*/
|
||||
static inline uint16_t l2cap_event_le_channel_opened_get_remote_mtu(const uint8_t * event){
|
||||
return little_endian_read_16(event, 20);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get field local_cid from event L2CAP_EVENT_LE_CHANNEL_CLOSED
|
||||
* @param event packet
|
||||
* @return local_cid
|
||||
* @note: btstack_type 2
|
||||
*/
|
||||
static inline uint16_t l2cap_event_le_channel_closed_get_local_cid(const uint8_t * event){
|
||||
return little_endian_read_16(event, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get field local_cid from event L2CAP_EVENT_LE_CAN_SEND_NOW
|
||||
* @param event packet
|
||||
* @return local_cid
|
||||
* @note: btstack_type 2
|
||||
*/
|
||||
static inline uint16_t l2cap_event_le_can_send_now_get_local_cid(const uint8_t * event){
|
||||
return little_endian_read_16(event, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get field local_cid from event L2CAP_EVENT_LE_PACKET_SENT
|
||||
* @param event packet
|
||||
* @return local_cid
|
||||
* @note: btstack_type 2
|
||||
*/
|
||||
static inline uint16_t l2cap_event_le_packet_sent_get_local_cid(const uint8_t * event){
|
||||
return little_endian_read_16(event, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get field status from event RFCOMM_EVENT_CHANNEL_OPENED
|
||||
* @param event packet
|
||||
|
140
src/l2cap.c
140
src/l2cap.c
@ -87,12 +87,13 @@ static inline l2cap_service_t * l2cap_get_service(uint16_t psm);
|
||||
static void l2cap_emit_channel_opened(l2cap_channel_t *channel, uint8_t status);
|
||||
static void l2cap_emit_can_send_now(btstack_packet_handler_t packet_handler, uint16_t channel);
|
||||
static void l2cap_emit_channel_closed(l2cap_channel_t *channel);
|
||||
static void l2cap_emit_connection_request(l2cap_channel_t *channel);
|
||||
static void l2cap_emit_incoming_connection(l2cap_channel_t *channel);
|
||||
static int l2cap_channel_ready_for_open(l2cap_channel_t *channel);
|
||||
static void l2cap_hci_event_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
|
||||
static void l2cap_acl_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size );
|
||||
static void l2cap_notify_channel_can_send(void);
|
||||
#ifdef ENABLE_LE_DATA_CHANNELS
|
||||
static void l2cap_le_notify_channel_can_send(l2cap_channel_t *channel);
|
||||
static void l2cap_le_finialize_channel_close(l2cap_channel_t *channel);
|
||||
static inline l2cap_service_t * l2cap_le_get_service(uint16_t psm);
|
||||
#endif
|
||||
@ -180,6 +181,15 @@ static void l2cap_dispatch_to_channel(l2cap_channel_t *channel, uint8_t type, ui
|
||||
(* (channel->packet_handler))(type, channel->local_cid, data, size);
|
||||
}
|
||||
|
||||
static void l2cap_emit_simple_event_with_cid(l2cap_channel_t * channel, uint8_t event_code){
|
||||
uint8_t event[4];
|
||||
event[0] = event_code;
|
||||
event[1] = sizeof(event) - 2;
|
||||
little_endian_store_16(event, 2, channel->local_cid);
|
||||
hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
|
||||
l2cap_dispatch_to_channel(channel, HCI_EVENT_PACKET, event, sizeof(event));
|
||||
}
|
||||
|
||||
void l2cap_emit_channel_opened(l2cap_channel_t *channel, uint8_t status) {
|
||||
log_info("L2CAP_EVENT_CHANNEL_OPENED status 0x%x addr %s handle 0x%x psm 0x%x local_cid 0x%x remote_cid 0x%x local_mtu %u, remote_mtu %u, flush_timeout %u",
|
||||
status, bd_addr_to_str(channel->address), channel->con_handle, channel->psm,
|
||||
@ -200,17 +210,23 @@ void l2cap_emit_channel_opened(l2cap_channel_t *channel, uint8_t status) {
|
||||
l2cap_dispatch_to_channel(channel, HCI_EVENT_PACKET, event, sizeof(event));
|
||||
}
|
||||
|
||||
void l2cap_emit_channel_closed(l2cap_channel_t *channel) {
|
||||
static void l2cap_emit_channel_closed(l2cap_channel_t *channel) {
|
||||
log_info("L2CAP_EVENT_CHANNEL_CLOSED local_cid 0x%x", channel->local_cid);
|
||||
uint8_t event[4];
|
||||
event[0] = L2CAP_EVENT_CHANNEL_CLOSED;
|
||||
event[1] = sizeof(event) - 2;
|
||||
little_endian_store_16(event, 2, channel->local_cid);
|
||||
hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
|
||||
l2cap_dispatch_to_channel(channel, HCI_EVENT_PACKET, event, sizeof(event));
|
||||
l2cap_emit_simple_event_with_cid(channel, L2CAP_EVENT_CHANNEL_CLOSED);
|
||||
}
|
||||
|
||||
void l2cap_emit_connection_request(l2cap_channel_t *channel) {
|
||||
|
||||
static void l2cap_emit_can_send_now(btstack_packet_handler_t packet_handler, uint16_t channel) {
|
||||
log_info("L2CAP_EVENT_CHANNEL_CAN_SEND_NOW local_cid 0x%x", channel);
|
||||
uint8_t event[4];
|
||||
event[0] = L2CAP_EVENT_CAN_SEND_NOW;
|
||||
event[1] = sizeof(event) - 2;
|
||||
little_endian_store_16(event, 2, channel);
|
||||
hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
|
||||
packet_handler(HCI_EVENT_PACKET, channel, event, sizeof(event));
|
||||
}
|
||||
|
||||
static void l2cap_emit_incoming_connection(l2cap_channel_t *channel) {
|
||||
log_info("L2CAP_EVENT_INCOMING_CONNECTION addr %s handle 0x%x psm 0x%x local_cid 0x%x remote_cid 0x%x",
|
||||
bd_addr_to_str(channel->address), channel->con_handle, channel->psm, channel->local_cid, channel->remote_cid);
|
||||
uint8_t event[16];
|
||||
@ -225,16 +241,6 @@ void l2cap_emit_connection_request(l2cap_channel_t *channel) {
|
||||
l2cap_dispatch_to_channel(channel, HCI_EVENT_PACKET, event, sizeof(event));
|
||||
}
|
||||
|
||||
static void l2cap_emit_can_send_now(btstack_packet_handler_t packet_handler, uint16_t channel) {
|
||||
log_info("L2CAP_EVENT_CHANNEL_CAN_SEND_NOW local_cid 0x%x", channel);
|
||||
uint8_t event[4];
|
||||
event[0] = L2CAP_EVENT_CAN_SEND_NOW;
|
||||
event[1] = sizeof(event) - 2;
|
||||
little_endian_store_16(event, 2, channel);
|
||||
hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
|
||||
packet_handler(HCI_EVENT_PACKET, channel, event, sizeof(event));
|
||||
}
|
||||
|
||||
static void l2cap_emit_connection_parameter_update_response(hci_con_handle_t con_handle, uint16_t result){
|
||||
uint8_t event[6];
|
||||
event[0] = L2CAP_EVENT_CONNECTION_PARAMETER_UPDATE_RESPONSE;
|
||||
@ -246,6 +252,46 @@ static void l2cap_emit_connection_parameter_update_response(hci_con_handle_t con
|
||||
(*l2cap_event_packet_handler)(HCI_EVENT_PACKET, 0, event, sizeof(event));
|
||||
}
|
||||
|
||||
#ifdef ENABLE_LE_DATA_CHANNELS
|
||||
// 1BH2222
|
||||
static void l2cap_emit_le_incoming_connection(l2cap_channel_t *channel) {
|
||||
log_info("L2CAP_EVENT_LE_INCOMING_CONNECTION addr_type %u, addr %s handle 0x%x psm 0x%x local_cid 0x%x remote_cid 0x%x, remote_mtu %u",
|
||||
channel->address_type, bd_addr_to_str(channel->address), channel->con_handle, channel->psm, channel->local_cid, channel->remote_cid, channel->remote_mtu);
|
||||
uint8_t event[19];
|
||||
event[0] = L2CAP_EVENT_LE_INCOMING_CONNECTION;
|
||||
event[1] = sizeof(event) - 2;
|
||||
event[2] = channel->address_type;
|
||||
reverse_bd_addr(channel->address, &event[3]);
|
||||
little_endian_store_16(event, 9, channel->con_handle);
|
||||
little_endian_store_16(event, 11, channel->psm);
|
||||
little_endian_store_16(event, 13, channel->local_cid);
|
||||
little_endian_store_16(event, 15, channel->remote_cid);
|
||||
little_endian_store_16(event, 17, channel->remote_mtu);
|
||||
hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
|
||||
l2cap_dispatch_to_channel(channel, HCI_EVENT_PACKET, event, sizeof(event));
|
||||
}
|
||||
// 11BH22222
|
||||
static void l2cap_emit_le_channel_opened(l2cap_channel_t *channel, uint8_t status) {
|
||||
log_info("L2CAP_EVENT_LE_CHANNEL_OPENED status 0x%x addr_type %u addr %s handle 0x%x psm 0x%x local_cid 0x%x remote_cid 0x%x local_mtu %u, remote_mtu %u",
|
||||
status, channel->address_type, bd_addr_to_str(channel->address), channel->con_handle, channel->psm,
|
||||
channel->local_cid, channel->remote_cid, channel->local_mtu, channel->remote_mtu);
|
||||
uint8_t event[22];
|
||||
event[0] = L2CAP_EVENT_LE_CHANNEL_OPENED;
|
||||
event[1] = sizeof(event) - 2;
|
||||
event[2] = status;
|
||||
event[3] = channel->address_type;
|
||||
reverse_bd_addr(channel->address, &event[4]);
|
||||
little_endian_store_16(event, 10, channel->con_handle);
|
||||
little_endian_store_16(event, 12, channel->psm);
|
||||
little_endian_store_16(event, 14, channel->local_cid);
|
||||
little_endian_store_16(event, 16, channel->remote_cid);
|
||||
little_endian_store_16(event, 18, channel->local_mtu);
|
||||
little_endian_store_16(event, 20, channel->remote_mtu);
|
||||
hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
|
||||
l2cap_dispatch_to_channel(channel, HCI_EVENT_PACKET, event, sizeof(event));
|
||||
}
|
||||
#endif
|
||||
|
||||
static l2cap_channel_t * l2cap_get_channel_for_local_cid(uint16_t local_cid){
|
||||
btstack_linked_list_iterator_t it;
|
||||
btstack_linked_list_iterator_init(&it, &l2cap_channels);
|
||||
@ -756,7 +802,7 @@ static void l2cap_run(void){
|
||||
channel->new_credits_incoming = 0;
|
||||
l2cap_send_le_signaling_packet(channel->con_handle, LE_CREDIT_BASED_CONNECTION_RESPONSE, channel->remote_sig_id, channel->local_cid, channel->local_mtu, 23, channel->credits_incoming, 0);
|
||||
// notify client
|
||||
l2cap_emit_channel_opened(channel, 0);
|
||||
l2cap_emit_le_channel_opened(channel, 0);
|
||||
break;
|
||||
case L2CAP_STATE_WILL_SEND_LE_CONNECTION_RESPONSE_DECLINE:
|
||||
if (!hci_can_send_acl_packet_now(channel->con_handle)) break;
|
||||
@ -808,7 +854,10 @@ static void l2cap_run(void){
|
||||
|
||||
if (channel->send_sdu_pos >= channel->send_sdu_len + 2){
|
||||
channel->send_sdu_buffer = NULL;
|
||||
// TODO: send done event
|
||||
// send done event
|
||||
l2cap_emit_simple_event_with_cid(channel, L2CAP_EVENT_LE_PACKET_SENT);
|
||||
// inform about can send now
|
||||
l2cap_le_notify_channel_can_send(channel);
|
||||
}
|
||||
hci_send_acl_packet_buffer(8 + pos);
|
||||
break;
|
||||
@ -1017,6 +1066,17 @@ static void l2cap_handle_connection_success_for_addr(bd_addr_t address, hci_con_
|
||||
l2cap_run();
|
||||
}
|
||||
|
||||
|
||||
#ifdef ENABLE_LE_DATA_CHANNELS
|
||||
static void l2cap_le_notify_channel_can_send(l2cap_channel_t *channel){
|
||||
if (!channel->waiting_for_can_send_now) return;
|
||||
if (channel->send_sdu_buffer) return;
|
||||
channel->waiting_for_can_send_now = 0;
|
||||
log_info("L2CAP_EVENT_CHANNEL_LE_CAN_SEND_NOW local_cid 0x%x", channel->local_cid);
|
||||
l2cap_emit_simple_event_with_cid(channel, L2CAP_EVENT_LE_CAN_SEND_NOW);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void l2cap_notify_channel_can_send(void){
|
||||
btstack_linked_list_iterator_t it;
|
||||
btstack_linked_list_iterator_init(&it, &l2cap_channels);
|
||||
@ -1028,6 +1088,7 @@ static void l2cap_notify_channel_can_send(void){
|
||||
l2cap_emit_can_send_now(channel->packet_handler, channel->local_cid);
|
||||
}
|
||||
|
||||
|
||||
int i;
|
||||
for (i=0;i<L2CAP_FIXED_CHANNEL_TABLE_SIZE;i++){
|
||||
if (!fixed_channels[i].callback) continue;
|
||||
@ -1158,7 +1219,7 @@ static void l2cap_hci_event_handler(uint8_t packet_type, uint16_t cid, uint8_t *
|
||||
case L2CAP_STATE_WAIT_INCOMING_SECURITY_LEVEL_UPDATE:
|
||||
if (actual_level >= required_level){
|
||||
channel->state = L2CAP_STATE_WAIT_CLIENT_ACCEPT_OR_REJECT;
|
||||
l2cap_emit_connection_request(channel);
|
||||
l2cap_emit_incoming_connection(channel);
|
||||
} else {
|
||||
channel->reason = 0x0003; // security block
|
||||
channel->state = L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_DECLINE;
|
||||
@ -1605,7 +1666,7 @@ static int l2cap_le_signaling_handler_dispatch(hci_con_handle_t handle, uint8_t
|
||||
if (channel->state == L2CAP_STATE_WAIT_LE_CONNECTION_RESPONSE){
|
||||
channel->state = L2CAP_STATE_CLOSED;
|
||||
// no official value for this, use: Connection refused – LE_PSM not supported - 0x0002
|
||||
l2cap_emit_channel_opened(channel, 0x0002);
|
||||
l2cap_emit_le_channel_opened(channel, 0x0002);
|
||||
|
||||
// discard channel
|
||||
btstack_linked_list_remove(&l2cap_le_channels, (btstack_linked_item_t *) channel);
|
||||
@ -1701,7 +1762,7 @@ static int l2cap_le_signaling_handler_dispatch(hci_con_handle_t handle, uint8_t
|
||||
btstack_linked_list_add(&l2cap_le_channels, (btstack_linked_item_t *) channel);
|
||||
|
||||
// post connection request event
|
||||
l2cap_emit_connection_request(channel);
|
||||
l2cap_emit_le_incoming_connection(channel);
|
||||
|
||||
} else {
|
||||
// Connection refused – LE_PSM not supported
|
||||
@ -1727,7 +1788,7 @@ static int l2cap_le_signaling_handler_dispatch(hci_con_handle_t handle, uint8_t
|
||||
if (result){
|
||||
channel->state = L2CAP_STATE_CLOSED;
|
||||
// map l2cap connection response result to BTstack status enumeration
|
||||
l2cap_emit_channel_opened(channel, result);
|
||||
l2cap_emit_le_channel_opened(channel, result);
|
||||
|
||||
// discard channel
|
||||
btstack_linked_list_remove(&l2cap_le_channels, (btstack_linked_item_t *) channel);
|
||||
@ -1741,7 +1802,7 @@ static int l2cap_le_signaling_handler_dispatch(hci_con_handle_t handle, uint8_t
|
||||
channel->remote_mps = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET + 4);
|
||||
channel->credits_outgoing = little_endian_read_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET + 6);
|
||||
channel->state = L2CAP_STATE_OPEN;
|
||||
l2cap_emit_channel_opened(channel, result);
|
||||
l2cap_emit_le_channel_opened(channel, result);
|
||||
break;
|
||||
|
||||
case LE_FLOW_CONTROL_CREDIT:
|
||||
@ -1901,9 +1962,8 @@ void l2cap_finialize_channel_close(l2cap_channel_t * channel){
|
||||
// finalize closed channel - l2cap_handle_disconnect_request & DISCONNECTION_RESPONSE
|
||||
void l2cap_le_finialize_channel_close(l2cap_channel_t * channel){
|
||||
channel->state = L2CAP_STATE_CLOSED;
|
||||
l2cap_emit_channel_closed(channel);
|
||||
l2cap_emit_simple_event_with_cid(channel, L2CAP_EVENT_CHANNEL_CLOSED);
|
||||
// discard channel
|
||||
l2cap_stop_rtx(channel);
|
||||
btstack_linked_list_remove(&l2cap_le_channels, (btstack_linked_item_t *) channel);
|
||||
btstack_memory_l2cap_channel_free(channel);
|
||||
}
|
||||
@ -2156,8 +2216,20 @@ uint8_t l2cap_le_provide_credits(uint16_t local_cid, uint16_t credits){
|
||||
* @param local_cid L2CAP LE Data Channel Identifier
|
||||
*/
|
||||
int l2cap_le_can_send_now(uint16_t local_cid){
|
||||
// check if data can be sent via le at all
|
||||
return 0;
|
||||
l2cap_channel_t * channel = l2cap_le_get_channel_for_local_cid(local_cid);
|
||||
if (!channel) {
|
||||
log_error("l2cap_le_provide_credits no channel for cid 0x%02x", local_cid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// check state
|
||||
if (channel->state != L2CAP_STATE_OPEN) return 0;
|
||||
|
||||
// check queue
|
||||
if (channel->send_sdu_buffer) return 0;
|
||||
|
||||
// fine, go ahead
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2167,7 +2239,13 @@ int l2cap_le_can_send_now(uint16_t local_cid){
|
||||
* @param local_cid L2CAP LE Data Channel Identifier
|
||||
*/
|
||||
uint8_t l2cap_le_request_can_send_now_event(uint16_t local_cid){
|
||||
// same as for non-le
|
||||
l2cap_channel_t * channel = l2cap_le_get_channel_for_local_cid(local_cid);
|
||||
if (!channel) {
|
||||
log_error("l2cap_le_request_can_send_now_event no channel for cid 0x%02x", local_cid);
|
||||
return 0;
|
||||
}
|
||||
channel->waiting_for_can_send_now = 1;
|
||||
l2cap_le_notify_channel_can_send(channel);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -374,7 +374,7 @@ uint8_t l2cap_le_create_channel(btstack_packet_handler_t packet_handler, hci_con
|
||||
uint8_t l2cap_le_provide_credits(uint16_t cid, uint16_t credits);
|
||||
|
||||
/**
|
||||
* @brief Check if outgoing buffer is available and that there's space on the Bluetooth module
|
||||
* @brief Check if packet can be scheduled for transmission
|
||||
* @param local_cid L2CAP LE Data Channel Identifier
|
||||
*/
|
||||
int l2cap_le_can_send_now(uint16_t cid);
|
||||
|
@ -87,6 +87,8 @@ static uint16_t initial_credits = L2CAP_LE_AUTOMATIC_CREDITS;
|
||||
const char * data_short = "a";
|
||||
const char * data_long = "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||
const char * data_classic = "ABCDEF";
|
||||
static int todo_send_short;
|
||||
static int todo_send_long;
|
||||
|
||||
static uint8_t buffer_x[1000];
|
||||
|
||||
@ -141,31 +143,60 @@ static void app_packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *
|
||||
case HCI_EVENT_DISCONNECTION_COMPLETE:
|
||||
break;
|
||||
|
||||
// Classic
|
||||
case L2CAP_EVENT_INCOMING_CONNECTION:
|
||||
psm = little_endian_read_16(packet, 10);
|
||||
cid = little_endian_read_16(packet, 12);
|
||||
switch (psm){
|
||||
case TSPX_psm:
|
||||
printf("L2CAP: Accepting incoming Classic connection request for 0x%02x, PSM %02x\n", cid, psm);
|
||||
l2cap_accept_connection(cid);
|
||||
break;
|
||||
case TSPX_le_psm:
|
||||
printf("L2CAP: Accepting incoming LE connection request for 0x%02x, PSM %02x\n", cid, psm);
|
||||
l2cap_le_accept_connection(cid, receive_buffer_X, sizeof(receive_buffer_X), initial_credits);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
psm = l2cap_event_incoming_connection_get_psm(packet);
|
||||
cid = l2cap_event_incoming_connection_get_local_cid(packet);
|
||||
if (psm != TSPX_psm) break;
|
||||
printf("L2CAP: Accepting incoming Classic connection request for 0x%02x, PSM %02x\n", cid, psm);
|
||||
l2cap_le_accept_connection(cid, receive_buffer_X, sizeof(receive_buffer_X), initial_credits);
|
||||
break;
|
||||
|
||||
case L2CAP_EVENT_CHANNEL_OPENED:
|
||||
// inform about new l2cap connection
|
||||
reverse_bd_addr(&packet[3], event_address);
|
||||
psm = little_endian_read_16(packet, 11);
|
||||
cid = little_endian_read_16(packet, 13);
|
||||
handle = little_endian_read_16(packet, 9);
|
||||
l2cap_event_channel_opened_get_address(packet, event_address);
|
||||
psm = l2cap_event_channel_opened_get_psm(packet);
|
||||
cid = l2cap_event_channel_opened_get_local_cid(packet);
|
||||
handle = l2cap_event_channel_opened_get_handle(packet);
|
||||
if (packet[2] == 0) {
|
||||
printf("L2CAP: Channel successfully opened: %s, handle 0x%02x, psm 0x%02x, local cid 0x%02x, remote cid 0x%02x\n",
|
||||
printf("L2CAP: Classic Channel successfully opened: %s, handle 0x%02x, psm 0x%02x, local cid 0x%02x, remote cid 0x%02x\n",
|
||||
bd_addr_to_str(event_address), handle, psm, cid, l2cap_event_channel_opened_get_remote_cid(packet));
|
||||
switch (psm){
|
||||
case TSPX_le_psm:
|
||||
cid_le = cid;
|
||||
break;
|
||||
case TSPX_psm:
|
||||
cid_classic = cid;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
printf("L2CAP: classic connection to device %s failed. status code %u\n", bd_addr_to_str(event_address), packet[2]);
|
||||
}
|
||||
break;
|
||||
case L2CAP_EVENT_CHANNEL_CLOSED:
|
||||
cid = l2cap_event_channel_closed_get_local_cid(packet);
|
||||
printf("L2CAP: Clasic Channel closed 0x%02x\n", cid);
|
||||
break;
|
||||
|
||||
// LE Data Channels
|
||||
case L2CAP_EVENT_LE_INCOMING_CONNECTION:
|
||||
psm = l2cap_event_le_incoming_connection_get_psm(packet);
|
||||
cid = l2cap_event_le_incoming_connection_get_local_cid(packet);
|
||||
if (psm != TSPX_le_psm) break;
|
||||
printf("L2CAP: Accepting incoming LE connection request for 0x%02x, PSM %02x\n", cid, psm);
|
||||
l2cap_le_accept_connection(cid, receive_buffer_X, sizeof(receive_buffer_X), initial_credits);
|
||||
break;
|
||||
|
||||
|
||||
case L2CAP_EVENT_LE_CHANNEL_OPENED:
|
||||
// inform about new l2cap connection
|
||||
l2cap_event_le_channel_opened_get_address(packet, event_address);
|
||||
psm = l2cap_event_le_channel_opened_get_psm(packet);
|
||||
cid = l2cap_event_le_channel_opened_get_local_cid(packet);
|
||||
handle = l2cap_event_le_channel_opened_get_handle(packet);
|
||||
if (packet[2] == 0) {
|
||||
printf("L2CAP: LE Data Channel successfully opened: %s, handle 0x%02x, psm 0x%02x, local cid 0x%02x, remote cid 0x%02x\n",
|
||||
bd_addr_to_str(event_address), handle, psm, cid, little_endian_read_16(packet, 15));
|
||||
switch (psm){
|
||||
case TSPX_le_psm:
|
||||
@ -178,13 +209,30 @@ static void app_packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
printf("L2CAP: connection to device %s failed. status code %u\n", bd_addr_to_str(event_address), packet[2]);
|
||||
printf("L2CAP: LE Data Channel connection to device %s failed. status code %u\n", bd_addr_to_str(event_address), packet[2]);
|
||||
}
|
||||
break;
|
||||
|
||||
case L2CAP_EVENT_CHANNEL_CLOSED:
|
||||
cid = l2cap_event_channel_closed_get_local_cid(packet);
|
||||
printf("L2CAP: Channel closed 0x%02x\n", cid);
|
||||
case L2CAP_EVENT_LE_CAN_SEND_NOW:
|
||||
if (todo_send_short){
|
||||
todo_send_short = 0;
|
||||
l2cap_le_send_data(cid_le, (uint8_t *) data_short, strlen(data_short));
|
||||
break;
|
||||
}
|
||||
if (todo_send_long){
|
||||
todo_send_long = 0;
|
||||
l2cap_le_send_data(cid_le, (uint8_t *) data_long, strlen(data_long));
|
||||
}
|
||||
break;
|
||||
|
||||
case L2CAP_EVENT_LE_CHANNEL_CLOSED:
|
||||
cid = l2cap_event_le_channel_closed_get_local_cid(packet);
|
||||
printf("L2CAP: LE Data Channel closed 0x%02x\n", cid);
|
||||
break;
|
||||
|
||||
case L2CAP_EVENT_LE_PACKET_SENT:
|
||||
cid = l2cap_event_le_packet_sent_get_local_cid(packet);
|
||||
printf("L2CAP: LE Data Channel Packet sent0x%02x\n", cid);
|
||||
break;
|
||||
|
||||
case SM_EVENT_JUST_WORKS_REQUEST:
|
||||
@ -267,6 +315,7 @@ static void stdin_process(btstack_data_source_t *ds, btstack_data_source_callbac
|
||||
switch (buffer){
|
||||
case 'a':
|
||||
printf("Direct Connection Establishment to type %u, addr %s\n", pts_address_type, bd_addr_to_str(pts_address));
|
||||
gap_advertisements_enable(0); // controller with single role cannot create connection while advertising
|
||||
gap_connect(pts_address, pts_address_type);
|
||||
break;
|
||||
|
||||
@ -294,12 +343,14 @@ static void stdin_process(btstack_data_source_t *ds, btstack_data_source_callbac
|
||||
|
||||
case 's':
|
||||
printf("Send L2CAP Data Short %s\n", data_short);
|
||||
l2cap_le_send_data(cid_le, (uint8_t *) data_short, strlen(data_short));
|
||||
todo_send_short = 1;
|
||||
l2cap_le_request_can_send_now_event(cid_le);
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
printf("Send L2CAP Data Long %s\n", data_long);
|
||||
l2cap_le_send_data(cid_le, (uint8_t *) data_long, strlen(data_long));
|
||||
todo_send_long = 1;
|
||||
l2cap_le_request_can_send_now_event(cid_le);
|
||||
break;
|
||||
|
||||
case 'y':
|
||||
|
Loading…
x
Reference in New Issue
Block a user