int l2cap_send_prepared_connectionless(uint16_t handle, uint16_t cid, uint16_t len){ if (!hci_can_send_packet_now(HCI_ACL_DATA_PACKET)){ log_info("l2cap_send_prepared_to_handle cid %u, cannot send\n", cid); return BTSTACK_ACL_BUFFERS_FULL; } log_debug("l2cap_send_prepared_to_handle cid %u, handle %u\n", cid, handle); uint8_t *acl_buffer = hci_get_outgoing_acl_packet_buffer(); // 0 - Connection handle : PB=10 : BC=00 bt_store_16(acl_buffer, 0, handle | (2 << 12) | (0 << 14)); // 2 - ACL length bt_store_16(acl_buffer, 2, len + 4); // 4 - L2CAP packet length bt_store_16(acl_buffer, 4, len + 0); // 6 - L2CAP channel DEST bt_store_16(acl_buffer, 6, cid); // send int err = hci_send_acl_packet(acl_buffer, len+8); l2cap_hand_out_credits(); return err; }
static void att_try_respond(void){ if (!att_response_size) return; if (!att_response_handle) return; if (!hci_can_send_packet_now(HCI_ACL_DATA_PACKET)) return; // update state before sending packet uint16_t size = att_response_size; att_response_size = 0; l2cap_send_connectionless(att_response_handle, L2CAP_CID_ATTRIBUTE_PROTOCOL, att_response_buffer, size); }
int l2cap_send_connectionless(uint16_t handle, uint16_t cid, uint8_t *data, uint16_t len){ if (!hci_can_send_packet_now(HCI_ACL_DATA_PACKET)){ log_info("l2cap_send_internal cid %u, cannot send\n", cid); return BTSTACK_ACL_BUFFERS_FULL; } uint8_t *acl_buffer = hci_get_outgoing_acl_packet_buffer(); memcpy(&acl_buffer[8], data, len); return l2cap_send_prepared_connectionless(handle, cid, len); }
int l2cap_send_signaling_packet(hci_con_handle_t handle, L2CAP_SIGNALING_COMMANDS cmd, uint8_t identifier, ...){ if (!hci_can_send_packet_now(HCI_ACL_DATA_PACKET)){ log_info("l2cap_send_signaling_packet, cannot send\n"); return BTSTACK_ACL_BUFFERS_FULL; } // log_info("l2cap_send_signaling_packet type %u\n", cmd); uint8_t *acl_buffer = hci_get_outgoing_acl_packet_buffer(); va_list argptr; va_start(argptr, identifier); uint16_t len = l2cap_create_signaling_internal(acl_buffer, handle, cmd, identifier, argptr); va_end(argptr); // log_info("l2cap_send_signaling_packet con %u!\n", handle); return hci_send_acl_packet(acl_buffer, len); }
int l2cap_send_prepared(uint16_t local_cid, uint16_t len){ if (!hci_can_send_packet_now(HCI_ACL_DATA_PACKET)){ log_info("l2cap_send_internal cid %u, cannot send\n", local_cid); return BTSTACK_ACL_BUFFERS_FULL; } l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid); if (!channel) { log_error("l2cap_send_internal no channel for cid %u\n", local_cid); return -1; // TODO: define error } if (channel->packets_granted == 0){ log_error("l2cap_send_internal cid %u, no credits!\n", local_cid); return -1; // TODO: define error } --channel->packets_granted; log_debug("l2cap_send_internal cid %u, handle %u, 1 credit used, credits left %u;\n", local_cid, channel->handle, channel->packets_granted); uint8_t *acl_buffer = hci_get_outgoing_acl_packet_buffer(); // 0 - Connection handle : PB=10 : BC=00 bt_store_16(acl_buffer, 0, channel->handle | (2 << 12) | (0 << 14)); // 2 - ACL length bt_store_16(acl_buffer, 2, len + 4); // 4 - L2CAP packet length bt_store_16(acl_buffer, 4, len + 0); // 6 - L2CAP channel DEST bt_store_16(acl_buffer, 6, channel->remote_cid); // send int err = hci_send_acl_packet(acl_buffer, len+8); l2cap_hand_out_credits(); return err; }
void hci_run(){ hci_connection_t * connection; linked_item_t * it; if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return; // global/non-connection oriented commands // decline incoming connections if (hci_stack.decline_reason){ uint8_t reason = hci_stack.decline_reason; hci_stack.decline_reason = 0; hci_send_cmd(&hci_reject_connection_request, hci_stack.decline_addr, reason); } if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return; // send scan enable if (hci_stack.new_scan_enable_value != 0xff){ hci_send_cmd(&hci_write_scan_enable, hci_stack.new_scan_enable_value); hci_stack.new_scan_enable_value = 0xff; } // send pending HCI commands for (it = (linked_item_t *) hci_stack.connections; it ; it = it->next){ if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return; connection = (hci_connection_t *) it; if (connection->state == RECEIVED_CONNECTION_REQUEST){ log_info("sending hci_accept_connection_request\n"); hci_send_cmd(&hci_accept_connection_request, connection->address, 1); connection->state = ACCEPTED_CONNECTION_REQUEST; } if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return; if (connection->authentication_flags & HANDLE_LINK_KEY_REQUEST){ link_key_t link_key; log_info("responding to link key request\n"); if ( hci_stack.remote_device_db->get_link_key( &connection->address, &link_key)){ hci_send_cmd(&hci_link_key_request_reply, connection->address, &link_key); } else { hci_send_cmd(&hci_link_key_request_negative_reply, connection->address); } connection->authentication_flags &= ~HANDLE_LINK_KEY_REQUEST; } } if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return; switch (hci_stack.state){ case HCI_STATE_INITIALIZING: // log_info("hci_init: substate %u\n", hci_stack.substate); if (hci_stack.substate % 2) { // odd: waiting for command completion return; } switch (hci_stack.substate >> 1){ case 0: // RESET hci_send_cmd(&hci_reset); if (hci_stack.config == 0 || ((hci_uart_config_t *)hci_stack.config)->baudrate_main == 0){ // skip baud change hci_stack.substate = 4; // >> 1 = 2 } break; case 1: // SEND BAUD CHANGE hci_stack.control->baudrate_cmd(hci_stack.config, ((hci_uart_config_t *)hci_stack.config)->baudrate_main, hci_stack.hci_packet_buffer); hci_send_cmd_packet(hci_stack.hci_packet_buffer, 3 + hci_stack.hci_packet_buffer[2]); break; case 2: // LOCAL BAUD CHANGE hci_stack.hci_transport->set_baudrate(((hci_uart_config_t *)hci_stack.config)->baudrate_main); hci_stack.substate += 2; // break missing here for fall through case 3: // custom initialization if (hci_stack.control && hci_stack.control->next_cmd){ int valid_cmd = (*hci_stack.control->next_cmd)(hci_stack.config, hci_stack.hci_packet_buffer); if (valid_cmd){ int size = 3 + hci_stack.hci_packet_buffer[2]; hci_stack.hci_transport->send_packet(HCI_COMMAND_DATA_PACKET, hci_stack.hci_packet_buffer, size); hci_stack.substate = 4; // more init commands break; } log_info("hci_run: init script done\n\r"); } // otherwise continue hci_send_cmd(&hci_read_bd_addr); break; case 4: hci_send_cmd(&hci_read_buffer_size); break; case 5: // ca. 15 sec hci_send_cmd(&hci_write_page_timeout, 0x6000); break; case 6: hci_send_cmd(&hci_write_scan_enable, 2 | hci_stack.discoverable); // page scan break; case 7: #ifndef EMBEDDED { char hostname[30]; gethostname(hostname, 30); hostname[29] = '\0'; hci_send_cmd(&hci_write_local_name, hostname); break; } case 8: #ifdef USE_BLUETOOL hci_send_cmd(&hci_write_class_of_device, 0x007a020c); // Smartphone break; case 9: #endif #endif // done. hci_stack.state = HCI_STATE_WORKING; hci_emit_state(); break; default: break; } hci_stack.substate++; break; case HCI_STATE_HALTING: log_info("HCI_STATE_HALTING\n"); // close all open connections connection = (hci_connection_t *) hci_stack.connections; if (connection){ // send disconnect if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return; log_info("HCI_STATE_HALTING, connection %p, handle %u\n", connection, (uint16_t)connection->con_handle); hci_send_cmd(&hci_disconnect, connection->con_handle, 0x13); // remote closed connection // send disconnected event right away - causes higher layer connections to get closed, too. hci_shutdown_connection(connection); return; } log_info("HCI_STATE_HALTING, calling off\n"); // switch mode hci_power_control_off(); log_info("HCI_STATE_HALTING, emitting state\n"); hci_emit_state(); log_info("HCI_STATE_HALTING, done\n"); break; case HCI_STATE_FALLING_ASLEEP: switch(hci_stack.substate) { case 0: log_info("HCI_STATE_FALLING_ASLEEP\n"); // close all open connections connection = (hci_connection_t *) hci_stack.connections; #if defined(USE_POWERMANAGEMENT) && defined(USE_BLUETOOL) // don't close connections, if H4 supports power management if (bt_control_iphone_power_management_enabled()){ connection = NULL; } #endif if (connection){ // send disconnect if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return; log_info("HCI_STATE_FALLING_ASLEEP, connection %p, handle %u\n", connection, (uint16_t)connection->con_handle); hci_send_cmd(&hci_disconnect, connection->con_handle, 0x13); // remote closed connection // send disconnected event right away - causes higher layer connections to get closed, too. hci_shutdown_connection(connection); return; } // disable page and inquiry scan if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return; log_info("HCI_STATE_HALTING, disabling inq & page scans\n"); hci_send_cmd(&hci_write_scan_enable, 0); // none // continue in next sub state hci_stack.substate++; break; case 1: // wait for command complete "hci_write_scan_enable" in event_handler(); break; case 2: log_info("HCI_STATE_HALTING, calling sleep\n"); #if defined(USE_POWERMANAGEMENT) && defined(USE_BLUETOOL) // don't actually go to sleep, if H4 supports power management if (bt_control_iphone_power_management_enabled()){ // SLEEP MODE reached hci_stack.state = HCI_STATE_SLEEPING; hci_emit_state(); break; } #endif // switch mode hci_power_control_sleep(); // changes hci_stack.state to SLEEP hci_emit_state(); break; default: break; } break; default: break; } }
void l2cap_event_handler( uint8_t *packet, uint16_t size ){ bd_addr_t address; hci_con_handle_t handle; l2cap_channel_t * channel; linked_item_t *it; int hci_con_used; switch(packet[0]){ // handle connection complete events case HCI_EVENT_CONNECTION_COMPLETE: bt_flip_addr(address, &packet[5]); if (packet[2] == 0){ handle = READ_BT_16(packet, 3); l2cap_handle_connection_success_for_addr(address, handle); } else { l2cap_handle_connection_failed_for_addr(address, packet[2]); } break; // handle successful create connection cancel command case HCI_EVENT_COMMAND_COMPLETE: if ( COMMAND_COMPLETE_EVENT(packet, hci_create_connection_cancel) ) { if (packet[5] == 0){ bt_flip_addr(address, &packet[6]); // CONNECTION TERMINATED BY LOCAL HOST (0X16) l2cap_handle_connection_failed_for_addr(address, 0x16); } } l2cap_run(); // try sending signaling packets first break; case HCI_EVENT_COMMAND_STATUS: l2cap_run(); // try sending signaling packets first break; // handle disconnection complete events case HCI_EVENT_DISCONNECTION_COMPLETE: // send l2cap disconnect events for all channels on this handle handle = READ_BT_16(packet, 3); it = (linked_item_t *) &l2cap_channels; while (it->next){ l2cap_channel_t * channel = (l2cap_channel_t *) it->next; if ( channel->handle == handle ){ // update prev item before free'ing next element - don't call l2cap_finalize_channel_close it->next = it->next->next; l2cap_emit_channel_closed(channel); btstack_memory_l2cap_channel_free(channel); } else { it = it->next; } } break; case HCI_EVENT_NUMBER_OF_COMPLETED_PACKETS: l2cap_run(); // try sending signaling packets first l2cap_hand_out_credits(); break; // HCI Connection Timeouts case L2CAP_EVENT_TIMEOUT_CHECK: handle = READ_BT_16(packet, 2); if (hci_authentication_active_for_handle(handle)) break; hci_con_used = 0; for (it = (linked_item_t *) l2cap_channels; it ; it = it->next){ channel = (l2cap_channel_t *) it; if (channel->handle == handle) { hci_con_used = 1; } } if (hci_con_used) break; if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) break; hci_send_cmd(&hci_disconnect, handle, 0x13); // remote closed connection break; case DAEMON_EVENT_HCI_PACKET_SENT: for (it = (linked_item_t *) l2cap_channels; it ; it = it->next){ channel = (l2cap_channel_t *) it; if (channel->packet_handler) { (* (channel->packet_handler))(HCI_EVENT_PACKET, channel->local_cid, packet, size); } } if (attribute_protocol_packet_handler) { (*attribute_protocol_packet_handler)(HCI_EVENT_PACKET, 0, packet, size); } if (security_protocol_packet_handler) { (*security_protocol_packet_handler)(HCI_EVENT_PACKET, 0, packet, size); } break; default: break; } // pass on (*packet_handler)(NULL, HCI_EVENT_PACKET, 0, packet, size); }
// MARK: L2CAP_RUN // process outstanding signaling tasks void l2cap_run(void){ // check pending signaling responses while (signaling_responses_pending){ if (!hci_can_send_packet_now(HCI_ACL_DATA_PACKET)) break; hci_con_handle_t handle = signaling_responses[0].handle; uint8_t sig_id = signaling_responses[0].sig_id; uint16_t infoType = signaling_responses[0].data; // INFORMATION_REQUEST uint16_t result = signaling_responses[0].data; // CONNECTION_REQUEST switch (signaling_responses[0].code){ case CONNECTION_REQUEST: l2cap_send_signaling_packet(handle, CONNECTION_RESPONSE, sig_id, 0, 0, result, 0); break; case ECHO_REQUEST: l2cap_send_signaling_packet(handle, ECHO_RESPONSE, sig_id, 0, NULL); break; case INFORMATION_REQUEST: if (infoType == 2) { uint32_t features = 0; // extended features request supported, however no features present l2cap_send_signaling_packet(handle, INFORMATION_RESPONSE, sig_id, infoType, 0, 4, &features); } else { // all other types are not supported l2cap_send_signaling_packet(handle, INFORMATION_RESPONSE, sig_id, infoType, 1, 0, NULL); } break; default: // should not happen break; } // remove first item signaling_responses_pending--; int i; for (i=0; i < signaling_responses_pending; i++){ memcpy(&signaling_responses[i], &signaling_responses[i+1], sizeof(l2cap_signaling_response_t)); } } uint8_t config_options[4]; linked_item_t *it; linked_item_t *next; for (it = (linked_item_t *) l2cap_channels; it ; it = next){ next = it->next; // cache next item as current item might get freed if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) break; if (!hci_can_send_packet_now(HCI_ACL_DATA_PACKET)) break; l2cap_channel_t * channel = (l2cap_channel_t *) it; // log_info("l2cap_run: state %u, var 0x%02x\n", channel->state, channel->state_var); switch (channel->state){ case L2CAP_STATE_WILL_SEND_CREATE_CONNECTION: // send connection request - set state first channel->state = L2CAP_STATE_WAIT_CONNECTION_COMPLETE; // BD_ADDR, Packet_Type, Page_Scan_Repetition_Mode, Reserved, Clock_Offset, Allow_Role_Switch hci_send_cmd(&hci_create_connection, channel->address, hci_usable_acl_packet_types(), 0, 0, 0, 1); break; case L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_DECLINE: l2cap_send_signaling_packet(channel->handle, CONNECTION_RESPONSE, channel->remote_sig_id, 0, 0, channel->reason, 0); // discard channel - l2cap_finialize_channel_close without sending l2cap close event linked_list_remove(&l2cap_channels, (linked_item_t *) channel); // -- remove from list btstack_memory_l2cap_channel_free(channel); break; case L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_ACCEPT: channel->state = L2CAP_STATE_CONFIG; channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ); l2cap_send_signaling_packet(channel->handle, CONNECTION_RESPONSE, channel->remote_sig_id, channel->local_cid, channel->remote_cid, 0, 0); break; case L2CAP_STATE_WILL_SEND_CONNECTION_REQUEST: // success, start l2cap handshake channel->local_sig_id = l2cap_next_sig_id(); channel->state = L2CAP_STATE_WAIT_CONNECT_RSP; l2cap_send_signaling_packet( channel->handle, CONNECTION_REQUEST, channel->local_sig_id, channel->psm, channel->local_cid); break; case L2CAP_STATE_CONFIG: if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP){ channelStateVarClearFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP); channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SENT_CONF_RSP); l2cap_send_signaling_packet(channel->handle, CONFIGURE_RESPONSE, channel->remote_sig_id, channel->remote_cid, 0, 0, 0, NULL); } else if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ){ channelStateVarClearFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ); channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SENT_CONF_REQ); channel->local_sig_id = l2cap_next_sig_id(); config_options[0] = 1; // MTU config_options[1] = 2; // len param bt_store_16( (uint8_t*)&config_options, 2, channel->local_mtu); l2cap_send_signaling_packet(channel->handle, CONFIGURE_REQUEST, channel->local_sig_id, channel->remote_cid, 0, 4, &config_options); } if (l2cap_channel_ready_for_open(channel)){ channel->state = L2CAP_STATE_OPEN; l2cap_emit_channel_opened(channel, 0); // success l2cap_emit_credits(channel, 1); } break; case L2CAP_STATE_WILL_SEND_DISCONNECT_RESPONSE: l2cap_send_signaling_packet( channel->handle, DISCONNECTION_RESPONSE, channel->remote_sig_id, channel->local_cid, channel->remote_cid); l2cap_finialize_channel_close(channel); // -- remove from list break; case L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST: channel->local_sig_id = l2cap_next_sig_id(); channel->state = L2CAP_STATE_WAIT_DISCONNECT; l2cap_send_signaling_packet( channel->handle, DISCONNECTION_REQUEST, channel->local_sig_id, channel->remote_cid, channel->local_cid); break; default: break; } } }
int l2cap_can_send_packet_now(uint16_t local_cid){ l2cap_channel_t *channel = l2cap_get_channel_for_local_cid(local_cid); if (!channel) return 0; if (!channel->packets_granted) return 0; return hci_can_send_packet_now(HCI_ACL_DATA_PACKET); }
static void sm_run(void){ // assert that we can send either one if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return; if (!hci_can_send_packet_now(HCI_ACL_DATA_PACKET)) return; switch (sm_state_responding){ case SM_STATE_C1_GET_RANDOM_A: case SM_STATE_C1_GET_RANDOM_B: hci_send_cmd(&hci_le_rand); sm_state_responding++; return; case SM_STATE_C1_GET_ENC_A: case SM_STATE_C1_GET_ENC_B: break; case SM_STATE_C1_SEND: { uint8_t buffer[17]; buffer[0] = SM_CODE_PAIRING_CONFIRM; memcpy(&buffer[1], sm_s_confirm, 16); l2cap_send_connectionless(sm_response_handle, L2CAP_CID_SECURITY_MANAGER_PROTOCOL, (uint8_t*) buffer, sizeof(buffer)); sm_state_responding = SM_STATE_IDLE; return; } default: break; } // send security manager packet if (sm_response_size){ uint16_t size = sm_response_size; sm_response_size = 0; l2cap_send_connectionless(sm_response_handle, L2CAP_CID_SECURITY_MANAGER_PROTOCOL, (uint8_t*) sm_response_buffer, size); } // send security request if (sm_send_security_request){ sm_send_security_request = 0; uint8_t buffer[2]; buffer[0] = SM_CODE_SECURITY_REQUEST; buffer[1] = SM_AUTHREQ_BONDING; l2cap_send_connectionless(sm_response_handle, L2CAP_CID_SECURITY_MANAGER_PROTOCOL, (uint8_t*) buffer, sizeof(buffer)); return; } if (sm_send_encryption_information){ sm_send_encryption_information = 0; uint8_t buffer[17]; buffer[0] = SM_CODE_ENCRYPTION_INFORMATION; memcpy(&buffer[1], sm_s_ltk, 16); l2cap_send_connectionless(sm_response_handle, L2CAP_CID_SECURITY_MANAGER_PROTOCOL, (uint8_t*) buffer, sizeof(buffer)); return; } if (sm_send_master_identification){ sm_send_master_identification = 0; uint8_t buffer[11]; buffer[0] = SM_CODE_MASTER_IDENTIFICATION; bt_store_16(buffer, 1, sm_s_ediv); memcpy(&buffer[3],sm_s_rand,8); l2cap_send_connectionless(sm_response_handle, L2CAP_CID_SECURITY_MANAGER_PROTOCOL, (uint8_t*) buffer, sizeof(buffer)); return; } if (sm_send_identity_information){ sm_send_identity_information = 0; uint8_t buffer[17]; buffer[0] = SM_CODE_IDENTITY_INFORMATION; memcpy(&buffer[1], sm_s_irk, 16); l2cap_send_connectionless(sm_response_handle, L2CAP_CID_SECURITY_MANAGER_PROTOCOL, (uint8_t*) buffer, sizeof(buffer)); return; } if (sm_send_identity_address_information ){ sm_send_identity_address_information = 0; uint8_t buffer[8]; buffer[0] = SM_CODE_IDENTITY_ADDRESS_INFORMATION; buffer[1] = sm_s_addr_type; BD_ADDR_COPY(&buffer[2], sm_s_address); l2cap_send_connectionless(sm_response_handle, L2CAP_CID_SECURITY_MANAGER_PROTOCOL, (uint8_t*) buffer, sizeof(buffer)); return; } if (sm_send_signing_identification){ sm_send_signing_identification = 0; uint8_t buffer[17]; buffer[0] = SM_CODE_SIGNING_INFORMATION; memcpy(&buffer[1], sm_s_csrk, 16); l2cap_send_connectionless(sm_response_handle, L2CAP_CID_SECURITY_MANAGER_PROTOCOL, (uint8_t*) buffer, sizeof(buffer)); return; } }
static void gap_run(){ // make sure we can send one packet if (todos == 0 || !hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return; printf("todo %x\n", todos); if (todos & DISABLE_ADVERTISEMENTS){ todos &= ~DISABLE_ADVERTISEMENTS; advertisements_enabled = 0; printf("GAP_RUN: disable advertisements\n"); hci_send_cmd(&hci_le_set_advertise_enable, 0); return; } if (todos & SET_ADVERTISEMENT_DATA){ todos &= ~SET_ADVERTISEMENT_DATA; uint8_t adv_data[] = { 2, 0x1, 0x2, 3, 0x03, 0xf0, 0xff, 14, 0x09, 'M','e', 't', 'e', 'o', 'r', 'L', 'E', ' ', 'X','X','X','X','\0' }; const char* addr = (const char*)system_getserial(); sprintf((char*)&adv_data[18], "%02X%02X", addr[4], addr[5]); printf("GAP_RUN: set advertisement data\n"); hexdump(adv_data, sizeof(adv_data)); hci_send_cmd(&hci_le_set_advertising_data, sizeof(adv_data) - 1, adv_data); return; } if (todos & SET_ADVERTISEMENT_PARAMS){ todos &= ~SET_ADVERTISEMENT_PARAMS; uint8_t adv_type; if (advertisements_enabled) adv_type = 0x00; else adv_type = 0x02; bd_addr_t null_addr; memset(null_addr, 0, 6); uint16_t adv_int_min = 0x808; uint16_t adv_int_max = 0x808; switch (adv_type){ case 0: case 2: case 3: hci_send_cmd(&hci_le_set_advertising_parameters, adv_int_min, adv_int_max, adv_type, 0, 0, &null_addr, 0x07, 0x00); break; } return; } if (todos & SET_SCAN_RESPONSE_DATA){ uint8_t scan_data[] = { 2, 0x1, 0x2, 2, 0x11, 3, 17, 0x15, 0xD0, 0x00, 0x2D, 0x12, 0x1E, 0x4B, 0x0F, 0xA4, 0x99, 0x4E, 0xCE, 0xB5, 0x31, 0xF4, 0x05, 0x79 }; printf("GAP_RUN: set scan response data\n"); todos &= ~SET_SCAN_RESPONSE_DATA; hci_send_cmd(&hci_le_set_scan_response_data, sizeof(scan_data), scan_data); return; } if (todos & ENABLE_ADVERTISEMENTS){ printf("GAP_RUN: enable advertisements\n"); todos &= ~ENABLE_ADVERTISEMENTS; advertisements_enabled = 1; hci_send_cmd(&hci_le_set_advertise_enable, 1); return; } }