From ad7fa5b10e3da7566d4bc69bc20d0847aa051fc6 Mon Sep 17 00:00:00 2001 From: Peter Harper Date: Mon, 7 Jul 2025 18:03:11 +0100 Subject: [PATCH] Simplify standaline BT examples Move client and server to their own folder Get rid of the wifi stuff --- pico_w/bt/standalone/CMakeLists.txt | 70 +---------- pico_w/bt/standalone/client/CMakeLists.txt | 22 ++++ pico_w/bt/standalone/{ => client}/client.c | 0 pico_w/bt/standalone/server.c | 105 ---------------- pico_w/bt/standalone/server/CMakeLists.txt | 19 +++ .../{server_common.c => server/server.c} | 105 +++++++++++++++- .../standalone/{ => server}/temp_sensor.gatt | 0 pico_w/bt/standalone/server_common.h | 22 ---- pico_w/bt/standalone/server_with_wifi.c | 117 ------------------ 9 files changed, 143 insertions(+), 317 deletions(-) create mode 100644 pico_w/bt/standalone/client/CMakeLists.txt rename pico_w/bt/standalone/{ => client}/client.c (100%) delete mode 100644 pico_w/bt/standalone/server.c create mode 100644 pico_w/bt/standalone/server/CMakeLists.txt rename pico_w/bt/standalone/{server_common.c => server/server.c} (59%) rename pico_w/bt/standalone/{ => server}/temp_sensor.gatt (100%) delete mode 100644 pico_w/bt/standalone/server_common.h delete mode 100644 pico_w/bt/standalone/server_with_wifi.c diff --git a/pico_w/bt/standalone/CMakeLists.txt b/pico_w/bt/standalone/CMakeLists.txt index 28d20b687..ef03fe482 100644 --- a/pico_w/bt/standalone/CMakeLists.txt +++ b/pico_w/bt/standalone/CMakeLists.txt @@ -1,68 +1,2 @@ -# Standalone example that reads from the on board temperature sensor and sends notifications via BLE -# Flashes slowly each second to show it's running -add_executable(picow_ble_temp_sensor - server.c server_common.c - ) -target_link_libraries(picow_ble_temp_sensor - pico_stdlib - pico_btstack_ble - pico_btstack_cyw43 - pico_cyw43_arch_none - hardware_adc - ) -target_include_directories(picow_ble_temp_sensor PRIVATE - ${CMAKE_CURRENT_LIST_DIR} # For btstack config - ) -pico_btstack_make_gatt_header(picow_ble_temp_sensor PRIVATE "${CMAKE_CURRENT_LIST_DIR}/temp_sensor.gatt") - -pico_add_extra_outputs(picow_ble_temp_sensor) -example_auto_set_url(picow_ble_temp_sensor) - -# Standalone example that connects to picow_ble_temp_sensor and reads the temperature -# Flahes once quickly each second when it's running but not connected to another device -# Flashes twice quickly each second when connected to another device and reading it's temperature -add_executable(picow_ble_temp_reader - client.c - ) -target_link_libraries(picow_ble_temp_reader - pico_stdlib - pico_btstack_ble - pico_btstack_cyw43 - pico_cyw43_arch_none - hardware_adc - ) -target_include_directories(picow_ble_temp_reader PRIVATE - ${CMAKE_CURRENT_LIST_DIR} # For btstack config - ) -target_compile_definitions(picow_ble_temp_reader PRIVATE - RUNNING_AS_CLIENT=1 -) - -pico_add_extra_outputs(picow_ble_temp_reader) -example_auto_set_url(picow_ble_temp_reader) - -if (WIFI_SSID AND WIFI_PASSWORD) - # Another version of the sensor example, but this time also runs iperf over wifi - add_executable(picow_ble_temp_sensor_with_wifi - server_with_wifi.c server_common.c - ) - target_link_libraries(picow_ble_temp_sensor_with_wifi - pico_stdlib - pico_btstack_ble - pico_btstack_cyw43 - pico_cyw43_arch_lwip_threadsafe_background - pico_lwip_iperf - hardware_adc - ) - target_include_directories(picow_ble_temp_sensor_with_wifi PRIVATE - ${CMAKE_CURRENT_LIST_DIR} # For btstack config - ) - target_compile_definitions(picow_ble_temp_sensor_with_wifi PRIVATE - WIFI_SSID=\"${WIFI_SSID}\" - WIFI_PASSWORD=\"${WIFI_PASSWORD}\" - ) - pico_btstack_make_gatt_header(picow_ble_temp_sensor_with_wifi PRIVATE "${CMAKE_CURRENT_LIST_DIR}/temp_sensor.gatt") - - pico_add_extra_outputs(picow_ble_temp_sensor_with_wifi) - example_auto_set_url(picow_ble_temp_sensor_with_wifi) -endif() +add_subdirectory(client) +add_subdirectory(server) diff --git a/pico_w/bt/standalone/client/CMakeLists.txt b/pico_w/bt/standalone/client/CMakeLists.txt new file mode 100644 index 000000000..8399e0740 --- /dev/null +++ b/pico_w/bt/standalone/client/CMakeLists.txt @@ -0,0 +1,22 @@ +# Standalone example that connects to picow_ble_temp_sensor and reads the temperature +# Flahes once quickly each second when it's running but not connected to another device +# Flashes twice quickly each second when connected to another device and reading it's temperature +add_executable(picow_ble_temp_reader + client.c + ) +target_link_libraries(picow_ble_temp_reader + pico_stdlib + pico_btstack_ble + pico_btstack_cyw43 + pico_cyw43_arch_none + hardware_adc + ) +target_include_directories(picow_ble_temp_reader PRIVATE + ${CMAKE_CURRENT_LIST_DIR}/.. # For btstack config + ) +target_compile_definitions(picow_ble_temp_reader PRIVATE + RUNNING_AS_CLIENT=1 +) + +pico_add_extra_outputs(picow_ble_temp_reader) +example_auto_set_url(picow_ble_temp_reader) diff --git a/pico_w/bt/standalone/client.c b/pico_w/bt/standalone/client/client.c similarity index 100% rename from pico_w/bt/standalone/client.c rename to pico_w/bt/standalone/client/client.c diff --git a/pico_w/bt/standalone/server.c b/pico_w/bt/standalone/server.c deleted file mode 100644 index 567106d84..000000000 --- a/pico_w/bt/standalone/server.c +++ /dev/null @@ -1,105 +0,0 @@ -/** - * Copyright (c) 2023 Raspberry Pi (Trading) Ltd. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include -#include "btstack.h" -#include "pico/cyw43_arch.h" -#include "pico/btstack_cyw43.h" -#include "hardware/adc.h" -#include "pico/stdlib.h" - -#include "server_common.h" - -#define HEARTBEAT_PERIOD_MS 1000 - -static btstack_timer_source_t heartbeat; -static btstack_packet_callback_registration_t hci_event_callback_registration; - -static void heartbeat_handler(struct btstack_timer_source *ts) { - static uint32_t counter = 0; - counter++; - - // Update the temp every 10s - if (counter % 10 == 0) { - poll_temp(); - if (le_notification_enabled) { - att_server_request_can_send_now_event(con_handle); - } - } - - // Invert the led - static int led_on = true; - led_on = !led_on; - cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, led_on); - - // Restart timer - btstack_run_loop_set_timer(ts, HEARTBEAT_PERIOD_MS); - btstack_run_loop_add_timer(ts); -} - -static volatile bool key_pressed; -void key_pressed_func(void *param) { - int key = getchar_timeout_us(0); // get any pending key press but don't wait - if (key == 's' || key == 'S') { - key_pressed = true; - } -} - -int main() { - stdio_init_all(); - -restart: - // initialize CYW43 driver architecture (will enable BT if/because CYW43_ENABLE_BLUETOOTH == 1) - if (cyw43_arch_init()) { - printf("failed to initialise cyw43_arch\n"); - return -1; - } - - // Get notified if the user presses a key - printf("Press the \"S\" key to Stop bluetooth\n"); - stdio_set_chars_available_callback(key_pressed_func, NULL); - - // Initialise adc for the temp sensor - adc_init(); - adc_select_input(ADC_CHANNEL_TEMPSENSOR); - adc_set_temp_sensor_enabled(true); - - l2cap_init(); - sm_init(); - - att_server_init(profile_data, att_read_callback, att_write_callback); - - // inform about BTstack state - hci_event_callback_registration.callback = &packet_handler; - hci_add_event_handler(&hci_event_callback_registration); - - // register for ATT event - att_server_register_packet_handler(packet_handler); - - // set one-shot btstack timer - heartbeat.process = &heartbeat_handler; - btstack_run_loop_set_timer(&heartbeat, HEARTBEAT_PERIOD_MS); - btstack_run_loop_add_timer(&heartbeat); - - // turn on bluetooth! - hci_power_control(HCI_POWER_ON); - - key_pressed = false; - while(!key_pressed) { - async_context_poll(cyw43_arch_async_context()); - async_context_wait_for_work_until(cyw43_arch_async_context(), at_the_end_of_time); - } - - cyw43_arch_deinit(); - - printf("Press the \"S\" key to Start bluetooth\n"); - key_pressed = false; - while(!key_pressed) { - sleep_ms(1000); - } - goto restart; - return 0; -} diff --git a/pico_w/bt/standalone/server/CMakeLists.txt b/pico_w/bt/standalone/server/CMakeLists.txt new file mode 100644 index 000000000..46b9bd795 --- /dev/null +++ b/pico_w/bt/standalone/server/CMakeLists.txt @@ -0,0 +1,19 @@ +# Standalone example that reads from the on board temperature sensor and sends notifications via BLE +# Flashes slowly each second to show it's running +add_executable(picow_ble_temp_sensor + server.c + ) +target_link_libraries(picow_ble_temp_sensor + pico_stdlib + pico_btstack_ble + pico_btstack_cyw43 + pico_cyw43_arch_none + hardware_adc + ) +target_include_directories(picow_ble_temp_sensor PRIVATE + ${CMAKE_CURRENT_LIST_DIR}/.. # For btstack config + ) +pico_btstack_make_gatt_header(picow_ble_temp_sensor PRIVATE "${CMAKE_CURRENT_LIST_DIR}/temp_sensor.gatt") + +pico_add_extra_outputs(picow_ble_temp_sensor) +example_auto_set_url(picow_ble_temp_sensor) diff --git a/pico_w/bt/standalone/server_common.c b/pico_w/bt/standalone/server/server.c similarity index 59% rename from pico_w/bt/standalone/server_common.c rename to pico_w/bt/standalone/server/server.c index fd429196c..eb83a53e6 100644 --- a/pico_w/bt/standalone/server_common.c +++ b/pico_w/bt/standalone/server/server.c @@ -6,12 +6,17 @@ #include #include "btstack.h" +#include "pico/cyw43_arch.h" +#include "pico/btstack_cyw43.h" #include "hardware/adc.h" +#include "pico/stdlib.h" #include "temp_sensor.h" -#include "server_common.h" +#define HEARTBEAT_PERIOD_MS 1000 +#define ADC_CHANNEL_TEMPSENSOR 4 #define APP_AD_FLAGS 0x06 + static uint8_t adv_data[] = { // Flags general discoverable 0x02, BLUETOOTH_DATA_TYPE_FLAGS, APP_AD_FLAGS, @@ -24,6 +29,10 @@ static const uint8_t adv_data_len = sizeof(adv_data); int le_notification_enabled; hci_con_handle_t con_handle; uint16_t current_temp; +static btstack_timer_source_t heartbeat; +static btstack_packet_callback_registration_t hci_event_callback_registration; + +extern uint8_t const profile_data[]; void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) { UNUSED(size); @@ -76,7 +85,7 @@ int att_write_callback(hci_con_handle_t connection_handle, uint16_t att_handle, UNUSED(transaction_mode); UNUSED(offset); UNUSED(buffer_size); - + if (att_handle != ATT_CHARACTERISTIC_ORG_BLUETOOTH_CHARACTERISTIC_TEMPERATURE_01_CLIENT_CONFIGURATION_HANDLE) return 0; le_notification_enabled = little_endian_read_16(buffer, 0) == GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION; con_handle = connection_handle; @@ -97,10 +106,96 @@ void poll_temp(void) { // ref https://github.com/raspberrypi/pico-micropython-examples/blob/master/adc/temperature.py const float conversion_factor = 3.3 / (65535); float reading = raw16 * conversion_factor; - + // The temperature sensor measures the Vbe voltage of a biased bipolar diode, connected to the fifth ADC channel - // Typically, Vbe = 0.706V at 27 degrees C, with a slope of -1.721mV (0.001721) per degree. + // Typically, Vbe = 0.706V at 27 degrees C, with a slope of -1.721mV (0.001721) per degree. float deg_c = 27 - (reading - 0.706) / 0.001721; current_temp = deg_c * 100; printf("Write temp %.2f degc\n", deg_c); - } \ No newline at end of file + } + +static void heartbeat_handler(struct btstack_timer_source *ts) { + static uint32_t counter = 0; + counter++; + + // Update the temp every 10s + if (counter % 10 == 0) { + poll_temp(); + if (le_notification_enabled) { + att_server_request_can_send_now_event(con_handle); + } + } + + // Invert the led + static int led_on = true; + led_on = !led_on; + cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, led_on); + + // Restart timer + btstack_run_loop_set_timer(ts, HEARTBEAT_PERIOD_MS); + btstack_run_loop_add_timer(ts); +} + +static volatile bool key_pressed; +void key_pressed_func(void *param) { + int key = getchar_timeout_us(0); // get any pending key press but don't wait + if (key == 's' || key == 'S') { + key_pressed = true; + } +} + +int main() { + stdio_init_all(); + +restart: + // initialize CYW43 driver architecture (will enable BT if/because CYW43_ENABLE_BLUETOOTH == 1) + if (cyw43_arch_init()) { + printf("failed to initialise cyw43_arch\n"); + return -1; + } + + // Get notified if the user presses a key + printf("Press the \"S\" key to Stop bluetooth\n"); + stdio_set_chars_available_callback(key_pressed_func, NULL); + + // Initialise adc for the temp sensor + adc_init(); + adc_select_input(ADC_CHANNEL_TEMPSENSOR); + adc_set_temp_sensor_enabled(true); + + l2cap_init(); + sm_init(); + + att_server_init(profile_data, att_read_callback, att_write_callback); + + // inform about BTstack state + hci_event_callback_registration.callback = &packet_handler; + hci_add_event_handler(&hci_event_callback_registration); + + // register for ATT event + att_server_register_packet_handler(packet_handler); + + // set one-shot btstack timer + heartbeat.process = &heartbeat_handler; + btstack_run_loop_set_timer(&heartbeat, HEARTBEAT_PERIOD_MS); + btstack_run_loop_add_timer(&heartbeat); + + // turn on bluetooth! + hci_power_control(HCI_POWER_ON); + + key_pressed = false; + while(!key_pressed) { + async_context_poll(cyw43_arch_async_context()); + async_context_wait_for_work_until(cyw43_arch_async_context(), at_the_end_of_time); + } + + cyw43_arch_deinit(); + + printf("Press the \"S\" key to Start bluetooth\n"); + key_pressed = false; + while(!key_pressed) { + sleep_ms(1000); + } + goto restart; + return 0; +} diff --git a/pico_w/bt/standalone/temp_sensor.gatt b/pico_w/bt/standalone/server/temp_sensor.gatt similarity index 100% rename from pico_w/bt/standalone/temp_sensor.gatt rename to pico_w/bt/standalone/server/temp_sensor.gatt diff --git a/pico_w/bt/standalone/server_common.h b/pico_w/bt/standalone/server_common.h deleted file mode 100644 index 80b9c59fb..000000000 --- a/pico_w/bt/standalone/server_common.h +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Copyright (c) 2023 Raspberry Pi (Trading) Ltd. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef SERVER_COMMON_H_ -#define SERVER_COMMON_H_ - -#define ADC_CHANNEL_TEMPSENSOR 4 - -extern int le_notification_enabled; -extern hci_con_handle_t con_handle; -extern uint16_t current_temp; -extern uint8_t const profile_data[]; - -void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); -uint16_t att_read_callback(hci_con_handle_t connection_handle, uint16_t att_handle, uint16_t offset, uint8_t * buffer, uint16_t buffer_size); -int att_write_callback(hci_con_handle_t connection_handle, uint16_t att_handle, uint16_t transaction_mode, uint16_t offset, uint8_t *buffer, uint16_t buffer_size); -void poll_temp(void); - -#endif diff --git a/pico_w/bt/standalone/server_with_wifi.c b/pico_w/bt/standalone/server_with_wifi.c deleted file mode 100644 index af17e6f05..000000000 --- a/pico_w/bt/standalone/server_with_wifi.c +++ /dev/null @@ -1,117 +0,0 @@ -/** - * Copyright (c) 2023 Raspberry Pi (Trading) Ltd. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include -#include "btstack.h" -#include "pico/cyw43_arch.h" -#include "pico/stdlib.h" -#include "hardware/adc.h" - -#include "lwip/netif.h" -#include "lwip/ip4_addr.h" -#include "lwip/apps/lwiperf.h" - -#include "server_common.h" - -#define HEARTBEAT_PERIOD_MS 1000 - -static void heartbeat_handler(async_context_t *context, async_at_time_worker_t *worker); - -static async_at_time_worker_t heartbeat_worker = { .do_work = heartbeat_handler }; -static btstack_packet_callback_registration_t hci_event_callback_registration; - -static void heartbeat_handler(async_context_t *context, async_at_time_worker_t *worker) { - static uint32_t counter = 0; - counter++; - - // Update the temp every 10s - if (counter % 10 == 0) { - poll_temp(); - if (le_notification_enabled) { - att_server_request_can_send_now_event(con_handle); - } - } - - // Invert the led - static int led_on = true; - led_on = !led_on; - cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, led_on); - - // Restart timer - async_context_add_at_time_worker_in_ms(context, &heartbeat_worker, HEARTBEAT_PERIOD_MS); -} - -// Report IP results and exit -static void iperf_report(void *arg, enum lwiperf_report_type report_type, - const ip_addr_t *local_addr, u16_t local_port, const ip_addr_t *remote_addr, u16_t remote_port, - u32_t bytes_transferred, u32_t ms_duration, u32_t bandwidth_kbitpsec) { - static uint32_t total_iperf_megabytes = 0; - uint32_t mbytes = bytes_transferred / 1024 / 1024; - float mbits = bandwidth_kbitpsec / 1000.0; - - total_iperf_megabytes += mbytes; - - printf("Completed iperf transfer of %u MBytes @ %.1f Mbits/sec\n", mbytes, mbits); - printf("Total iperf megabytes since start %u Mbytes\n", total_iperf_megabytes); -} - -int main() { - stdio_init_all(); - - // initialize CYW43 architecture - // - will enable BT if CYW43_ENABLE_BLUETOOTH == 1 - // - will enable lwIP if CYW43_LWIP == 1 - if (cyw43_arch_init()) { - printf("failed to initialise cyw43_arch\n"); - return -1; - } - - // Initialise adc for the temp sensor - adc_init(); - adc_select_input(ADC_CHANNEL_TEMPSENSOR); - adc_set_temp_sensor_enabled(true); - - l2cap_init(); - sm_init(); - att_server_init(profile_data, att_read_callback, att_write_callback); - - // inform about BTstack state - hci_event_callback_registration.callback = &packet_handler; - hci_add_event_handler(&hci_event_callback_registration); - - // register for ATT event - att_server_register_packet_handler(packet_handler); - - // use an async worker for for the led - async_context_add_at_time_worker_in_ms(cyw43_arch_async_context(), &heartbeat_worker, HEARTBEAT_PERIOD_MS); - - // Connect to Wi-Fi - cyw43_arch_enable_sta_mode(); - printf("Connecting to Wi-Fi...\n"); - if (cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWORD, CYW43_AUTH_WPA2_AES_PSK, 30000)) { - printf("failed to connect.\n"); - return 1; - } else { - printf("Connected.\n"); - } - - // setup iperf - cyw43_arch_lwip_begin(); - printf("\nReady, running iperf server at %s\n", ip4addr_ntoa(netif_ip4_addr(netif_list))); - lwiperf_start_tcp_server_default(&iperf_report, NULL); - cyw43_arch_lwip_end(); - - // turn on bluetooth! - hci_power_control(HCI_POWER_ON); - - // For threadsafe background we can just enter a loop - while(true) { - sleep_ms(1000); - } - - cyw43_arch_deinit(); - return 0; -}