From 847b6744c3620923926e3c01e257dd2200f63d62 Mon Sep 17 00:00:00 2001 From: theshteves Date: Tue, 23 Apr 2024 19:55:01 -0400 Subject: [PATCH 1/2] Add `pico_btstack_mesh` CMake library to link BlueTooth Mesh capabilities hidden in BTstack --- src/rp2_common/pico_btstack/CMakeLists.txt | 45 +++++++++++++++++++++- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/src/rp2_common/pico_btstack/CMakeLists.txt b/src/rp2_common/pico_btstack/CMakeLists.txt index 9cf6f28ef..ad18eccd2 100644 --- a/src/rp2_common/pico_btstack/CMakeLists.txt +++ b/src/rp2_common/pico_btstack/CMakeLists.txt @@ -55,8 +55,6 @@ if (EXISTS ${PICO_BTSTACK_PATH}/${BTSTACK_TEST_PATH}) ${PICO_BTSTACK_PATH}/src/hci_event.c ${PICO_BTSTACK_PATH}/src/l2cap.c ${PICO_BTSTACK_PATH}/src/l2cap_signaling.c - ${PICO_BTSTACK_PATH}/src/mesh/gatt-service/mesh_provisioning_service_server.c - ${PICO_BTSTACK_PATH}/src/mesh/gatt-service/mesh_proxy_service_server.c ${PICO_BTSTACK_PATH}/3rd-party/md5/md5.c ${PICO_BTSTACK_PATH}/3rd-party/yxml/yxml.c ${CMAKE_CURRENT_LIST_DIR}/btstack_stdin_pico.c @@ -154,6 +152,49 @@ if (EXISTS ${PICO_BTSTACK_PATH}/${BTSTACK_TEST_PATH}) ENABLE_CLASSIC=1 ) + pico_add_library(pico_btstack_mesh) + target_sources(pico_btstack_mesh INTERFACE + ${PICO_BTSTACK_PATH}/src/mesh/mesh.c + ${PICO_BTSTACK_PATH}/src/mesh/adv_bearer.c + ${PICO_BTSTACK_PATH}/src/mesh/beacon.c + ${PICO_BTSTACK_PATH}/src/mesh/gatt_bearer.c + ${PICO_BTSTACK_PATH}/src/mesh/gatt-service/mesh_provisioning_service_server.c + ${PICO_BTSTACK_PATH}/src/mesh/gatt-service/mesh_proxy_service_server.c + ${PICO_BTSTACK_PATH}/src/mesh/mesh.c + ${PICO_BTSTACK_PATH}/src/mesh/mesh_access.c + ${PICO_BTSTACK_PATH}/src/mesh/mesh_configuration_client.c + ${PICO_BTSTACK_PATH}/src/mesh/mesh_configuration_server.c + ${PICO_BTSTACK_PATH}/src/mesh/mesh_crypto.c + ${PICO_BTSTACK_PATH}/src/mesh/mesh_foundation.c + ${PICO_BTSTACK_PATH}/src/mesh/mesh_generic_default_transition_time_client.c + ${PICO_BTSTACK_PATH}/src/mesh/mesh_generic_default_transition_time_server.c + ${PICO_BTSTACK_PATH}/src/mesh/mesh_generic_level_client.c + ${PICO_BTSTACK_PATH}/src/mesh/mesh_generic_level_server.c + ${PICO_BTSTACK_PATH}/src/mesh/mesh_generic_on_off_client.c + ${PICO_BTSTACK_PATH}/src/mesh/mesh_generic_on_off_server.c + ${PICO_BTSTACK_PATH}/src/mesh/mesh_health_server.c + ${PICO_BTSTACK_PATH}/src/mesh/mesh_iv_index_seq_number.c + ${PICO_BTSTACK_PATH}/src/mesh/mesh_keys.c + ${PICO_BTSTACK_PATH}/src/mesh/mesh_lower_transport.c + ${PICO_BTSTACK_PATH}/src/mesh/mesh_network.c + ${PICO_BTSTACK_PATH}/src/mesh/mesh_node.c + ${PICO_BTSTACK_PATH}/src/mesh/mesh_peer.c + ${PICO_BTSTACK_PATH}/src/mesh/mesh_proxy.c + ${PICO_BTSTACK_PATH}/src/mesh/mesh_upper_transport.c + ${PICO_BTSTACK_PATH}/src/mesh/mesh_virtual_addresses.c + ${PICO_BTSTACK_PATH}/src/mesh/pb_adv.c + ${PICO_BTSTACK_PATH}/src/mesh/pb_gatt.c + ${PICO_BTSTACK_PATH}/src/mesh/provisioning.c + ${PICO_BTSTACK_PATH}/src/mesh/provisioning_device.c + ${PICO_BTSTACK_PATH}/src/mesh/provisioning_provisioner.c + ) + pico_mirrored_target_link_libraries(pico_btstack_mesh INTERFACE + pico_btstack_ble + ) + target_compile_definitions(pico_btstack_mesh_headers INTERFACE + ENABLE_MESH=1 + ) + pico_add_library(pico_btstack_flash_bank) target_sources(pico_btstack_flash_bank INTERFACE ${CMAKE_CURRENT_LIST_DIR}/btstack_flash_bank.c From 3534dbbba322935f6a446e4af6aedb15d2ff4ae0 Mon Sep 17 00:00:00 2001 From: theshteves Date: Wed, 1 May 2024 01:28:40 -0400 Subject: [PATCH 2/2] Add `pico_btstack_mesh` CMake library build test --- test/pico_btstack_mesh_test/CMakeLists.txt | 42 +++ test/pico_btstack_mesh_test/btstack_config.h | 52 ++++ test/pico_btstack_mesh_test/lwipopts.h | 21 ++ .../lwipopts_examples_common.h | 90 ++++++ test/pico_btstack_mesh_test/mesh_node_demo.c | 294 ++++++++++++++++++ .../mesh_node_demo.gatt | 5 + test/pico_btstack_mesh_test/mesh_node_demo.h | 105 +++++++ .../pico_sdk_import.cmake | 73 +++++ 8 files changed, 682 insertions(+) create mode 100644 test/pico_btstack_mesh_test/CMakeLists.txt create mode 100644 test/pico_btstack_mesh_test/btstack_config.h create mode 100644 test/pico_btstack_mesh_test/lwipopts.h create mode 100644 test/pico_btstack_mesh_test/lwipopts_examples_common.h create mode 100644 test/pico_btstack_mesh_test/mesh_node_demo.c create mode 100644 test/pico_btstack_mesh_test/mesh_node_demo.gatt create mode 100644 test/pico_btstack_mesh_test/mesh_node_demo.h create mode 100644 test/pico_btstack_mesh_test/pico_sdk_import.cmake diff --git a/test/pico_btstack_mesh_test/CMakeLists.txt b/test/pico_btstack_mesh_test/CMakeLists.txt new file mode 100644 index 000000000..4c8eaa3b6 --- /dev/null +++ b/test/pico_btstack_mesh_test/CMakeLists.txt @@ -0,0 +1,42 @@ +cmake_minimum_required(VERSION 3.5) + +include(pico_sdk_import.cmake) +project(mesh_node_demo C CXX ASM) + +set(PICO_BOARD pico_w) +set(CMAKE_C STANDARD 11) +set(CMAKE_CXX_STANDARD 17) + +pico_sdk_init() + +add_compile_options( + -Wall + -Wno-format # int != int32_t as far as the compiler is concerned because gcc has int32_t as long int + -Wno-unused-function # we have some for the docs that aren't called + -Wno-maybe-uninitialized + -O3 + -g +) + +add_executable(mesh_node_demo mesh_node_demo.c) + +pico_enable_stdio_usb(mesh_node_demo 1) # Enable USB output +pico_enable_stdio_uart(mesh_node_demo 0) # Disable UART output +pico_add_extra_outputs(mesh_node_demo) # Generate map/bin/hex/uf2 + +target_include_directories(mesh_node_demo + PRIVATE ${CMAKE_CURRENT_LIST_DIR} +) + +target_link_libraries(mesh_node_demo + hardware_adc + pico_btstack_cyw43 + pico_btstack_mesh + pico_cyw43_arch_lwip_threadsafe_background + pico_stdlib +) + +target_link_options(mesh_node_demo + PRIVATE "LINKER:--print-memory-usage" + PRIVATE "LINKER:--verbose" +) diff --git a/test/pico_btstack_mesh_test/btstack_config.h b/test/pico_btstack_mesh_test/btstack_config.h new file mode 100644 index 000000000..f1e4bd72f --- /dev/null +++ b/test/pico_btstack_mesh_test/btstack_config.h @@ -0,0 +1,52 @@ +// +// btstack_config.h for Raspberry Pi port +// +// Documentation: https://bluekitchen-gmbh.com/btstack/#how_to/ +// + +#ifndef BTSTACK_CONFIG_H +#define BTSTACK_CONFIG_H + +// Port related features +#define HAVE_ASSERT +#define HAVE_BTSTACK_STDIN +#define HAVE_MALLOC +#define HAVE_POSIX_FILE_IO +#define HAVE_POSIX_TIME + +// BTstack features that can be enabled +//#define ENABLE_BLE // Already defined in pico_btstack_ble +#define ENABLE_LE_CENTRAL +#define ENABLE_LE_DATA_LENGTH_EXTENSION +#define ENABLE_LE_PERIPHERAL +#define ENABLE_LE_SECURE_CONNECTIONS +#define ENABLE_LOG_ERROR +#define ENABLE_LOG_INFO +#define ENABLE_PRINTF_HEXDUMP + +// Mesh Configuration +//#define ENABLE_MESH // Already defined in pico_btstack_mesh +#define ENABLE_MESH_ADV_BEARER +#define ENABLE_MESH_GATT_BEARER +#define ENABLE_MESH_PB_ADV +#define ENABLE_MESH_PB_GATT +#define ENABLE_MESH_PROVISIONER +#define ENABLE_MESH_PROXY_SERVER + +// BTstack configuration. buffers, sizes, ... +#define HCI_ACL_CHUNK_SIZE_ALIGNMENT 4 +#define HCI_ACL_PAYLOAD_SIZE (1691 + 4) +#define HCI_INCOMING_PRE_BUFFER_SIZE 14 // sizeof BNEP header, avoid memcpy +#define HCI_OUTGOING_PRE_BUFFER_SIZE 4 + +#define MAX_NR_MESH_SUBNETS 2 +#define MAX_NR_MESH_TRANSPORT_KEYS 16 +#define MAX_NR_MESH_VIRTUAL_ADDRESSES 16 + +// allow for one NetKey update +#define MAX_NR_MESH_NETWORK_KEYS (MAX_NR_MESH_SUBNETS+1) + +#define NVM_NUM_DEVICE_DB_ENTRIES 16 +#define NVM_NUM_LINK_KEYS 16 + +#endif diff --git a/test/pico_btstack_mesh_test/lwipopts.h b/test/pico_btstack_mesh_test/lwipopts.h new file mode 100644 index 000000000..b8983d7d9 --- /dev/null +++ b/test/pico_btstack_mesh_test/lwipopts.h @@ -0,0 +1,21 @@ +#ifndef _LWIPOPTS_H +#define _LWIPOPTS_H + +// Generally you would define your own explicit list of lwIP options +// (see https://www.nongnu.org/lwip/2_1_x/group__lwip__opts.html) +// +// This example uses a common include to avoid repetition +#include "lwipopts_examples_common.h" + +#if !NO_SYS +#define TCPIP_THREAD_STACKSIZE 1024 +#define DEFAULT_THREAD_STACKSIZE 1024 +#define DEFAULT_RAW_RECVMBOX_SIZE 8 +#define TCPIP_MBOX_SIZE 8 +#define LWIP_TIMEVAL_PRIVATE 0 + +// not necessary, can be done either way +#define LWIP_TCPIP_CORE_LOCKING_INPUT 1 +#endif + +#endif diff --git a/test/pico_btstack_mesh_test/lwipopts_examples_common.h b/test/pico_btstack_mesh_test/lwipopts_examples_common.h new file mode 100644 index 000000000..217cb1357 --- /dev/null +++ b/test/pico_btstack_mesh_test/lwipopts_examples_common.h @@ -0,0 +1,90 @@ +#ifndef _LWIPOPTS_EXAMPLE_COMMONH_H +#define _LWIPOPTS_EXAMPLE_COMMONH_H + + +// Common settings used in most of the pico_w examples +// (see https://www.nongnu.org/lwip/2_1_x/group__lwip__opts.html for details) + +// allow override in some examples +#ifndef NO_SYS +#define NO_SYS 1 +#endif +// allow override in some examples +#ifndef LWIP_SOCKET +#define LWIP_SOCKET 0 +#endif +#if PICO_CYW43_ARCH_POLL +#define MEM_LIBC_MALLOC 1 +#else +// MEM_LIBC_MALLOC is incompatible with non polling versions +#define MEM_LIBC_MALLOC 0 +#endif +#define MEM_ALIGNMENT 4 +#define MEM_SIZE 4000 +#define MEMP_NUM_TCP_SEG 32 +#define MEMP_NUM_ARP_QUEUE 10 +#define PBUF_POOL_SIZE 24 +#define LWIP_ARP 1 +#define LWIP_ETHERNET 1 +#define LWIP_ICMP 1 +#define LWIP_RAW 1 +#define TCP_WND (8 * TCP_MSS) +#define TCP_MSS 1460 +#define TCP_SND_BUF (8 * TCP_MSS) +#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1)) / (TCP_MSS)) +#define LWIP_NETIF_STATUS_CALLBACK 1 +#define LWIP_NETIF_LINK_CALLBACK 1 +#define LWIP_NETIF_HOSTNAME 1 +#define LWIP_NETCONN 0 +#define MEM_STATS 0 +#define SYS_STATS 0 +#define MEMP_STATS 0 +#define LINK_STATS 0 +// #define ETH_PAD_SIZE 2 +#define LWIP_CHKSUM_ALGORITHM 3 +#define LWIP_DHCP 1 +#define LWIP_IPV4 1 +#define LWIP_TCP 1 +#define LWIP_UDP 1 +#define LWIP_DNS 1 +#define LWIP_TCP_KEEPALIVE 1 +#define LWIP_NETIF_TX_SINGLE_PBUF 1 +#define DHCP_DOES_ARP_CHECK 0 +#define LWIP_DHCP_DOES_ACD_CHECK 0 + +#ifndef NDEBUG +#define LWIP_DEBUG 1 +#define LWIP_STATS 1 +#define LWIP_STATS_DISPLAY 1 +#endif + +#define ETHARP_DEBUG LWIP_DBG_OFF +#define NETIF_DEBUG LWIP_DBG_OFF +#define PBUF_DEBUG LWIP_DBG_OFF +#define API_LIB_DEBUG LWIP_DBG_OFF +#define API_MSG_DEBUG LWIP_DBG_OFF +#define SOCKETS_DEBUG LWIP_DBG_OFF +#define ICMP_DEBUG LWIP_DBG_OFF +#define INET_DEBUG LWIP_DBG_OFF +#define IP_DEBUG LWIP_DBG_OFF +#define IP_REASS_DEBUG LWIP_DBG_OFF +#define RAW_DEBUG LWIP_DBG_OFF +#define MEM_DEBUG LWIP_DBG_OFF +#define MEMP_DEBUG LWIP_DBG_OFF +#define SYS_DEBUG LWIP_DBG_OFF +#define TCP_DEBUG LWIP_DBG_OFF +#define TCP_INPUT_DEBUG LWIP_DBG_OFF +#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF +#define TCP_RTO_DEBUG LWIP_DBG_OFF +#define TCP_CWND_DEBUG LWIP_DBG_OFF +#define TCP_WND_DEBUG LWIP_DBG_OFF +#define TCP_FR_DEBUG LWIP_DBG_OFF +#define TCP_QLEN_DEBUG LWIP_DBG_OFF +#define TCP_RST_DEBUG LWIP_DBG_OFF +#define UDP_DEBUG LWIP_DBG_OFF +#define TCPIP_DEBUG LWIP_DBG_OFF +#define PPP_DEBUG LWIP_DBG_OFF +#define SLIP_DEBUG LWIP_DBG_OFF +#define DHCP_DEBUG LWIP_DBG_OFF + +#endif /* __LWIPOPTS_H__ */ diff --git a/test/pico_btstack_mesh_test/mesh_node_demo.c b/test/pico_btstack_mesh_test/mesh_node_demo.c new file mode 100644 index 000000000..a4b4be070 --- /dev/null +++ b/test/pico_btstack_mesh_test/mesh_node_demo.c @@ -0,0 +1,294 @@ +/* + * Copyright (C) 2019 BlueKitchen GmbH + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * 4. Any redistribution, use, or modification is done solely for + * personal benefit and not for any commercial purpose or for + * monetary gain. + * + * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN + * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Please inquire about commercial licensing options at + * contact@bluekitchen-gmbh.com + * + */ + +/** + * Basic Mesh Node demo + */ + +#define BTSTACK_FILE__ "mesh_node_demo.c" + +#include +#include +#include +#include + +#include "btstack.h" +#include "mesh_node_demo.h" + +const char * device_uuid_string = "001BDC0810210B0E0A0C000B0E0A0C00"; + +// general +#define MESH_BLUEKITCHEN_MODEL_ID_TEST_SERVER 0x0000u + +static mesh_model_t mesh_vendor_model; + +static mesh_model_t mesh_generic_on_off_server_model; +static mesh_generic_on_off_state_t mesh_generic_on_off_state; + +static char gap_name_buffer[] = "Mesh 00:00:00:00:00:00"; + +static btstack_packet_callback_registration_t hci_event_callback_registration; + +#ifdef ENABLE_MESH_GATT_BEARER +static void 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; + + switch (hci_event_packet_get_type(packet)) { + case BTSTACK_EVENT_STATE: + if (btstack_event_state_get_state(packet) != HCI_STATE_WORKING) break; + // setup gap name from local address + gap_local_bd_addr(addr); + btstack_replace_bd_addr_placeholder((uint8_t*)gap_name_buffer, sizeof(gap_name_buffer), addr); + break; + default: + break; + } +} + +static 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){ + UNUSED(connection_handle); + if (att_handle == ATT_CHARACTERISTIC_GAP_DEVICE_NAME_01_VALUE_HANDLE){ + return att_read_callback_handle_blob((const uint8_t *)gap_name_buffer, (uint16_t) strlen(gap_name_buffer), offset, buffer, buffer_size); + } + return 0; +} +#endif + +static void mesh_provisioning_message_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ + UNUSED(packet_type); + UNUSED(channel); + UNUSED(size); + + if (packet_type != HCI_EVENT_PACKET) return; + + switch(packet[0]){ + case HCI_EVENT_MESH_META: + switch(packet[2]){ + case MESH_SUBEVENT_PB_TRANSPORT_LINK_OPEN: + printf("Provisioner link opened"); + break; + case MESH_SUBEVENT_ATTENTION_TIMER: + printf("Attention Timer: %u\n", mesh_subevent_attention_timer_get_attention_time(packet)); + break; + case MESH_SUBEVENT_PB_TRANSPORT_LINK_CLOSED: + printf("Provisioner link close"); + break; + case MESH_SUBEVENT_PB_PROV_COMPLETE: + printf("Provisioning complete\n"); + break; + default: + break; + } + break; + default: + break; + } +} + +static void mesh_state_update_message_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; + + switch(packet[0]){ + case HCI_EVENT_MESH_META: + switch(packet[2]){ + case MESH_SUBEVENT_STATE_UPDATE_BOOL: + printf("State update: model identifier 0x%08x, state identifier 0x%08x, reason %u, state %u\n", + mesh_subevent_state_update_bool_get_model_identifier(packet), + mesh_subevent_state_update_bool_get_state_identifier(packet), + mesh_subevent_state_update_bool_get_reason(packet), + mesh_subevent_state_update_bool_get_value(packet)); + break; + default: + break; + } + break; + default: + break; + } +} + +static void show_usage(void){ + bd_addr_t iut_address; + gap_local_bd_addr(iut_address); + printf("\n--- Bluetooth Mesh Console at %s ---\n", bd_addr_to_str(iut_address)); + printf("8 - Delete provisioning data\n"); + printf("g - Generic ON/OFF Server Toggle Value\n"); + printf("\n"); +} + +static void stdin_process(char cmd){ + switch (cmd){ + case '8': + mesh_node_reset(); + printf("Mesh Node Reset!\n"); + mesh_proxy_start_advertising_unprovisioned_device(); + break; + case 'g': + printf("Generic ON/OFF Server Toggle Value\n"); + mesh_generic_on_off_server_set(&mesh_generic_on_off_server_model, 1-mesh_generic_on_off_server_get(&mesh_generic_on_off_server_model), 0, 0); + break; + case ' ': + show_usage(); + break; + default: + printf("Command: '%c' not implemented\n", cmd); + show_usage(); + break; + } +} + +static int scan_hex_byte(const char * byte_string){ + int upper_nibble = nibble_for_char(*byte_string++); + if (upper_nibble < 0) return -1; + int lower_nibble = nibble_for_char(*byte_string); + if (lower_nibble < 0) return -1; + return (upper_nibble << 4) | lower_nibble; +} + +static int btstack_parse_hex(const char * string, uint16_t len, uint8_t * buffer){ + int i; + for (i = 0; i < len; i++) { + int single_byte = scan_hex_byte(string); + if (single_byte < 0) return 0; + string += 2; + buffer[i] = (uint8_t)single_byte; + // don't check seperator after last byte + if (i == len - 1) { + return 1; + } + // optional seperator + char separator = *string; + if (separator == ':' && separator == '-' && separator == ' ') { + string++; + } + } + return 1; +} + +int btstack_main(void); +int btstack_main(void) +{ +#ifdef HAVE_BTSTACK_STDIN + // console + btstack_stdin_setup(stdin_process); +#endif + + // crypto + btstack_crypto_init(); + +#ifdef ENABLE_MESH_GATT_BEARER + // l2cap + l2cap_init(); + + // setup ATT server + att_server_init(profile_data, &att_read_callback, NULL); + + // + sm_init(); +#endif + +#ifdef ENABLE_MESH_GATT_BEARER + // register for HCI events + hci_event_callback_registration.callback = &packet_handler; + hci_add_event_handler(&hci_event_callback_registration); +#endif + + // mesh + mesh_init(); + +#ifdef ENABLE_MESH_GATT_BEARER + // setup connectable advertisments + bd_addr_t null_addr; + memset(null_addr, 0, 6); + uint8_t adv_type = 0; // AFV_IND + uint16_t adv_int_min = 0x0030; + uint16_t adv_int_max = 0x0030; + adv_bearer_advertisements_set_params(adv_int_min, adv_int_max, adv_type, 0, null_addr, 0x07, 0x00); +#endif + + // Track Provisioning as device role + mesh_register_provisioning_device_packet_handler(&mesh_provisioning_message_handler); + + // Loc - bottom - https://www.bluetooth.com/specifications/assigned-numbers/gatt-namespace-descriptors + mesh_node_set_element_location(mesh_node_get_primary_element(), 0x103); + + // Setup Generic On/Off model + mesh_generic_on_off_server_model.model_identifier = mesh_model_get_model_identifier_bluetooth_sig(MESH_SIG_MODEL_ID_GENERIC_ON_OFF_SERVER); + mesh_generic_on_off_server_model.operations = mesh_generic_on_off_server_get_operations(); + mesh_generic_on_off_server_model.model_data = (void *) &mesh_generic_on_off_state; + mesh_generic_on_off_server_register_packet_handler(&mesh_generic_on_off_server_model, &mesh_state_update_message_handler); + mesh_element_add_model(mesh_node_get_primary_element(), &mesh_generic_on_off_server_model); + + // Setup our custom model + mesh_vendor_model.model_identifier = mesh_model_get_model_identifier(BLUETOOTH_COMPANY_ID_BLUEKITCHEN_GMBH, MESH_BLUEKITCHEN_MODEL_ID_TEST_SERVER); + mesh_element_add_model(mesh_node_get_primary_element(), &mesh_vendor_model); + + // Enable Output OOB + provisioning_device_set_output_oob_actions(0x08, 0x08); + + // Enable PROXY + mesh_foundation_gatt_proxy_set(1); + +#if defined(ENABLE_MESH_ADV_BEARER) + // setup scanning when supporting ADV Bearer + gap_set_scan_parameters(0, 0x300, 0x300); + gap_start_scan(); +#endif + + uint8_t device_uuid[16]; + btstack_parse_hex(device_uuid_string, 16, device_uuid); + mesh_node_set_device_uuid(device_uuid); + + // turn on! + hci_power_control(HCI_POWER_ON); + + return 0; +} + +int main(int argc, char *argv[]) { + btstack_main(); + return 0; +} +/* EXAMPLE_END */ diff --git a/test/pico_btstack_mesh_test/mesh_node_demo.gatt b/test/pico_btstack_mesh_test/mesh_node_demo.gatt new file mode 100644 index 000000000..02cd788c3 --- /dev/null +++ b/test/pico_btstack_mesh_test/mesh_node_demo.gatt @@ -0,0 +1,5 @@ +PRIMARY_SERVICE, GAP_SERVICE +CHARACTERISTIC, GAP_DEVICE_NAME, READ | DYNAMIC, + +#import +#import diff --git a/test/pico_btstack_mesh_test/mesh_node_demo.h b/test/pico_btstack_mesh_test/mesh_node_demo.h new file mode 100644 index 000000000..2062b57a2 --- /dev/null +++ b/test/pico_btstack_mesh_test/mesh_node_demo.h @@ -0,0 +1,105 @@ + +// ./mesh_node_demo.h generated from ./mesh_node_demo.gatt for BTstack +// it needs to be regenerated when the .gatt file is updated. + +// To generate ./mesh_node_demo.h: +// $(PICO_SDK_PATH)/lib/btstack/tool/compile_gatt.py ./mesh_node_demo.gatt ./mesh_node_demo.h + +// att db format version 1 + +// binary attribute representation: +// - size in bytes (16), flags(16), handle (16), uuid (16/128), value(...) + +#include + +// Reference: https://en.cppreference.com/w/cpp/feature_test +#if __cplusplus >= 200704L +constexpr +#endif +const uint8_t profile_data[] = +{ + // ATT DB Version + 1, + + // 0x0001 PRIMARY_SERVICE-GAP_SERVICE + 0x0a, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x28, 0x00, 0x18, + // 0x0002 CHARACTERISTIC-GAP_DEVICE_NAME - READ | DYNAMIC + 0x0d, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x28, 0x02, 0x03, 0x00, 0x00, 0x2a, + // 0x0003 VALUE CHARACTERISTIC-GAP_DEVICE_NAME - READ | DYNAMIC + // READ_ANYBODY + 0x08, 0x00, 0x02, 0x01, 0x03, 0x00, 0x00, 0x2a, + + + // #import -- BEGIN + // Specification Type org.bluetooth.service.mesh_provisioning + // https://www.bluetooth.com/api/gatt/xmlfile?xmlFileName=org.bluetooth.service.mesh_provisioning.xml + // Mesh Provisioning Service 1827 + // 0x0004 PRIMARY_SERVICE-ORG_BLUETOOTH_SERVICE_MESH_PROVISIONING + 0x0a, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x28, 0x27, 0x18, + // 0x0005 CHARACTERISTIC-ORG_BLUETOOTH_CHARACTERISTIC_MESH_PROVISIONING_DATA_IN - DYNAMIC | WRITE_WITHOUT_RESPONSE + 0x0d, 0x00, 0x02, 0x00, 0x05, 0x00, 0x03, 0x28, 0x04, 0x06, 0x00, 0xdb, 0x2a, + // 0x0006 VALUE CHARACTERISTIC-ORG_BLUETOOTH_CHARACTERISTIC_MESH_PROVISIONING_DATA_IN - DYNAMIC | WRITE_WITHOUT_RESPONSE + // WRITE_ANYBODY + 0x08, 0x00, 0x04, 0x01, 0x06, 0x00, 0xdb, 0x2a, + // 0x0007 CHARACTERISTIC-ORG_BLUETOOTH_CHARACTERISTIC_MESH_PROVISIONING_DATA_OUT - DYNAMIC | NOTIFY + 0x0d, 0x00, 0x02, 0x00, 0x07, 0x00, 0x03, 0x28, 0x10, 0x08, 0x00, 0xdc, 0x2a, + // 0x0008 VALUE CHARACTERISTIC-ORG_BLUETOOTH_CHARACTERISTIC_MESH_PROVISIONING_DATA_OUT - DYNAMIC | NOTIFY + // + 0x08, 0x00, 0x00, 0x01, 0x08, 0x00, 0xdc, 0x2a, + // 0x0009 CLIENT_CHARACTERISTIC_CONFIGURATION + // READ_ANYBODY, WRITE_ANYBODY + 0x0a, 0x00, 0x0e, 0x01, 0x09, 0x00, 0x02, 0x29, 0x00, 0x00, + // #import -- END + + + // #import -- BEGIN + // Specification Type org.bluetooth.service.mesh_proxy + // https://www.bluetooth.com/api/gatt/xmlfile?xmlFileName=org.bluetooth.service.mesh_proxy.xml + // Mesh Proxy Service 1828 + // 0x000a PRIMARY_SERVICE-ORG_BLUETOOTH_SERVICE_MESH_PROXY + 0x0a, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x28, 0x28, 0x18, + // 0x000b CHARACTERISTIC-ORG_BLUETOOTH_CHARACTERISTIC_MESH_PROXY_DATA_IN - DYNAMIC | WRITE_WITHOUT_RESPONSE + 0x0d, 0x00, 0x02, 0x00, 0x0b, 0x00, 0x03, 0x28, 0x04, 0x0c, 0x00, 0xdd, 0x2a, + // 0x000c VALUE CHARACTERISTIC-ORG_BLUETOOTH_CHARACTERISTIC_MESH_PROXY_DATA_IN - DYNAMIC | WRITE_WITHOUT_RESPONSE + // WRITE_ANYBODY + 0x08, 0x00, 0x04, 0x01, 0x0c, 0x00, 0xdd, 0x2a, + // 0x000d CHARACTERISTIC-ORG_BLUETOOTH_CHARACTERISTIC_MESH_PROXY_DATA_OUT - DYNAMIC | NOTIFY + 0x0d, 0x00, 0x02, 0x00, 0x0d, 0x00, 0x03, 0x28, 0x10, 0x0e, 0x00, 0xde, 0x2a, + // 0x000e VALUE CHARACTERISTIC-ORG_BLUETOOTH_CHARACTERISTIC_MESH_PROXY_DATA_OUT - DYNAMIC | NOTIFY + // + 0x08, 0x00, 0x00, 0x01, 0x0e, 0x00, 0xde, 0x2a, + // 0x000f CLIENT_CHARACTERISTIC_CONFIGURATION + // READ_ANYBODY, WRITE_ANYBODY + 0x0a, 0x00, 0x0e, 0x01, 0x0f, 0x00, 0x02, 0x29, 0x00, 0x00, + // #import -- END + // END + 0x00, 0x00, +}; // total size 97 bytes + + +// +// list service handle ranges +// +#define ATT_SERVICE_GAP_SERVICE_START_HANDLE 0x0001 +#define ATT_SERVICE_GAP_SERVICE_END_HANDLE 0x0003 +#define ATT_SERVICE_GAP_SERVICE_01_START_HANDLE 0x0001 +#define ATT_SERVICE_GAP_SERVICE_01_END_HANDLE 0x0003 +#define ATT_SERVICE_ORG_BLUETOOTH_SERVICE_MESH_PROVISIONING_START_HANDLE 0x0004 +#define ATT_SERVICE_ORG_BLUETOOTH_SERVICE_MESH_PROVISIONING_END_HANDLE 0x0009 +#define ATT_SERVICE_ORG_BLUETOOTH_SERVICE_MESH_PROVISIONING_01_START_HANDLE 0x0004 +#define ATT_SERVICE_ORG_BLUETOOTH_SERVICE_MESH_PROVISIONING_01_END_HANDLE 0x0009 +#define ATT_SERVICE_ORG_BLUETOOTH_SERVICE_MESH_PROXY_START_HANDLE 0x000a +#define ATT_SERVICE_ORG_BLUETOOTH_SERVICE_MESH_PROXY_END_HANDLE 0x000f +#define ATT_SERVICE_ORG_BLUETOOTH_SERVICE_MESH_PROXY_01_START_HANDLE 0x000a +#define ATT_SERVICE_ORG_BLUETOOTH_SERVICE_MESH_PROXY_01_END_HANDLE 0x000f + +// +// list mapping between characteristics and handles +// +#define ATT_CHARACTERISTIC_GAP_DEVICE_NAME_01_VALUE_HANDLE 0x0003 +#define ATT_CHARACTERISTIC_ORG_BLUETOOTH_CHARACTERISTIC_MESH_PROVISIONING_DATA_IN_01_VALUE_HANDLE 0x0006 +#define ATT_CHARACTERISTIC_ORG_BLUETOOTH_CHARACTERISTIC_MESH_PROVISIONING_DATA_OUT_01_VALUE_HANDLE 0x0008 +#define ATT_CHARACTERISTIC_ORG_BLUETOOTH_CHARACTERISTIC_MESH_PROVISIONING_DATA_OUT_01_CLIENT_CONFIGURATION_HANDLE 0x0009 +#define ATT_CHARACTERISTIC_ORG_BLUETOOTH_CHARACTERISTIC_MESH_PROXY_DATA_IN_01_VALUE_HANDLE 0x000c +#define ATT_CHARACTERISTIC_ORG_BLUETOOTH_CHARACTERISTIC_MESH_PROXY_DATA_OUT_01_VALUE_HANDLE 0x000e +#define ATT_CHARACTERISTIC_ORG_BLUETOOTH_CHARACTERISTIC_MESH_PROXY_DATA_OUT_01_CLIENT_CONFIGURATION_HANDLE 0x000f diff --git a/test/pico_btstack_mesh_test/pico_sdk_import.cmake b/test/pico_btstack_mesh_test/pico_sdk_import.cmake new file mode 100644 index 000000000..65f8a6f7d --- /dev/null +++ b/test/pico_btstack_mesh_test/pico_sdk_import.cmake @@ -0,0 +1,73 @@ +# This is a copy of /external/pico_sdk_import.cmake + +# This can be dropped into an external project to help locate this SDK +# It should be include()ed prior to project() + +if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH)) + set(PICO_SDK_PATH $ENV{PICO_SDK_PATH}) + message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT)) + set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT}) + message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH)) + set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH}) + message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')") +endif () + +set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK") +set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable") +set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK") + +if (NOT PICO_SDK_PATH) + if (PICO_SDK_FETCH_FROM_GIT) + include(FetchContent) + set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR}) + if (PICO_SDK_FETCH_FROM_GIT_PATH) + get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") + endif () + # GIT_SUBMODULES_RECURSE was added in 3.17 + if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0") + FetchContent_Declare( + pico_sdk + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG master + GIT_SUBMODULES_RECURSE FALSE + ) + else () + FetchContent_Declare( + pico_sdk + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG master + ) + endif () + + if (NOT pico_sdk) + message("Downloading Raspberry Pi Pico SDK") + FetchContent_Populate(pico_sdk) + set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) + endif () + set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE}) + else () + message(FATAL_ERROR + "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git." + ) + endif () +endif () + +get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") +if (NOT EXISTS ${PICO_SDK_PATH}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found") +endif () + +set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake) +if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK") +endif () + +set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE) + +include(${PICO_SDK_INIT_CMAKE_FILE})