#define PROFILE_NUM 1 #define PROFILE_APP_IDX 0 #define LED_CHAR_UUID 0x0100 #define LED_CHAR_PROP (ESP_GATT_CHAR_PROP_BIT_WRITE | ESP_GATT_CHAR_PROP_BIT_READ) #define LED_CHAR_DESCR_UUID 0x0101 #define LED_SERVICE_UUID 0x00FF #define LED_VALUE_LEN 1 static uint8_t led_value = 0; static uint8_t led_char_descr[ESP_UUID_LEN_16] = { ESP_UUID_16(LED_CHAR_DESCR_UUID), ESP_UUID_16(ESP_GATT_UUID_CHAR_CLIENT_CONFIG), }; static esp_ble_adv_data_t adv_data = { .set_scan_rsp = false, .include_name = true, .include_txpower = true, .min_interval = 0x20, .max_interval = 0x40, .appearance = 0x00, .manufacturer_len = 0, .p_manufacturer_data = NULL, .service_data_len = 0, .p_service_data = NULL, .service_uuid_len = sizeof(LED_SERVICE_UUID), .p_service_uuid = (uint8_t *)&LED_SERVICE_UUID, .flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT), }; static esp_ble_adv_params_t adv_params = { .adv_int_min = 0x20, .adv_int_max = 0x40, .adv_type = ADV_TYPE_NONCONN_IND, .own_addr_type = BLE_ADDR_TYPE_PUBLIC, .channel_map = ADV_CHNL_ALL, .adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY, }; static esp_gatts_attr_db_t gatt_db[1] = { [0] = { .att_desc = { .uuid_length = ESP_UUID_LEN_16, .uuid_p = (uint8_t *)&LED_CHAR_UUID, .perm = ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE, .max_length = LED_VALUE_LEN, .length = LED_VALUE_LEN, }, .desc = { .uuid_length = ESP_UUID_LEN_16, .uuid_p = (uint8_t *)&LED_CHAR_DESCR_UUID, .perm = ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE, .max_length = sizeof(uint16_t), .length = sizeof(uint16_t), .value = (uint8_t *)&led_char_descr, }, .attr_control = { .auto_rsp = ESP_GATT_AUTO_RSP, }, }, }; static esp_gatts_attr_db_t *gatt_db_ptr = gatt_db; static esp_gatts_service_t gatt_service = { .uuid = { .len = ESP_UUID_LEN_16, .uuid = (uint8_t *)&LED_SERVICE_UUID, }, .num_handle = 1, .handle = NULL, .end_handle = NULL, .type = ESP_GATT_SVC_TYPE_PRIMARY, .parent = NULL, .desc = { .uuid_length = 0, .uuid_p = NULL, .perm = 0, .max_length = 0, .length = 0, .value = NULL, }, .srvc_db = gatt static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) { switch (event) { case ESP_GATTS_REG_EVT: esp_ble_gap_set_device_name("LED Control"); esp_ble_gap_config_adv_data(&adv_data); esp_ble_gatts_create_service(gatts_if, &gatt_service, PROFILE_NUM); break; case ESP_GATTS_READ_EVT: if (param->read.handle == gatt_db[0].att_desc.handle) { esp_ble_gatts_send_response(gatts_if, param->read.conn_id, param->read.trans_id, ESP_GATT_OK, &led_value, sizeof(led_value)); } break; case ESP_GATTS_WRITE_EVT: if (param->write.handle == gatt_db[0].att_desc.handle) { led_value = *param->write.value; update_led_brightness(led_value); esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, ESP_GATT_OK, NULL, 0); } break; case ESP_GATTS_CREAT_ATTR_TAB_EVT: if (param->add_attr_tab.status != ESP_GATT_OK) { break; } gatt_db_ptr[0].att_desc.handle = param->add_attr_tab.handles[0]; gatt_db_ptr[0].desc.handle = param->add_attr_tab.handles[1]; esp_ble_gatts_start_service(gatt_db_ptr[0].att_desc.handle); break; case ESP_GATTS_CONNECT_EVT: esp_ble_gap_stop_advertising(); break; case ESP_GATTS_DISCONNECT_EVT: esp_ble_gap_start_advertising(&adv_params); break; default: break; } } void app_main() { gpio_set_direction(LED_PIN, GPIO_MODE_OUTPUT); gpio_set_direction(BUTTON_A_PIN, GPIO_MODE_INPUT); gpio_set_direction(BUTTON_B_PIN, GPIO_MODE_INPUT); gpio_set_direction(BUTTON_C_PIN, GPIO_MODE_INPUT); esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); esp_bt_controller_init(&bt_cfg); esp_bt_controller_enable(ESP_BT_MODE_BLE); esp esp_bluedroid_init(); esp_bluedroid_enable(); esp_gap_ble_set_device_name("LED Control"); esp_gap_ble_set_advertise_mode(ESP_BLE_ADV_TYPE_ADV_IND); esp_gap_ble_add_service_uuid(&gatt_service_id); esp_gap_ble_set_adv_data(&adv_data); esp_gap_ble_start_advertising(&adv_params); esp_ble_gatts_register_callback(gatts_event_handler); esp_ble_gatts_app_register(PROFILE_NUM); while (1) { if (gpio_get_level(BUTTON_A_PIN) == 0) { increase_led_brightness(); } if (gpio_get_level(BUTTON_B_PIN) == 0) { decrease_led_brightness(); } if (gpio_get_level(BUTTON_C_PIN) == 0) { toggle_led(); } vTaskDelay(50 / portTICK_PERIOD_MS); } }