1cf862b36SMatthias Ringwald /* 2cf862b36SMatthias Ringwald * Copyright (C) 2019 BlueKitchen GmbH 3cf862b36SMatthias Ringwald * 4cf862b36SMatthias Ringwald * Redistribution and use in source and binary forms, with or without 5cf862b36SMatthias Ringwald * modification, are permitted provided that the following conditions 6cf862b36SMatthias Ringwald * are met: 7cf862b36SMatthias Ringwald * 8cf862b36SMatthias Ringwald * 1. Redistributions of source code must retain the above copyright 9cf862b36SMatthias Ringwald * notice, this list of conditions and the following disclaimer. 10cf862b36SMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright 11cf862b36SMatthias Ringwald * notice, this list of conditions and the following disclaimer in the 12cf862b36SMatthias Ringwald * documentation and/or other materials provided with the distribution. 13cf862b36SMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of 14cf862b36SMatthias Ringwald * contributors may be used to endorse or promote products derived 15cf862b36SMatthias Ringwald * from this software without specific prior written permission. 16cf862b36SMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for 17cf862b36SMatthias Ringwald * personal benefit and not for any commercial purpose or for 18cf862b36SMatthias Ringwald * monetary gain. 19cf862b36SMatthias Ringwald * 20cf862b36SMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21cf862b36SMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22cf862b36SMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23cf862b36SMatthias Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 24cf862b36SMatthias Ringwald * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25cf862b36SMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26cf862b36SMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27cf862b36SMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28cf862b36SMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29cf862b36SMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30cf862b36SMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31cf862b36SMatthias Ringwald * SUCH DAMAGE. 32cf862b36SMatthias Ringwald * 33cf862b36SMatthias Ringwald * Please inquire about commercial licensing options at 34cf862b36SMatthias Ringwald * [email protected] 35cf862b36SMatthias Ringwald * 36cf862b36SMatthias Ringwald */ 37cf862b36SMatthias Ringwald 38cf862b36SMatthias Ringwald /** 39cf862b36SMatthias Ringwald * Basic Mesh Node demo 40cf862b36SMatthias Ringwald */ 41cf862b36SMatthias Ringwald 42cf862b36SMatthias Ringwald #define __BTSTACK_FILE__ "mesh_node_demo.c" 43cf862b36SMatthias Ringwald 44cf862b36SMatthias Ringwald #include <stdint.h> 45cf862b36SMatthias Ringwald #include <stdio.h> 46cf862b36SMatthias Ringwald #include <stdlib.h> 47cf862b36SMatthias Ringwald #include <string.h> 48cf862b36SMatthias Ringwald 49cf862b36SMatthias Ringwald #include "btstack.h" 50cf862b36SMatthias Ringwald #include "mesh_node_demo.h" 51cf862b36SMatthias Ringwald 52*138818a3SMatthias Ringwald const char * device_uuid_string = "001BDC0810210B0E0A0C000B0E0A0C00"; 53*138818a3SMatthias Ringwald 54cf862b36SMatthias Ringwald // general 55cf862b36SMatthias Ringwald #define MESH_BLUEKITCHEN_MODEL_ID_TEST_SERVER 0x0000u 56cf862b36SMatthias Ringwald 57cf862b36SMatthias Ringwald static mesh_model_t mesh_vendor_model; 58cf862b36SMatthias Ringwald 59cf862b36SMatthias Ringwald static mesh_model_t mesh_generic_on_off_server_model; 60cf862b36SMatthias Ringwald static mesh_generic_on_off_state_t mesh_generic_on_off_state; 61cf862b36SMatthias Ringwald 62f2229d0eSMatthias Ringwald static char gap_name_buffer[30]; 63f2229d0eSMatthias Ringwald static char gap_name_prefix[] = "Mesh "; 64f2229d0eSMatthias Ringwald 65f2229d0eSMatthias Ringwald static btstack_packet_callback_registration_t hci_event_callback_registration; 66f2229d0eSMatthias Ringwald 675127fa8aSMatthias Ringwald #ifdef ENABLE_MESH_GATT_BEARER 68f2229d0eSMatthias Ringwald static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 69f2229d0eSMatthias Ringwald UNUSED(channel); 70f2229d0eSMatthias Ringwald UNUSED(size); 71f2229d0eSMatthias Ringwald bd_addr_t addr; 72f2229d0eSMatthias Ringwald switch (packet_type) { 73f2229d0eSMatthias Ringwald case HCI_EVENT_PACKET: 74f2229d0eSMatthias Ringwald switch (hci_event_packet_get_type(packet)) { 75f2229d0eSMatthias Ringwald case BTSTACK_EVENT_STATE: 76f2229d0eSMatthias Ringwald if (btstack_event_state_get_state(packet) != HCI_STATE_WORKING) break; 77f2229d0eSMatthias Ringwald // setup gap name 78f2229d0eSMatthias Ringwald gap_local_bd_addr(addr); 79f2229d0eSMatthias Ringwald strcpy(gap_name_buffer, gap_name_prefix); 80f2229d0eSMatthias Ringwald strcat(gap_name_buffer, bd_addr_to_str(addr)); 81f2229d0eSMatthias Ringwald break; 82f2229d0eSMatthias Ringwald default: 83f2229d0eSMatthias Ringwald break; 84f2229d0eSMatthias Ringwald } 85f2229d0eSMatthias Ringwald break; 86f2229d0eSMatthias Ringwald } 87f2229d0eSMatthias Ringwald } 88f2229d0eSMatthias Ringwald 89f2229d0eSMatthias Ringwald 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){ 90f2229d0eSMatthias Ringwald UNUSED(connection_handle); 91f2229d0eSMatthias Ringwald if (att_handle == ATT_CHARACTERISTIC_GAP_DEVICE_NAME_01_VALUE_HANDLE){ 92f2229d0eSMatthias Ringwald return att_read_callback_handle_blob((const uint8_t *)gap_name_buffer, strlen(gap_name_buffer), offset, buffer, buffer_size); 93f2229d0eSMatthias Ringwald } 94f2229d0eSMatthias Ringwald return 0; 95f2229d0eSMatthias Ringwald } 965127fa8aSMatthias Ringwald #endif 97cf862b36SMatthias Ringwald 98cf862b36SMatthias Ringwald static void mesh_provisioning_message_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 99cf862b36SMatthias Ringwald UNUSED(packet_type); 100cf862b36SMatthias Ringwald UNUSED(channel); 101cf862b36SMatthias Ringwald UNUSED(size); 102cf862b36SMatthias Ringwald 103cf862b36SMatthias Ringwald if (packet_type != HCI_EVENT_PACKET) return; 104cf862b36SMatthias Ringwald 105cf862b36SMatthias Ringwald switch(packet[0]){ 106cf862b36SMatthias Ringwald case HCI_EVENT_MESH_META: 107cf862b36SMatthias Ringwald switch(packet[2]){ 108cf862b36SMatthias Ringwald case MESH_SUBEVENT_PB_TRANSPORT_LINK_OPEN: 109cf862b36SMatthias Ringwald printf("Provisioner link opened"); 110cf862b36SMatthias Ringwald break; 1110728b042SMatthias Ringwald case MESH_SUBEVENT_ATTENTION_TIMER: 1120728b042SMatthias Ringwald printf("Attention Timer: %u\n", mesh_subevent_attention_timer_get_attention_time(packet)); 1130728b042SMatthias Ringwald break; 114cf862b36SMatthias Ringwald case MESH_SUBEVENT_PB_TRANSPORT_LINK_CLOSED: 115cf862b36SMatthias Ringwald printf("Provisioner link close"); 116cf862b36SMatthias Ringwald break; 117cf862b36SMatthias Ringwald case MESH_SUBEVENT_PB_PROV_COMPLETE: 118cf862b36SMatthias Ringwald printf("Provisioning complete\n"); 119cf862b36SMatthias Ringwald break; 120cf862b36SMatthias Ringwald default: 121cf862b36SMatthias Ringwald break; 122cf862b36SMatthias Ringwald } 123cf862b36SMatthias Ringwald break; 124cf862b36SMatthias Ringwald default: 125cf862b36SMatthias Ringwald break; 126cf862b36SMatthias Ringwald } 127cf862b36SMatthias Ringwald } 128cf862b36SMatthias Ringwald 129cf862b36SMatthias Ringwald static void mesh_state_update_message_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 130cf862b36SMatthias Ringwald UNUSED(channel); 131cf862b36SMatthias Ringwald UNUSED(size); 132cf862b36SMatthias Ringwald 133cf862b36SMatthias Ringwald if (packet_type != HCI_EVENT_PACKET) return; 134cf862b36SMatthias Ringwald 135cf862b36SMatthias Ringwald switch(packet[0]){ 136cf862b36SMatthias Ringwald case HCI_EVENT_MESH_META: 137cf862b36SMatthias Ringwald switch(packet[2]){ 138cf862b36SMatthias Ringwald case MESH_SUBEVENT_STATE_UPDATE_BOOL: 139cf862b36SMatthias Ringwald printf("State update: model identifier 0x%08x, state identifier 0x%08x, reason %u, state %u\n", 140cf862b36SMatthias Ringwald mesh_subevent_state_update_bool_get_model_identifier(packet), 141cf862b36SMatthias Ringwald mesh_subevent_state_update_bool_get_state_identifier(packet), 142cf862b36SMatthias Ringwald mesh_subevent_state_update_bool_get_reason(packet), 143cf862b36SMatthias Ringwald mesh_subevent_state_update_bool_get_value(packet)); 144cf862b36SMatthias Ringwald break; 145cf862b36SMatthias Ringwald default: 146cf862b36SMatthias Ringwald break; 147cf862b36SMatthias Ringwald } 148cf862b36SMatthias Ringwald break; 149cf862b36SMatthias Ringwald default: 150cf862b36SMatthias Ringwald break; 151cf862b36SMatthias Ringwald } 152cf862b36SMatthias Ringwald } 153cf862b36SMatthias Ringwald 154cf862b36SMatthias Ringwald static void show_usage(void){ 155cf862b36SMatthias Ringwald bd_addr_t iut_address; 156cf862b36SMatthias Ringwald gap_local_bd_addr(iut_address); 157cf862b36SMatthias Ringwald printf("\n--- Bluetooth Mesh Console at %s ---\n", bd_addr_to_str(iut_address)); 158cf862b36SMatthias Ringwald printf("8 - Delete provisioning data\n"); 159cf862b36SMatthias Ringwald printf("g - Generic ON/OFF Server Toggle Value\n"); 160cf862b36SMatthias Ringwald printf("\n"); 161cf862b36SMatthias Ringwald } 162cf862b36SMatthias Ringwald 163cf862b36SMatthias Ringwald static void stdin_process(char cmd){ 164cf862b36SMatthias Ringwald switch (cmd){ 165cf862b36SMatthias Ringwald case '8': 166cf862b36SMatthias Ringwald mesh_node_reset(); 167cf862b36SMatthias Ringwald printf("Mesh Node Reset!\n"); 168cf862b36SMatthias Ringwald mesh_proxy_start_advertising_unprovisioned_device(); 169cf862b36SMatthias Ringwald break; 170cf862b36SMatthias Ringwald case 'g': 171cf862b36SMatthias Ringwald printf("Generic ON/OFF Server Toggle Value\n"); 172cf862b36SMatthias Ringwald 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); 173cf862b36SMatthias Ringwald break; 174cf862b36SMatthias Ringwald case ' ': 175cf862b36SMatthias Ringwald show_usage(); 176cf862b36SMatthias Ringwald break; 177cf862b36SMatthias Ringwald default: 178cf862b36SMatthias Ringwald printf("Command: '%c' not implemented\n", cmd); 179cf862b36SMatthias Ringwald show_usage(); 180cf862b36SMatthias Ringwald break; 181cf862b36SMatthias Ringwald } 182cf862b36SMatthias Ringwald } 183cf862b36SMatthias Ringwald 184*138818a3SMatthias Ringwald static int scan_hex_byte(const char * byte_string){ 185*138818a3SMatthias Ringwald int upper_nibble = nibble_for_char(*byte_string++); 186*138818a3SMatthias Ringwald if (upper_nibble < 0) return -1; 187*138818a3SMatthias Ringwald int lower_nibble = nibble_for_char(*byte_string); 188*138818a3SMatthias Ringwald if (lower_nibble < 0) return -1; 189*138818a3SMatthias Ringwald return (upper_nibble << 4) | lower_nibble; 190*138818a3SMatthias Ringwald } 191*138818a3SMatthias Ringwald 192*138818a3SMatthias Ringwald static int btstack_parse_hex(const char * string, uint16_t len, uint8_t * buffer){ 193*138818a3SMatthias Ringwald int i; 194*138818a3SMatthias Ringwald for (i = 0; i < len; i++) { 195*138818a3SMatthias Ringwald int single_byte = scan_hex_byte(string); 196*138818a3SMatthias Ringwald if (single_byte < 0) return 0; 197*138818a3SMatthias Ringwald string += 2; 198*138818a3SMatthias Ringwald buffer[i] = (uint8_t)single_byte; 199*138818a3SMatthias Ringwald // don't check seperator after last byte 200*138818a3SMatthias Ringwald if (i == len - 1) { 201*138818a3SMatthias Ringwald return 1; 202*138818a3SMatthias Ringwald } 203*138818a3SMatthias Ringwald // optional seperator 204*138818a3SMatthias Ringwald char separator = *string; 205*138818a3SMatthias Ringwald if (separator == ':' && separator == '-' && separator == ' ') { 206*138818a3SMatthias Ringwald string++; 207*138818a3SMatthias Ringwald } 208*138818a3SMatthias Ringwald } 209*138818a3SMatthias Ringwald return 1; 210*138818a3SMatthias Ringwald } 211*138818a3SMatthias Ringwald 212cf862b36SMatthias Ringwald int btstack_main(void); 213cf862b36SMatthias Ringwald int btstack_main(void) 214cf862b36SMatthias Ringwald { 2155127fa8aSMatthias Ringwald #ifdef HAVE_BTSTACK_STDIN 216cf862b36SMatthias Ringwald // console 217cf862b36SMatthias Ringwald btstack_stdin_setup(stdin_process); 2185127fa8aSMatthias Ringwald #endif 219cf862b36SMatthias Ringwald 220cf862b36SMatthias Ringwald // crypto 221cf862b36SMatthias Ringwald btstack_crypto_init(); 222cf862b36SMatthias Ringwald 223*138818a3SMatthias Ringwald #ifdef ENABLE_MESH_GATT_BEARER 224cf862b36SMatthias Ringwald // l2cap 225cf862b36SMatthias Ringwald l2cap_init(); 226cf862b36SMatthias Ringwald 227cf862b36SMatthias Ringwald // setup le device db 228cf862b36SMatthias Ringwald le_device_db_init(); 229cf862b36SMatthias Ringwald 230cf862b36SMatthias Ringwald // setup ATT server 231f2229d0eSMatthias Ringwald att_server_init(profile_data, &att_read_callback, NULL); 232cf862b36SMatthias Ringwald 233cf862b36SMatthias Ringwald // 234cf862b36SMatthias Ringwald sm_init(); 2355127fa8aSMatthias Ringwald #endif 236cf862b36SMatthias Ringwald 2375127fa8aSMatthias Ringwald #ifdef ENABLE_MESH_GATT_BEARER 238f2229d0eSMatthias Ringwald // register for HCI events 239f2229d0eSMatthias Ringwald hci_event_callback_registration.callback = &packet_handler; 240f2229d0eSMatthias Ringwald hci_add_event_handler(&hci_event_callback_registration); 2415127fa8aSMatthias Ringwald #endif 242cf862b36SMatthias Ringwald 243cf862b36SMatthias Ringwald // mesh 244cf862b36SMatthias Ringwald mesh_init(); 245cf862b36SMatthias Ringwald 246*138818a3SMatthias Ringwald #ifdef ENABLE_MESH_GATT_BEARER 247cf862b36SMatthias Ringwald // setup connectable advertisments 248cf862b36SMatthias Ringwald bd_addr_t null_addr; 249cf862b36SMatthias Ringwald memset(null_addr, 0, 6); 250cf862b36SMatthias Ringwald uint8_t adv_type = 0; // AFV_IND 251cf862b36SMatthias Ringwald uint16_t adv_int_min = 0x0030; 252cf862b36SMatthias Ringwald uint16_t adv_int_max = 0x0030; 253cf862b36SMatthias Ringwald adv_bearer_advertisements_set_params(adv_int_min, adv_int_max, adv_type, 0, null_addr, 0x07, 0x00); 2545127fa8aSMatthias Ringwald #endif 255cf862b36SMatthias Ringwald 256cf862b36SMatthias Ringwald // Track Provisioning as device role 257cf862b36SMatthias Ringwald mesh_register_provisioning_device_packet_handler(&mesh_provisioning_message_handler); 258cf862b36SMatthias Ringwald 259cf862b36SMatthias Ringwald // Loc - bottom - https://www.bluetooth.com/specifications/assigned-numbers/gatt-namespace-descriptors 260cf862b36SMatthias Ringwald mesh_node_set_element_location(mesh_node_get_primary_element(), 0x103); 261cf862b36SMatthias Ringwald 262cf862b36SMatthias Ringwald // Setup Generic On/Off model 263cf862b36SMatthias Ringwald mesh_generic_on_off_server_model.model_identifier = mesh_model_get_model_identifier_bluetooth_sig(MESH_SIG_MODEL_ID_GENERIC_ON_OFF_SERVER); 264cf862b36SMatthias Ringwald mesh_generic_on_off_server_model.operations = mesh_generic_on_off_server_get_operations(); 265cf862b36SMatthias Ringwald mesh_generic_on_off_server_model.model_data = (void *) &mesh_generic_on_off_state; 266cf862b36SMatthias Ringwald mesh_generic_on_off_server_register_packet_handler(&mesh_generic_on_off_server_model, &mesh_state_update_message_handler); 267cf862b36SMatthias Ringwald mesh_element_add_model(mesh_node_get_primary_element(), &mesh_generic_on_off_server_model); 268cf862b36SMatthias Ringwald 269cf862b36SMatthias Ringwald // Setup our custom model 270cf862b36SMatthias Ringwald mesh_vendor_model.model_identifier = mesh_model_get_model_identifier(BLUETOOTH_COMPANY_ID_BLUEKITCHEN_GMBH, MESH_BLUEKITCHEN_MODEL_ID_TEST_SERVER); 271cf862b36SMatthias Ringwald mesh_element_add_model(mesh_node_get_primary_element(), &mesh_vendor_model); 272cf862b36SMatthias Ringwald 273cf862b36SMatthias Ringwald // Enable Output OOB 274cf862b36SMatthias Ringwald provisioning_device_set_output_oob_actions(0x08, 0x08); 275cf862b36SMatthias Ringwald 276cf862b36SMatthias Ringwald // Enable PROXY 277cf862b36SMatthias Ringwald mesh_foundation_gatt_proxy_set(1); 278cf862b36SMatthias Ringwald 279cf862b36SMatthias Ringwald #if defined(ENABLE_MESH_ADV_BEARER) 280cf862b36SMatthias Ringwald // setup scanning when supporting ADV Bearer 281cf862b36SMatthias Ringwald gap_set_scan_parameters(0, 0x300, 0x300); 282cf862b36SMatthias Ringwald gap_start_scan(); 283cf862b36SMatthias Ringwald #endif 284cf862b36SMatthias Ringwald 285*138818a3SMatthias Ringwald uint8_t device_uuid[16]; 286*138818a3SMatthias Ringwald btstack_parse_hex(device_uuid_string, 16, device_uuid); 287*138818a3SMatthias Ringwald mesh_node_set_device_uuid(device_uuid); 288*138818a3SMatthias Ringwald 289cf862b36SMatthias Ringwald // turn on! 290cf862b36SMatthias Ringwald hci_power_control(HCI_POWER_ON); 291cf862b36SMatthias Ringwald 292cf862b36SMatthias Ringwald return 0; 293cf862b36SMatthias Ringwald } 294cf862b36SMatthias Ringwald /* EXAMPLE_END */ 295