Simultanious data reading from connected devices to central.

Hi,

I am working in Nrf52832, Zephyr as central for connecting multiple peripheral devics. I want to read the multiple devices data at a same time. I am using common discovery function for all devices. And I use delayed work queue for conntion update. Give some instruction for simultanous data reading?

Athulya

  • Hi Athulya,

    You will not be able to read data at the exact same time, but it is for instance possible for a central to be connected to multiple peripheral devices at the same time, and read a characteristic from each, one after another (within the limitations of having to wait for a connection event on each of the links). In practice, you would just read from each one, and the stack would handle the details for you.

    Perhaps you can elaborate a bit on what you are doing, what you want to do, and in what way you are having problems with it?

    Einar

  • Hi

    Thank you for your response. Any sample code formultiple data reading?  Here I give scaning and connection parameters.

    struct bt_le_scan_param scan_param = {
          .type = BT_LE_SCAN_TYPE_ACTIVE,
          .options = BT_HCI_LE_SCAN_FILTER_DUP_DISABLE,
          .interval = SCAN_INTERVAL,
          .window = SCAN_WINDOW,
      };
      
      struct bt_conn_le_create_param create_param = {
    		.options = BT_CONN_LE_OPT_NONE,
    		.interval = INIT_INTERVAL,
    		.window = INIT_WINDOW,
    		.interval_coded = 0,
    		.window_coded = 0,
    		.timeout = 0,
    	};
    	struct bt_le_conn_param conn_param = {
    		.interval_min = CONN_INTERVAL,
    		.interval_max = CONN_INTERVAL,
    		.latency = CONN_LATENCY,
    		.timeout = CONN_TIMEOUT,
    	};

  • You can refer to the multilink central sample for how to connect to multiple peripherals at once. This does not actually read any data or do anything else, but for that you esentially just iterate/loop through all connected devices and read them one by one (all connection related API calls takes a bt_conn parameter that is a handle tot hat specific connection).

  • main.c

    /*
     * Copyright (c) 2012-2014 Wind River Systems, Inc.
     *
     * SPDX-License-Identifier: Apache-2.0
     */
    #include "main.h"
    
    int dev_type;
    uint8_t pMAC[6];
    bool Discovered = false;
    uint8_t conn_count = 0;
    
    char central_pool[512] = {};
    driver_inst_t *gen_drivers[CONFIG_BT_MAX_CONN] = {};
    char d_name[16];
    struct bt_conn *conn_in_progress;
    struct bt_gatt_discover_params discover_params;
    static struct bt_uuid_16 uuid;
    
    volatile bool should_connect = true;
    
    static ble_state_e g_main_state;
    
    #define UART_DEVICE_NODE DT_NODELABEL(uart0)
    static const struct device *uart_dev = DEVICE_DT_GET(UART_DEVICE_NODE);
    
    K_MSGQ_DEFINE(todo, 36, 32, 4);
    
    //struct k_delayed_work conn_work, sec_work, kill_work;
    struct k_mutex my_mutex;
    
    //Test
    int i=-1;
    //
    
    /* size of stack area used by each thread */
    #define STACKSIZE 1024
    
    /* scheduling priority used by each thread */
    #define PRIORITY 0
    
    void send_data_pkt(uint8_t *pkt, uint16_t len)
    {
      for (int i = 0; i < len; i++) {
    		uart_poll_out(uart_dev, pkt[i]);
    	}
    }
    
    void main_set_ble_state(ble_state_e state)
    {
      g_main_state = state;
    }
    
    static uint16_t heartrate_main_init(void)
    {
    
      heartrate_init((driver_inst_t *)gen_drivers[i], d_name);
    }
    
    static uint16_t wellue_main_init(void)
    {
    
      wellue_init((driver_inst_t *)gen_drivers[i], d_name);
    }
    
    static uint16_t and_main_init(void)
    {
      //auth_cb_display.passkey_entry = passkey_entry;
      and_init((driver_inst_t *)gen_drivers[i], d_name);
    }
    
    static uint8_t svc_discover_func(struct bt_conn *conn,
                                     const struct bt_gatt_attr *attr,
                                     struct bt_gatt_discover_params *params)
    {
      k_mutex_lock(&my_mutex, K_FOREVER);
      uint8_t ret;
      
      if (!attr)
      {
        //printk("Discover complete\n");
        (void)memset(params, 0, sizeof(*params));
        generic_on_svc_disc_evt(gen_drivers[i], 0);
        goto done;
      }
    
       //printk("[SERVICE] handle %x\n", attr->handle);
    
      if (generic_on_svc_disc_evt(gen_drivers[i], attr))
      {
        // printk("Found service\n");
      }
    
      ret = BT_GATT_ITER_CONTINUE;
    
    done:
      return ret;
      k_mutex_unlock(&my_mutex);
    }
    
    static uint8_t char_discover_func(struct bt_conn *conn,
                                      const struct bt_gatt_attr *attr,
                                      struct bt_gatt_discover_params *params)
    {
      k_mutex_lock(&my_mutex, K_FOREVER);
      uint8_t ret;
      if (!attr)
      {
    
        // printk("Char discovery complete\n");
        memset(params, 0, sizeof(*params));
        generic_on_char_disc_evt(gen_drivers[i], attr);
        ret = BT_GATT_ITER_STOP;
        goto done;
      }
    
      // printk("[ATTRIBUTE] handle %x\n", attr->handle);
      if (generic_on_char_disc_evt(gen_drivers[i], attr))
      {
        // printk("Found characteristic\n");
      }
    
      ret = BT_GATT_ITER_CONTINUE;
    done:
      k_mutex_unlock(&my_mutex);
      return ret;
    }
    
    static uint8_t cccd_discover_func(struct bt_conn *conn,
                                      const struct bt_gatt_attr *attr,
                                      struct bt_gatt_discover_params *params)
    {
      k_mutex_lock(&my_mutex, K_FOREVER);
      uint8_t ret;
      if (!attr)
      {
        // printk("[CCCD] discovery complete\n");
        memset(params, 0, sizeof(*params));
        generic_on_cccd_disc_evt(gen_drivers[i], attr);
        ret = BT_GATT_ITER_STOP;
        goto done;
      }
    
      // printk("[CCCD] handle %x\n", attr->handle);
      if (generic_on_cccd_disc_evt(gen_drivers[i], attr))
      {
        // printk("Found cccd\n");
      }
    
      ret = BT_GATT_ITER_CONTINUE;
    done:
      k_mutex_unlock(&my_mutex);
      return ret;
    }
    
    void start_char_discovery(struct bt_conn *conn, uint16_t start_handle, uint16_t end_handle)
    {
      // printk("Char Start Handle %x - End Handle %x\n", start_handle, end_handle);
      discover_params.start_handle = start_handle;
      discover_params.end_handle = end_handle;
      discover_params.func = char_discover_func;
      discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
      bt_gatt_discover(conn, &discover_params);
    }
    
    void start_cccd_discovery(driver_inst_t *inst, uint16_t start_handle, uint16_t end_handle)
    {
      // printk("CCCD Start Handle %x - End Handle %x\n", start_handle, end_handle);
      struct bt_conn *conn = inst->conn;
      start_handle--;
      if (inst->common->init->quirks & QUIRK_FIND_INFO_BOUNDS)
        end_handle++;
      memcpy(&uuid, BT_UUID_GATT_CCC, sizeof(uuid));
      discover_params.uuid = &uuid.uuid;
      discover_params.start_handle = start_handle;
      discover_params.end_handle = end_handle;
      discover_params.func = cccd_discover_func;
      discover_params.type = BT_GATT_DISCOVER_DESCRIPTOR;
      bt_gatt_discover(conn, &discover_params);
    }
    
    static struct bt_gatt_subscribe_params subscribe_params[UUID_MAX];
    
    void subscribe(struct bt_conn *conn, uint16_t handle, uint16_t value_handle, uint16_t value, bt_gatt_notify_func_t notify_func, int cccd_index)
    {
      subscribe_params[cccd_index].notify = notify_func;
      subscribe_params[cccd_index].value = value;
      subscribe_params[cccd_index].value_handle = value_handle;
      subscribe_params[cccd_index].ccc_handle = handle;
    
      int err = bt_gatt_subscribe(conn, &subscribe_params[cccd_index]);
      if (err && err != -EALREADY)
      {
        //printk("Subscribe failed (err %d)\n", err);
      }
      else
      {
        //printk("[SUBSCRIBED] %x %x %x\n", handle, value_handle, value);
      }
    }
    
    static void initialize_discovery(struct bt_conn *conn)
    {
      if (Discovered)
      {
        //printk("Already discovered\n");
        return true;
      }
      Discovered = true;
      //printk("Starting discovery\n");
    
      //Presdiscovered //Comment test
      // if (gen_drivers[0]->common->init->uuids[0].handle)
      // {
      //   //printk("Using prediscovery\n");
         //generic_prediscover(gen_drivers[0]);
      //   return;
      // }
    //
      discover_params.uuid = 0;
      discover_params.func = svc_discover_func;
      discover_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
      discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
      discover_params.type = BT_GATT_DISCOVER_PRIMARY;
    
      int err = bt_gatt_discover(conn, &discover_params);
      if (err)
      {
        //printk("Discover failed(err %d)\n", err);
        return;
      }
      else
      {
        //printk("initialize_discovery success\n");
      }
    }
    
    
    static void connected(struct bt_conn *conn, uint8_t err)
    {
      //k_mutex_lock(&my_mutex, K_FOREVER); //TEST COMMENTED
    //TEST
    i++;
    printk("Value of i=%d\n",i);
    //
      gen_drivers[i] = (driver_inst_t *)central_pool;
      // printk("Connecting type %d - Size of object %d\n", dev_type, sizeof(driver_init_t));
      gen_drivers[i]->conn = conn;
      //i++;
      // conn_in_progress = 0;
    
      char addr[BT_ADDR_LE_STR_LEN];
      const bt_addr_le_t *daddr = bt_conn_get_dst(conn);
      memcpy(pMAC, daddr->a.val, 6);
      bt_addr_le_to_str(daddr, addr, sizeof(addr));
      main_set_ble_state(BLE_STATE_CONNECTED);
      if (err)
      {
        printk("Failed to connect to %s (%u)\n", addr, err);
    
        bt_conn_unref(conn_in_progress);
        conn_in_progress = NULL;
    
        start_scan();
        return;
      }
      conn_in_progress = NULL;
      conn_count++;
      if (conn_count <CONFIG_BT_MAX_CONN)
      {
        start_scan();
      }
      printk("Connected (%u): %s\n", conn_count, addr);
      switch (dev_type)
      {
      case RENPHOSCALE_TYPE:
        heartrate_main_init();
        initialize_discovery(conn);
        break;
      case WELLUE_TYPE:
        wellue_main_init();
        initialize_discovery(conn);
        break;
      case AND_TYPE:
        and_main_init();
        initialize_discovery(conn);
        break;
      default:
        break;
      }
      
    done:
      k_mutex_unlock(&my_mutex);
    }
    
    static void disconnected(struct bt_conn *conn, uint8_t reason)
    {
      char addr[BT_ADDR_LE_STR_LEN];
    
      k_mutex_lock(&my_mutex, K_FOREVER);
    
      bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
    
      printk("Disconnected: %s (reason 0x%02x)\n", addr, reason);
    
      // if (!conn)
      // {
      //   return;
      // }
    
      bt_conn_unref(conn);
      conn = NULL;
      if (conn_count < CONFIG_BT_MAX_CONN)
      {
        // printk("conn_cont=%d",conn_count);
        //gScanning = false;
        start_scan();
      }
      //conn_count--;
      // if ((conn_count == 1U)) {
    	// 	start_scan();
    	// }
      conn_count--;
    done:
      k_mutex_unlock(&my_mutex);
    }
    bool gScanning = false;
    
    bool start_scan()
    {
      if (gScanning)
      {
        printk("Scanning already running\n");
        return true;
      }
      int err;
    
      /* Use active scanning and disable duplicate filtering to handle any
       * devices that might update their advertising data at runtime. */
      struct bt_le_scan_param scan_param = {
          .type = BT_LE_SCAN_TYPE_ACTIVE,
          .options = BT_HCI_LE_SCAN_FILTER_DUP_DISABLE,
          .interval = 300,
          .window = 290,
      };
    
      err = bt_le_scan_start(&scan_param, device_found); // Call back function
    
      if (err)
      {
        printk("Scanning failed to start (err %d)\n", err);
        return;
      }
    
      printk("Scanning successfully started............................................\n");
    
      #if 0
      err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad),
                            sd, ARRAY_SIZE(sd));
      if (err)
      {
        printk("Advertising failed to start (err %d)\n", err);
        return false;
      }
    #endif
    
      gScanning = true;
      return true;
    }
    
    static bool le_param_req(struct bt_conn *conn, struct bt_le_conn_param *param)
    {
      char addr[BT_ADDR_LE_STR_LEN];
    
      bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
    
      // printk("LE conn param req: %s int (0x%04x, 0x%04x) lat %d to %d\n",
      //        addr, param->interval_min, param->interval_max, param->latency,
      //        param->timeout);
    
      return true;
    }
    
    static void le_param_updated(struct bt_conn *conn, uint16_t interval,
                                 uint16_t latency, uint16_t timeout)
    {
      char addr[BT_ADDR_LE_STR_LEN];
    
      bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
    
      k_mutex_lock(&my_mutex, K_FOREVER);
     
    
      if (dev_type == AND_TYPE)
      {
        int err = bt_conn_set_security(conn, BT_SECURITY_L2);
        if (err)
        {
          printk("Failed to set security\n");
        }
        else
        {
          //printk("bt_conn_set_security -> BT_SECURITY_L2\n");
        }
      }
      else
      {
        
        initialize_discovery(conn);
      }
    
      // initialize_discovery();
    done:
      k_mutex_unlock(&my_mutex);
    }
    
    static void security_changed(struct bt_conn *conn, bt_security_t level,
    			     enum bt_security_err err)
    {
      k_mutex_lock(&my_mutex, K_FOREVER);
    	char addr[BT_ADDR_LE_STR_LEN];
    
    	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
    
    	if (!err) {
    		//printk("Security changed: %s level %u", addr, level);
    	} else {
    		printk("Security failed: %s level %u err %d", addr,
    			level, err);
    	}
      done:
       k_mutex_unlock(&my_mutex);
    }
    static struct bt_conn_cb conn_callbacks = {
        .connected = connected,
        .disconnected = disconnected,
        .le_param_req = le_param_req,
        .le_param_updated = le_param_updated,
        .security_changed = security_changed,
    
    };
    
    /* Bluetooth initialization*/
    static void bt_ready(int err)
    {
    
      if (err)
      {
        printk("Bluetooth init failed (err %d)\n", err);
        return;
      }
    
      printk("Bluetooth initialized\n");
    
      heartrate_reserve();
      wellue_reserve();
      and_reserve();
    
      bt_conn_cb_register(&conn_callbacks);
    
    
      main_set_ble_state(BLE_STATE_SCANNING);
      start_scan();
    }
    // K_MUTEX_DEFINE(my_mutex);
    static void conn_update(struct k_work *work)
    {
      // printk("Forcing end of connect\n");
    
      if (conn_in_progress)
      {
        // printk("Fo real\n");
        bt_conn_disconnect(conn_in_progress, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
        conn_in_progress = 0;
        should_connect = true;
      }
    }
    
    
    void main(void)
    {
    
      int err;
      k_mutex_init(&my_mutex);
    
      if (!device_is_ready(uart_dev)) {
    		//printk("UART device not found!");
    		return;
    	}
      err = bt_enable(bt_ready);  
    }
    
    // TEST
    // K_THREAD_DEFINE(discovery_id, STACKSIZE, initialize_discovery, NULL, NULL, NULL,
    // 		PRIORITY, 0, 0);
        

    scan.c

    #include "main.h"
    #include "generic.h"
    
    bool need_connect = false;
    struct bt_conn *default_conn;
    	
    /* List all the devices arround the central device*/
    void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
    			 struct net_buf_simple *ad)
    {
     	//k_mutex_lock(&my_mutex, K_FOREVER);
    	bool need_connect =false;
    	struct bt_conn_le_create_param create_param = {
    		.options = BT_CONN_LE_OPT_NONE,
    		.interval = INIT_INTERVAL,
    		.window = INIT_WINDOW,
    		.interval_coded = 0,
    		.window_coded = 0,
    		.timeout = 0,
    	};
    	struct bt_le_conn_param conn_param = {
    		.interval_min = CONN_INTERVAL,
    		.interval_max = CONN_INTERVAL,
    		.latency = CONN_LATENCY,
    		.timeout = CONN_TIMEOUT,
    	};
    	
    	if(conn_in_progress){
    		return;
    	}
    	char name[40];
    	strcpy(name, ad->data);
    	if(strstr(name,"QN-Scale")!=NULL)
        {
    		need_connect =true;
            dev_type = RENPHOSCALE_TYPE;
            printk("Weighting Mechine found.....................\n");
        }
    	else if (strstr(name,"VTM 20F")!=NULL)
    	{
    		   need_connect =true;
               dev_type = WELLUE_TYPE;
    		   printk("Pulse Oximeter device found.....................\n");
    	}
    	else if (ad->len == 13)
    	{
    		need_connect = true;
    		dev_type = AND_TYPE;
    		printk("A&D Medical device found.....................\n");
    	}
    	
    	if(need_connect)
    	{
    		Discovered = false;
    		int err = bt_le_scan_stop();
    		if (err)
    		{
    			printk("Stop LE scan  (err %d)\n", err);
    		}
    		gScanning = false;
    		uint8_t strAddr[BT_ADDR_LE_STR_LEN];
    		bool res = bt_conn_exists_le(BT_ID_DEFAULT, addr);
    		bt_addr_le_to_str(addr, strAddr, sizeof(strAddr));
    		//printk("Address %s\n", strAddr);
    		if (res)
    		{
    			conn_in_progress = bt_conn_lookup_addr_le(BT_ID_DEFAULT, addr);
    			err = bt_conn_disconnect(conn_in_progress, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
    		}
    
    		err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, BT_LE_CONN_PARAM_DEFAULT,&conn_in_progress);
    		if(err)
    		{
    			printk("Error code of bt_conn_le_create %d\n", err);
    			start_scan();
        		return false;
    		}
    		
    
    	return true;
    	}
     	
       done:
          k_mutex_unlock(&my_mutex);
    }
    		

    generic.c

    #include "main.h"
    
    uint16_t nchar;
    
    uint32_t generic_uuid_register(driver_common_t *common, const driver_init_t *init)
    {
      common->init = init;
      return NRF_SUCCESS;
    }
    
    uint32_t generic_inst_init(driver_inst_t *inst, const driver_common_t *common, const char *name)
    {
          int ret = NRF_SUCCESS;
    
      inst->common = common;
      inst->discovered = false;
      inst->current_svc = -1;
      inst->current_char = -1;
      inst->current_cccd = -1;
      inst->new_bond = false;
      memcpy(inst->name, name, sizeof(inst->name));
    
      for (int i = 0; i < common->init->nuuids; i++)
      {
        inst->char_handles[i] = BLE_GATT_HANDLE_INVALID;
        inst->cccd_handles[i] = BLE_GATT_HANDLE_INVALID;
        inst->serv_handles[i] = BLE_GATT_HANDLE_INVALID;
        inst->serv_ehandles[i] = 0xFFFF;
        inst->char_ehandles[i] = 0xFFFF;
      }
      if (ret == NRF_SUCCESS && common->init->init_func)
      {
        common->init->init_func(inst);
      }
     
      return ret;
      
    }
    void generic_on_timeout(driver_inst_t *inst)
    {
      if (inst->common->init->timeout_func)
      {
        inst->common->init->timeout_func(inst);
      }
    }
    uint32_t generic_prediscover(driver_inst_t *inst)
     {
       for (int i = 0; i < inst->common->init->nuuids; i++)
       {
         inst->char_handles[i] = inst->common->init->uuids[i].handle;
         inst->cccd_handles[i] = inst->common->init->uuids[i].cccd_handle;
         inst->serv_handles[i] = inst->common->init->uuids[i].handle;
       }
       generic_enable_notif(inst);
     }
    
    static uint16_t get_handle_by_name(driver_inst_t *inst, int name)
    {
      //Check if this uuid is one we need to save
      for (int j = 0; j < inst->common->init->nuuids; j++)
      {
        if (inst->common->init->uuids[j].name == name)
        {
          return inst->char_handles[j];
        }
      }
      return -1;
    }
    static uint32_t send_pkt_without_resp(driver_inst_t *inst, uint16_t handle_ept, const uint8_t *data, uint8_t len)
    {
    
      bt_gatt_write_without_response(inst->conn, handle_ept, data, len, false);
      return NRF_SUCCESS;
    }
    uint32_t generic_send_pkt_without_resp(driver_inst_t *inst, int name, const uint8_t *data, uint8_t len)
    {
      uint16_t handle = get_handle_by_name(inst, name);
      return send_pkt_without_resp(inst, handle, data, len);
    }
    
    static  uint8_t notify_func(struct bt_conn *conn,
    		struct bt_gatt_subscribe_params *params,
    		const void *data, uint16_t length)
    {
    
        uint8_t ret;
    		//printk("[NOTIFICATION] data %u length %u\n", data, length);
    
      driver_inst_t *inst = 0;
      for (int i = 0; i < MAX_D; i++)
      {
        if (!gen_drivers[i]){
          continue;
        }
        if (gen_drivers[i]->conn != conn){
          continue;
        }
        inst = gen_drivers[i];
      }
    
         ret = BT_GATT_ITER_STOP;
      if (!inst)
      {
        //printk("Notify func: failed to find conn\n");
         goto done;
      }
    
      if (!data)
      {
        
        if (length)
        {
          //printk("[SUBSCRIBED]\n");
          ret = BT_GATT_ITER_STOP;
           goto done;
        }
        //printk("[UNSUBSCRIBED]\n");
        params->value_handle = 0;
        ret = BT_GATT_ITER_STOP;
         goto done;
       }
    
      int name = inst->common->init->uuids[nchar].name;
    
      if (inst->common->init->hvx_func)
      {
        inst->common->init->hvx_func(inst, name, data, length);
      }
       ret=BT_GATT_ITER_CONTINUE;
    done:
      return ret;
    }
    
    // static u8_t read_func(struct bt_conn *conn, int err,
    //                       struct bt_gatt_read_params *params,
    //                       const void *data, u16_t len, u16_t nchar)
    // {
    //   k_mutex_lock(&gen_mutex, K_FOREVER);
    //   driver_inst_t *inst = 0;
    //   for (int i = 0; i < MAX_D; i++)
    //   {
    //     if (!gen_drivers[i])
    //       continue;
    //     if (g_drivers[i]->conn != conn)
    //       continue;
    //     inst = gen_drivers[i];
    //   }
    
    //   if (!inst)
    //   {
    //     printk("Notify func: failed to find conn\n");
    //     goto done;
    //   }
    
    //   int name = inst->common->init->uuids[nchar].name;
    
    //   printk("[READ_RSP] idx %d\n", name);
    
    //   if (inst->common->init->hvx_func)
    //   {
    //     inst->common->init->hvx_func(inst, name, data, len);
    //   }
    // done:
    //   k_mutex_unlock(&gen_mutex);
    //   return BT_GATT_ITER_STOP;
    // }
    
    #define NOTIFY(n)                                                        \
      static uint8_t notify##n(struct bt_conn *conn,                         \
                            struct bt_gatt_subscribe_params *params,         \
                            const void *data, uint16_t length)               \
      {                                                                      \
        return notify_func(conn, params, data, length);                      \
      }
    
    // #define RDECLS(n)                                         \
    //   static u8_t read##n(struct bt_conn *conn, u8_t err,     \
    //                       struct bt_gatt_read_params *params, \
    //                       const void *data, u16_t length)     \
    //   {                                                       \
    //     return read_func(conn, err, params, data, length, n); \
    //   }
    
    NOTIFY(0);
    NOTIFY(1);
    NOTIFY(2);
    NOTIFY(3);
    NOTIFY(4);
    NOTIFY(5);
    // RDECLS(0);
    // RDECLS(1);
    // RDECLS(2);
    // RDECLS(3);
    // RDECLS(4);
    static const bt_gatt_notify_func_t nfuncs[UUID_MAX]={notify0,notify1,notify2,notify3,notify4,notify5};
    //static const bt_gatt_read_func_t rfuncs[UUID_MAX] = {read0, read1, read2, read3, read4 };
    
    static struct bt_gatt_read_params params[UUID_MAX];
    
    void generic_enable_notif(driver_inst_t *inst)
    {
      if (inst->discovered)
        return;
    
      //printk("Notifications enabled\n");
    
      for (int i = inst->current_cccd + 1; i < inst->common->init->nuuids; i++)
      {
        if (inst->common->init->uuids[i].cccd && (inst->common->init->uuids[i].donotsubscribe == 0))
        {
          inst->current_cccd = i;
    
          subscribe(inst->conn, inst->cccd_handles[i], inst->char_handles[i], inst->common->init->uuids[i].cccd, nfuncs[i], i);
    
        }
      }
    
      inst->discovered = true;
      if (inst->common->init->connect_func != NULL)
      {
        inst->common->init->connect_func(inst);
      }
    }
    
    void generic_enable_notif_for_handle(driver_inst_t *inst, int name, bool indicate)
    {
      if (indicate)
      {
        subscribe(inst->conn, inst->cccd_handles[name], inst->char_handles[name], BLE_GATT_HVX_INDICATION, nfuncs[name], name);
      }
      else
      {
        subscribe(inst->conn, inst->cccd_handles[name], inst->char_handles[name], BLE_GATT_HVX_NOTIFICATION, nfuncs[name], name);
      }
    }
    
    bool compare_uuids(const u_t *a, const u_t *b, uint16_t mask)
    {
      
      if (a->uuid.type != b->uuid.type)
        return false;
      if (a->uuid.type == BT_UUID_TYPE_16)
        return memcmp(&a->u16.val, &b->u16.val, 2) == 0;
    
      if (memcmp(a->u128.val, b->u128.val, 16) != 0)
      {
        return false;
      }
      return true;
    }
    
    bool scan_chars(driver_inst_t *inst, int svc)
    {
      inst->current_svc = svc;
      inst->current_char = -1;
      bool found = false;
      for (int i = 0; i < inst->common->init->nuuids; i++)
      {
        if (inst->common->init->uuids[i].service != inst->common->init->uuids[svc].name)
          continue;
        inst->char_ehandles[i] = inst->serv_ehandles[svc];
        found =true;
      }
      if (!found){
        return false;
      }
      
      start_char_discovery(inst->conn, inst->serv_handles[svc] + 1, inst->serv_ehandles[svc]);
      return true;
    }
    
    bool generic_on_svc_disc_evt(driver_inst_t *inst, const struct bt_gatt_attr *attr)
    {
       
      if (!attr)
      {
      
        for (int i = 0; i < inst->common->init->nuuids; i++)
        {
          
          if (inst->common->init->uuids[i].name == inst->common->init->uuids[i].service)
          {
            if (scan_chars(inst, i))
            {
              return false;
            }  
          }
        }
        return false;
      }
      //printk("sdfghjkl\n");
      char str[BT_UUID_STR_LEN];
    	struct bt_gatt_service_val * gatt_service = attr->user_data;
    	bt_uuid_to_str(gatt_service->uuid, str, sizeof(str));
      u_t* my_uuid = (u_t*)gatt_service->uuid;
      struct bt_uuid_16 uuid = my_uuid->u16;
      //printk("Service: %s\n", str);
    
      if (inst->current_svc >= 0)
      {
        if (attr->handle <= inst->serv_ehandles[inst->current_svc])
        {
          inst->serv_ehandles[inst->current_svc] = attr->handle - 1;
        }
      }
    
    
      for (int i = 0; i < inst->common->init->nuuids; i++)
      {
        if (inst->common->init->uuids[i].name != inst->common->init->uuids[i].service)
          continue;
        if (compare_uuids(my_uuid, &inst->common->init->uuids[i].uuid, inst->common->init->uuids[i].mask))
        {
          inst->serv_handles[i] = attr->handle;
          inst->current_svc = i;
          return true;
        }
      }
      return false;
    }
    
    static void do_connect(driver_inst_t *inst)
    {
      //printk("Discovery completed\r\n");
      inst->current_cccd = -1;
      if (inst->common->init->presub_func)
        inst->common->init->presub_func(inst);
      generic_enable_notif(inst);
    }
    
    bool generic_on_cccd_disc_evt(driver_inst_t *inst, const struct bt_gatt_attr *attr)
    {
    
      if (!attr)
      {
        for (int i = inst->current_char + 1; i < inst->common->init->nuuids; i++)
        {
          if (inst->common->init->uuids[i].name == inst->common->init->uuids[i].service)
            continue;
          if (!inst->common->init->uuids[i].cccd)
            continue;
          inst->current_char = i;
          start_cccd_discovery(inst, inst->char_handles[i] + 1, inst->char_ehandles[i]);
          return false;
        }
        //printk("All cccd's discovered..........................................................\n");
        do_connect(inst);
        return false;
      }
      inst->cccd_handles[inst->current_char] = attr->handle;
      return true;
    }
    
    static void print_chrc_props(uint8_t properties)
    {
    	if (properties & BT_GATT_CHRC_BROADCAST) {
    		//printk("Properties:  BT_GATT_CHRC_BROADCAST\n");
    	}
    
    	if (properties & BT_GATT_CHRC_READ) {
    		//printk("Properties: BT_GATT_CHRC_READ\n");
    	}
    
    	if (properties & BT_GATT_CHRC_WRITE) {
    		//printk("Properties: BT_GATT_CHRC_WRITE\n");
    	}
    
    	if (properties & BT_GATT_CHRC_WRITE_WITHOUT_RESP) {
    		//printk("Properties: BT_GATT_CHRC_WRITE_WITHOUT_RESP\n");
    	}
    
    	if (properties & BT_GATT_CHRC_NOTIFY) {
    		//printk("Properties: BT_GATT_CHRC_NOTIFY\n");
    	}
    
    	if (properties & BT_GATT_CHRC_INDICATE) {
    		//printk("Properties: BT_GATT_CHRC_INDICATE\n");
    	}
    
    	if (properties & BT_GATT_CHRC_AUTH) {
    		//printk("Properties: BT_GATT_CHRC_AUTH\n");
    	}
    
    	if (properties & BT_GATT_CHRC_EXT_PROP) {
    		//printk("Properties: BT_GATT_CHRC_EXT_PROP\n");
    	}
    }
    bool generic_on_char_disc_evt(driver_inst_t *inst, const struct bt_gatt_attr *attr)
    {
      if (!attr)
      { 
        //printk("End of char discovery\n");
        for (int i = inst->current_svc + 1; i < inst->common->init->nuuids; i++)
        {
          if (inst->common->init->uuids[i].name == inst->common->init->uuids[i].service)
          {
            scan_chars(inst, i);
            return false;
          }
        }
        //printk("All chars discovered\n");
    
        for (int i = 0; i < inst->common->init->nuuids; i++)
        {
        
          if (inst->common->init->uuids[i].name == inst->common->init->uuids[i].service){
            continue;
          }
          if (!inst->common->init->uuids[i].cccd){
            continue;
          }
           
          inst->current_char = i;      
          start_cccd_discovery(inst, inst->char_handles[i] + 1, inst->char_ehandles[i]);
          
          return false;
        }
        //printk("All cccd's discovered\n");
        do_connect(inst);
    
        return false;
      }
      char str[BT_UUID_STR_LEN];
      struct bt_gatt_chrc *value = (struct bt_gatt_chrc *)attr->user_data;
      bt_uuid_to_str(value->uuid, str, sizeof(str));
      u_t *uuid = (u_t *)value->uuid;
    
      print_chrc_props(value->properties);
    
      if (inst->current_char >= 0)
      {
        if (attr->handle <= inst->char_ehandles[inst->current_char])
        {
        	inst->char_ehandles[inst->current_char] = attr->handle - 1;
        }
      }
    
      for (int i = 0; i < inst->common->init->nuuids; i++)
      {
        if (compare_uuids(uuid, &inst->common->init->uuids[i].uuid, inst->common->init->uuids[i].mask))
        {
          inst->char_handles[i] = value->value_handle;
          inst->current_char = i;
          return true;
        }
      }
      return false;
    }

    This is the main codes used my project. Please give any corrections. 

  • Looking at this briefly it does not look like you are trying to make more than one connection? Perhaps I misunderstood what you want to do. Can you elaborate on what you want to do, what you are implementing it the way you are, and in what way it is not working?

Related