| #include <stdio.h> |
| #include "pico/stdlib.h" |
| #include "btstack.h" |
| #include "pico/cyw43_arch.h" |
| #include "pico_tft.h" |
| #include "fonts/font_fixedsys_mono_16.h" |
| #include "fonts/font_freemono_mono_bold_24.h" |
| #include "tft_string/tft_string.h" |
| #include "le_central.h" |
| |
| #define BUTTON_PIN 16 |
| |
| #define SERVER_DEVICE_NAME "SM LED" |
| typedef enum { |
| CLIENT_STOP=0, |
| QUERY_SERVICE, |
| QUERY_CHARACTERISTIC_LED_BRIGHTNESS, |
| QUERY_CHARACTERISTIC_LED_SET_BRIGHTNESS, |
| QUERY_CHARACTERISTIC_LED_BRIGHT_SCALE, |
| ENABLE_NOTIFICATION, |
| ENABLE_COMPLETE, |
| CLIENT_CONNECTED, |
| CLIENT_SET_LED_BRIGHTNESS |
| } client_event_query_t; |
| |
| uint16_t led_brightness, led_brightness_scale=10; |
| uint8_t service_uuid128[]={ |
| 0x00,0x00,0x06,0x60,0x37,0xE4,0x4E,0x5D,0x95,0x92,0x69,0x32,0x7D,0x12,0x88,0x40 |
| }; |
| uint8_t char_led_brightness_uuid128[]={ |
| 0x00,0x00,0x06,0x61,0x37,0xE4,0x4E,0x5D,0x95,0x92,0x69,0x32,0x7D,0x12,0x88,0x40 |
| }; |
| uint8_t char_set_led_brightness_uuid128[]={ |
| 0x00,0x00,0x06,0x62,0x37,0xE4,0x4E,0x5D,0x95,0x92,0x69,0x32,0x7D,0x12,0x88,0x40 |
| }; |
| uint8_t char_led_bright_scale_uuid128[]={ |
| 0x00,0x00,0x06,0x63,0x37,0xE4,0x4E,0x5D,0x95,0x92,0x69,0x32,0x7D,0x12,0x88,0x40 |
| }; |
| |
| |
| client_event_query_t client_event_query; |
| |
| gatt_client_notification_t notification_listener_led_birghtness; |
| static hci_con_handle_t connection_handler; |
| gatt_client_service_t led_control_service; |
| gatt_client_characteristic_t char_set_led_brightness, char_led_brightness, char_led_bright_scale; |
| |
| static btstack_packet_callback_registration_t hci_event_callback_registration; |
| static btstack_packet_callback_registration_t sm_event_callback_registration; |
| static void sm_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); |
| static void handle_hci_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); |
| static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); |
| |
| static void tft_show_message(uint8_t *msg); |
| static void tft_show_passkey(uint32_t passkey); |
| static void tft_print_data(); |
| |
| uint32_t get_passkey() { |
| return 123456; |
| } |
| |
| static void sm_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ |
| UNUSED(channel); |
| UNUSED(size); |
| |
| if (packet_type != HCI_EVENT_PACKET) return; |
| |
| bd_addr_t addr; |
| bd_addr_type_t addr_type; |
| |
| switch (hci_event_packet_get_type(packet)) { |
| case SM_EVENT_JUST_WORKS_REQUEST: |
| printf("Just works requested\n"); |
| sm_just_works_confirm(sm_event_just_works_request_get_handle(packet)); |
| break; |
| case SM_EVENT_NUMERIC_COMPARISON_REQUEST: |
| printf("Confirming numeric comparison: %"PRIu32"\n", sm_event_numeric_comparison_request_get_passkey(packet)); |
| sm_numeric_comparison_confirm(sm_event_passkey_display_number_get_handle(packet)); |
| break; |
| case SM_EVENT_PASSKEY_DISPLAY_NUMBER: |
| printf("Display Passkey: %"PRIu32"\n", sm_event_passkey_display_number_get_passkey(packet)); |
| tft_show_passkey(sm_event_passkey_display_number_get_passkey(packet)); |
| break; |
| case SM_EVENT_PASSKEY_INPUT_NUMBER: |
| printf("Passkey Input requested\n"); |
| uint32_t passkey; |
| passkey = get_passkey(); |
| printf("Sending fixed passkey %"PRIu32"\n", passkey); |
| sm_passkey_input(sm_event_passkey_input_number_get_handle(packet), passkey); |
| break; |
| case SM_EVENT_PAIRING_STARTED: |
| printf("Pairing started\n"); |
| break; |
| case SM_EVENT_PAIRING_COMPLETE: |
| switch (sm_event_pairing_complete_get_status(packet)){ |
| case ERROR_CODE_SUCCESS: |
| printf("Pairing complete, success\n"); |
| tft_print_data(); |
| break; |
| case ERROR_CODE_CONNECTION_TIMEOUT: |
| printf("Pairing failed, timeout\n"); |
| tft_show_message("Pairing failed, timeout"); |
| busy_wait_ms(1000); |
| gap_disconnect(connection_handler); |
| break; |
| case ERROR_CODE_REMOTE_USER_TERMINATED_CONNECTION: |
| printf("Pairing failed, disconnected\n"); |
| tft_show_message("Pairing failed, disconnected"); |
| busy_wait_ms(1000); |
| gap_disconnect(connection_handler); |
| break; |
| case ERROR_CODE_AUTHENTICATION_FAILURE: |
| printf("Pairing failed, authentication failure with reason = %u\n", sm_event_pairing_complete_get_reason(packet)); |
| tft_show_message("authentication failure"); |
| busy_wait_ms(1000); |
| gap_disconnect(connection_handler); |
| break; |
| default: |
| break; |
| } |
| break; |
| case SM_EVENT_REENCRYPTION_STARTED: |
| sm_event_reencryption_complete_get_address(packet, addr); |
| printf("Bonding information exists for addr type %u, identity addr %s -> start re-encryption\n", |
| sm_event_reencryption_started_get_addr_type(packet), bd_addr_to_str(addr)); |
| break; |
| case SM_EVENT_REENCRYPTION_COMPLETE: |
| switch (sm_event_reencryption_complete_get_status(packet)){ |
| case ERROR_CODE_SUCCESS: |
| printf("Re-encryption complete, success\n"); |
| tft_print_data(); |
| break; |
| case ERROR_CODE_CONNECTION_TIMEOUT: |
| printf("Re-encryption failed, timeout\n"); |
| tft_show_message("Re-encryption failed"); |
| busy_wait_ms(1000); |
| |
| break; |
| case ERROR_CODE_REMOTE_USER_TERMINATED_CONNECTION: |
| printf("Re-encryption failed, disconnected\n"); |
| tft_show_message("Re-encryption failed"); |
| busy_wait_ms(1000); |
| |
| break; |
| case ERROR_CODE_PIN_OR_KEY_MISSING: |
| printf("Re-encryption failed, bonding information missing\n\n"); |
| printf("Assuming remote lost bonding information\n"); |
| printf("Deleting local bonding information and start new pairing...\n"); |
| tft_show_message("Re-encryption failed"); |
| busy_wait_ms(1000); |
| |
| sm_event_reencryption_complete_get_address(packet, addr); |
| addr_type = sm_event_reencryption_started_get_addr_type(packet); |
| gap_delete_bonding(addr_type, addr); |
| sm_request_pairing(sm_event_reencryption_complete_get_handle(packet)); |
| break; |
| default: |
| break; |
| } |
| break; |
| default: |
| break; |
| } |
| } |
| |
| static void handle_hci_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ |
| UNUSED(channel); |
| UNUSED(size); |
| bd_addr_t addr; |
| bd_addr_type_t addr_type; |
| if (packet_type != HCI_EVENT_PACKET) return; |
| |
| uint8_t event = hci_event_packet_get_type(packet); |
| switch (event) { |
| case BTSTACK_EVENT_STATE: |
| |
| if (btstack_event_state_get_state(packet) != HCI_STATE_WORKING) break; |
| gap_set_scan_parameters(0,0x0030, 0x0030); |
| gap_start_scan(); |
| break; |
| case GAP_EVENT_ADVERTISING_REPORT: |
| tft_show_message("Scan Device..."); |
| const uint8_t * adv_data = gap_event_advertising_report_get_data(packet); |
| uint8_t adv_len = gap_event_advertising_report_get_data_length(packet); |
| if (ad_data_contains_uuid128(adv_len, adv_data, service_uuid128)) { |
| gap_event_advertising_report_get_address(packet, addr); |
| addr_type = gap_event_advertising_report_get_address_type(packet); |
| gap_stop_scan(); |
| gap_connect(addr, addr_type); |
| } |
| break; |
| case HCI_EVENT_LE_META: |
| |
| if (hci_event_le_meta_get_subevent_code(packet) != HCI_SUBEVENT_LE_CONNECTION_COMPLETE) break; |
| connection_handler = hci_subevent_le_connection_complete_get_connection_handle(packet); |
| |
| |
| |
| client_event_query=QUERY_SERVICE; |
| gatt_client_discover_primary_services_by_uuid128(handle_gatt_client_event, connection_handler, |
| service_uuid128); |
| break; |
| case HCI_EVENT_DISCONNECTION_COMPLETE: |
| tft_show_message("Device Disconn"); |
| client_event_query = CLIENT_STOP; |
| gap_start_scan(); |
| break; |
| default: |
| break; |
| } |
| } |
| static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ |
| UNUSED(packet_type); |
| UNUSED(channel); |
| UNUSED(size); |
| uint16_t temp; |
| |
| switch(hci_event_packet_get_type(packet)){ |
| case GATT_EVENT_SERVICE_QUERY_RESULT: |
| gatt_event_service_query_result_get_service(packet, &led_control_service); |
| break; |
| case GATT_EVENT_CHARACTERISTIC_QUERY_RESULT: |
| |
| if (client_event_query == QUERY_CHARACTERISTIC_LED_SET_BRIGHTNESS) { |
| gatt_event_characteristic_query_result_get_characteristic(packet, &char_set_led_brightness); |
| } |
| if (client_event_query == QUERY_CHARACTERISTIC_LED_BRIGHTNESS) { |
| gatt_event_characteristic_query_result_get_characteristic(packet, &char_led_brightness); |
| } |
| if (client_event_query == QUERY_CHARACTERISTIC_LED_BRIGHT_SCALE) { |
| gatt_event_characteristic_query_result_get_characteristic(packet, &char_led_bright_scale); |
| } |
| break; |
| case GATT_EVENT_QUERY_COMPLETE: |
| switch(client_event_query) { |
| case QUERY_SERVICE: |
| client_event_query = QUERY_CHARACTERISTIC_LED_BRIGHTNESS; |
| gatt_client_discover_characteristics_for_service_by_uuid128(handle_gatt_client_event, connection_handler, |
| &led_control_service, char_led_brightness_uuid128); |
| break; |
| case QUERY_CHARACTERISTIC_LED_BRIGHTNESS: |
| client_event_query = QUERY_CHARACTERISTIC_LED_SET_BRIGHTNESS; |
| gatt_client_discover_characteristics_for_service_by_uuid128(handle_gatt_client_event, connection_handler, |
| &led_control_service, char_set_led_brightness_uuid128); |
| break; |
| case QUERY_CHARACTERISTIC_LED_SET_BRIGHTNESS: |
| client_event_query = QUERY_CHARACTERISTIC_LED_BRIGHT_SCALE; |
| gatt_client_discover_characteristics_for_service_by_uuid128(handle_gatt_client_event, connection_handler, |
| &led_control_service,char_led_bright_scale_uuid128); |
| break; |
| case QUERY_CHARACTERISTIC_LED_BRIGHT_SCALE: |
| client_event_query = ENABLE_NOTIFICATION; |
| gatt_client_listen_for_characteristic_value_updates(¬ification_listener_led_birghtness, handle_gatt_client_event, |
| connection_handler, &char_led_brightness); |
| |
| gatt_client_write_client_characteristic_configuration(handle_gatt_client_event, connection_handler, |
| &char_led_brightness, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION); |
| |
| |
| break; |
| |
| case ENABLE_NOTIFICATION: |
| client_event_query = CLIENT_CONNECTED; |
| |
| break; |
| case CLIENT_SET_LED_BRIGHTNESS: |
| |
| break; |
| } |
| break; |
| case GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT: |
| if (char_led_brightness.value_handle == gatt_event_characteristic_value_query_result_get_value_handle(packet)) { |
| led_brightness = little_endian_read_16(gatt_event_characteristic_value_query_result_get_value(packet), 0); |
| |
| tft_print_data(); |
| |
| |
| } |
| |
| break; |
| case GATT_EVENT_NOTIFICATION: |
| |
| if (char_led_brightness.value_handle == gatt_event_notification_get_value_handle(packet)) { |
| |
| led_brightness = little_endian_read_16(gatt_event_notification_get_value(packet), 0); |
| tft_print_data(); |
| |
| client_event_query = CLIENT_CONNECTED; |
| } |
| |
| break; |
| case ATT_EVENT_CAN_SEND_NOW: |
| break; |
| default: |
| break; |
| } |
| } |
| |
| void tft_show_message(uint8_t* msg) { |
| tft_fill_rect(0,0,TFT_WIDTH, TFT_HEIGHT, 0xffff); |
| tft_draw_string(20,5, msg, 0xf800, &font_fixedsys_mono_16); |
| } |
| |
| void tft_show_passkey(uint32_t passkey) { |
| char ts[40]; |
| tft_fill_rect(0,0,TFT_WIDTH, TFT_HEIGHT, 0xffff); |
| tft_draw_string(20,5, "Pairing Code", 0xf800, &font_fixedsys_mono_16); |
| sprintf(ts, "%u", passkey); |
| tft_draw_string(30,40, ts, 0x001f, &font_freemono_mono_bold_24); |
| } |
| void tft_print_data() { |
| char ts[50]; |
| tft_fill_rect(0,0,TFT_WIDTH, TFT_HEIGHT, 0xffff); |
| tft_draw_string(10,5, "LED Birghtness", 0xf800, &font_fixedsys_mono_16); |
| tft_draw_line(4,34,155,34, 0x07e0); |
| tft_draw_line(155,34,155,65, 0x07e0); |
| tft_draw_line(4,65,155,65, 0x07e0); |
| tft_draw_line(4,34,4,65, 0x07e0); |
| tft_fill_rect(5,35,150/led_brightness_scale*led_brightness, 30, 0x001f); |
| |
| sprintf(ts, "%d%c ", (int)((float)led_brightness/(float)led_brightness_scale*100), '%'); |
| tft_draw_string(65,75, ts, 0xf800, &font_fixedsys_mono_16); |
| |
| } |
| void button_pin_press_callback(uint gpio, uint32_t events) { |
| if (gpio == BUTTON_PIN && client_event_query == CLIENT_CONNECTED) { |
| led_brightness++; |
| if (led_brightness > 10) led_brightness=0; |
| client_event_query=CLIENT_SET_LED_BRIGHTNESS; |
| gatt_client_write_value_of_characteristic(handle_gatt_client_event, connection_handler, char_set_led_brightness.value_handle, 2, (uint8_t*)&led_brightness); |
| } |
| } |
| int main() |
| { |
| stdio_init_all(); |
| |
| |
| |
| gpio_init(BUTTON_PIN); |
| gpio_pull_up(BUTTON_PIN); |
| gpio_set_irq_enabled_with_callback(BUTTON_PIN, GPIO_IRQ_LEVEL_LOW , true, &button_pin_press_callback); |
| |
| |
| tft_init(); |
| |
| if (cyw43_arch_init()) { |
| printf("cyw43_init error\n"); |
| return 0; |
| } |
| client_event_query = CLIENT_STOP; |
| |
| l2cap_init(); |
| sm_init(); |
| |
| |
| l2cap_init(); |
| |
| |
| gatt_client_init(); |
| |
| |
| sm_init(); |
| |
| |
| hci_event_callback_registration.callback = &handle_hci_event; |
| hci_add_event_handler(&hci_event_callback_registration); |
| |
| sm_event_callback_registration.callback = &sm_packet_handler; |
| sm_add_event_handler(&sm_event_callback_registration); |
| |
| |
| sm_set_secure_connections_only_mode(true); |
| |
| |
| sm_set_io_capabilities(IO_CAPABILITY_DISPLAY_ONLY); |
| sm_set_authentication_requirements(SM_AUTHREQ_SECURE_CONNECTION|SM_AUTHREQ_MITM_PROTECTION |SM_AUTHREQ_BONDING); |
| |
| |
| hci_power_control(HCI_POWER_ON); |
| while(client_event_query != CLIENT_CONNECTED) { |
| tight_loop_contents(); |
| } |
| gatt_client_write_value_of_characteristic(handle_gatt_client_event, connection_handler, char_led_bright_scale.value_handle, 2, (uint8_t*)&led_brightness_scale); |
| |
| while(1) { |
| |
| |
| tight_loop_contents(); |
| } |
| |
| |
| return 0; |
| } |