int btstack_main(int argc, const char * argv[]){ printf("BTstack LE Peripheral starting up...\n"); // set up l2cap_le l2cap_init(); // setup le device db le_device_db_init(); // setup SM: Display only sm_init(); sm_set_io_capabilities(IO_CAPABILITY_DISPLAY_ONLY); sm_set_authentication_requirements( SM_AUTHREQ_BONDING | SM_AUTHREQ_MITM_PROTECTION); // setup ATT server att_server_init(profile_data, att_read_callback, att_write_callback); att_write_queue_init(); att_attributes_init(); att_server_register_packet_handler(app_packet_handler); att_dump_attributes(); btstack_stdin_setup(stdin_process); gap_random_address_set_update_period(300000); gap_random_address_set_mode(GAP_RANDOM_ADDRESS_RESOLVABLE); strcpy(gap_device_name, "BTstack"); sm_set_io_capabilities(IO_CAPABILITY_NO_INPUT_NO_OUTPUT); sm_io_capabilities = "IO_CAPABILITY_NO_INPUT_NO_OUTPUT"; sm_set_authentication_requirements(0); sm_register_oob_data_callback(get_oob_data_callback); sm_set_encryption_key_size_range(sm_min_key_size, 16); sm_test_set_irk(test_irk); // set one-shot timer heartbeat.process = &heartbeat_handler; run_loop_set_timer(&heartbeat, HEARTBEAT_PERIOD_MS); run_loop_add_timer(&heartbeat); // turn on! hci_power_control(HCI_POWER_ON); return 0; }
void setup(void){ /// GET STARTED with BTstack /// btstack_memory_init(); run_loop_init(RUN_LOOP_POSIX); // use logger: format HCI_DUMP_PACKETLOGGER, HCI_DUMP_BLUEZ or HCI_DUMP_STDOUT hci_dump_open("/tmp/hci_dump.pklg", HCI_DUMP_PACKETLOGGER); // init HCI #ifdef HAVE_UART_CSR hci_transport_t * transport = hci_transport_h4_instance(); hci_uart_config_t * config = &hci_uart_config; bt_control_t * control = bt_control_csr_instance(); #elif defined(HAVE_UART_CC256x) hci_transport_t * transport = hci_transport_h4_instance(); hci_uart_config_t * config = &hci_uart_config; bt_control_t * control = bt_control_cc256x_instance(); #else hci_transport_t * transport = hci_transport_usb_instance(); hci_uart_config_t * config = NULL; bt_control_t * control = NULL; #endif remote_device_db_t * remote_db = (remote_device_db_t *) &remote_device_db_memory; hci_init(transport, config, control, remote_db); // set up l2cap_le l2cap_init(); // setup central device db central_device_db_init(); // setup SM: Display only sm_init(); sm_set_io_capabilities(IO_CAPABILITY_DISPLAY_ONLY); sm_set_authentication_requirements( SM_AUTHREQ_BONDING | SM_AUTHREQ_MITM_PROTECTION); // setup ATT server att_server_init(profile_data, att_read_callback, att_write_callback); att_write_queue_init(); att_attributes_init(); att_server_register_packet_handler(app_packet_handler); att_dump_attributes(); }
static void app_packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ switch (packet_type) { case HCI_EVENT_PACKET: switch (packet[0]) { case BTSTACK_EVENT_STATE: // bt stack activated, get started if (packet[2] == HCI_STATE_WORKING) { printf("SM Init completed\n"); todos = SET_ADVERTISEMENT_PARAMS | SET_ADVERTISEMENT_DATA | SET_SCAN_RESPONSE_DATA | ENABLE_ADVERTISEMENTS; update_advertisements(); gap_run(); } break; case HCI_EVENT_LE_META: switch (packet[2]) { case HCI_SUBEVENT_LE_CONNECTION_COMPLETE: advertisements_enabled = 0; handle = READ_BT_16(packet, 4); printf("Connection handle 0x%04x\n", handle); // request connection parameter update - test parameters // l2cap_le_request_connection_parameter_update(READ_BT_16(packet, 4), 20, 1000, 100, 100); break; default: break; } break; case HCI_EVENT_DISCONNECTION_COMPLETE: if (!advertisements_enabled == 0 && gap_discoverable){ todos = ENABLE_ADVERTISEMENTS; } att_attributes_init(); att_write_queue_init(); break; case SM_PASSKEY_INPUT_NUMBER: { // display number sm_event_t * event = (sm_event_t *) packet; memcpy(master_address, event->address, 6); master_addr_type = event->addr_type; printf("\nGAP Bonding %s (%u): Enter 6 digit passkey: '", bd_addr_to_str(master_address), master_addr_type); fflush(stdout); ui_passkey = 0; ui_digits_for_passkey = 6; break; } case SM_PASSKEY_DISPLAY_NUMBER: { // display number sm_event_t * event = (sm_event_t *) packet; printf("\nGAP Bonding %s (%u): Display Passkey '%06u\n", bd_addr_to_str(master_address), master_addr_type, event->passkey); break; } case SM_PASSKEY_DISPLAY_CANCEL: printf("\nGAP Bonding %s (%u): Display cancel\n", bd_addr_to_str(master_address), master_addr_type); break; case SM_AUTHORIZATION_REQUEST: { // auto-authorize connection if requested sm_event_t * event = (sm_event_t *) packet; sm_authorization_grant(event->addr_type, event->address); break; } case ATT_HANDLE_VALUE_INDICATION_COMPLETE: printf("ATT_HANDLE_VALUE_INDICATION_COMPLETE status %u\n", packet[2]); break; default: break; } } gap_run(); }
// write requests static int att_write_callback(uint16_t con_handle, uint16_t attribute_handle, uint16_t transaction_mode, uint16_t offset, uint8_t *buffer, uint16_t buffer_size){ printf("WRITE Callback, handle %04x, mode %u, offset %u, data: ", handle, transaction_mode, offset); printf_hexdump(buffer, buffer_size); uint16_t uuid16 = att_uuid_for_handle(handle); switch (uuid16){ case 0x2902: client_configuration = buffer[0]; client_configuration_handle = handle; printf("Client Configuration set to %u for handle %04x\n", client_configuration, handle); return 0; // ok case 0x2a00: memcpy(gap_device_name, buffer, buffer_size); gap_device_name[buffer_size]=0; printf("Setting device name to '%s'\n", gap_device_name); return 0; case 0x2a01: gap_appearance = READ_BT_16(buffer, 0); printf("Setting appearance to 0x%04x'\n", gap_appearance); return 0; case 0x2a02: gap_privacy = buffer[0]; printf("Setting privacy to 0x%04x'\n", gap_privacy); update_advertisements(); return 0; case 0x2A03: bt_flip_addr(gap_reconnection_address, buffer); printf("Setting Reconnection Address to %s\n", bd_addr_to_str(gap_reconnection_address)); return 0; // handle device name // handle appearance } // check transaction mode int attributes_index; int writes_index; switch (transaction_mode){ case ATT_TRANSACTION_MODE_NONE: attributes_index = att_attribute_for_handle(handle); if (attributes_index < 0){ attributes_index = att_attribute_for_handle(0); if (attributes_index < 0) return 0; // ok, but we couldn't store it (our fault) att_attributes[attributes_index].handle = handle; // not written before uint8_t * att_value; uint16_t att_value_len; if (att_default_value_long){ att_value = (uint8_t*) default_value_long; att_value_len = strlen(default_value_long); } else { att_value = (uint8_t*) default_value_short; att_value_len = strlen(default_value_short); } att_attributes[attributes_index].len = att_value_len; } if (buffer_size > att_attributes[attributes_index].len) return ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LENGTH; att_attributes[attributes_index].len = buffer_size; memcpy(att_attributes[attributes_index].value, buffer, buffer_size); break; case ATT_TRANSACTION_MODE_ACTIVE: writes_index = att_write_queue_for_handle(handle); if (writes_index < 0) return ATT_ERROR_PREPARE_QUEUE_FULL; if (offset > att_write_queues[writes_index].len) return ATT_ERROR_INVALID_OFFSET; if (buffer_size + offset > ATT_VALUE_MAX_LEN) return ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LENGTH; att_write_queues[writes_index].len = buffer_size + offset; memcpy(&(att_write_queues[writes_index].value[offset]), buffer, buffer_size); break; case ATT_TRANSACTION_MODE_EXECUTE: for (writes_index=0 ; writes_index<ATT_NUM_WRITE_QUEUES ; writes_index++){ handle = att_write_queues[writes_index].handle; if (handle == 0) continue; attributes_index = att_attribute_for_handle(handle); if (attributes_index < 0){ attributes_index = att_attribute_for_handle(0); if (attributes_index < 0) continue; att_attributes[attributes_index].handle = handle; } att_attributes[attributes_index].len = att_write_queues[writes_index].len; memcpy(att_attributes[attributes_index].value, att_write_queues[writes_index].value, att_write_queues[writes_index].len); } att_write_queue_init(); break; case ATT_TRANSACTION_MODE_CANCEL: att_write_queue_init(); break; } return 0; }