SimpleBLE

Connect

Connect to a BLE peripheral and inspect its services, characteristics, and descriptors.

The C examples include <stdio.h> and <simplecble/simplecble.h> and borrow the peripheral handle passed to them. See the C tutorial for acquisition and cleanup.

Connecting moves from BLE advertisements into the GATT database. Once connected, SimpleBLE resolves services and characteristics so you can decide which characteristic to read, write, notify, or indicate.

Flow

  1. Scan for nearby devices.
  2. Keep only peripherals that are connectable.
  3. Let the user or application logic pick one.
  4. Connect.
  5. Enumerate services, characteristics, capabilities, and descriptors.
  6. Disconnect when finished.

Connect and list GATT objects

SimpleBLE::Peripheral peripheral = peripherals[selected_index];

peripheral.connect();

std::cout << "MTU: " << peripheral.mtu() << std::endl;
for (auto& service : peripheral.services()) {
    std::cout << "Service: " << service.uuid() << std::endl;

    for (auto& characteristic : service.characteristics()) {
        std::cout << "  Characteristic: " << characteristic.uuid() << std::endl;
        std::cout << "    read=" << characteristic.can_read()
                  << " notify=" << characteristic.can_notify()
                  << " write_request=" << characteristic.can_write_request()
                  << " write_command=" << characteristic.can_write_command()
                  << std::endl;
    }
}

peripheral.disconnect();
bool connect_and_inspect(simpleble_peripheral_t peripheral) {
    simpleble_error_t* error = NULL;
    simpleble_peripheral_connect(peripheral, &error);
    if (error) {
        fprintf(stderr, "%s\n", simpleble_error_message(error));
        simpleble_error_release(&error);
        return false;
    }

    size_t count = simpleble_peripheral_services_count(peripheral, &error);
    for (size_t i = 0; i < count && !error; i++) {
        simpleble_service_t service = {0};
        simpleble_peripheral_services_get(peripheral, i, &service, &error);
        if (!error) {
            printf("Service: %s\n", service.uuid.value);
            for (size_t j = 0; j < service.characteristic_count; j++) {
                printf("  Characteristic: %s\n", service.characteristics[j].uuid.value);
            }
        }
        simpleble_service_release(&service);
    }

    bool success = error == NULL;
    if (error) fprintf(stderr, "%s\n", simpleble_error_message(error));
    simpleble_peripheral_disconnect(peripheral, &error);
    if (error) {
        fprintf(stderr, "%s\n", simpleble_error_message(error));
        success = false;
    }
    simpleble_error_release(&error);
    return success;
}
peripheral = peripherals[selected_index]

peripheral.connect()

print(f"MTU: {peripheral.mtu()}")
for service in peripheral.services():
    print(f"Service: {service.uuid()}")
    for characteristic in service.characteristics():
        print(f"  Characteristic: {characteristic.uuid()}")
        print(f"    Capabilities: {' '.join(characteristic.capabilities())}")

peripheral.disconnect()
Peripheral peripheral = peripherals.get(selectedIndex);

peripheral.connect();

System.out.println("MTU: " + peripheral.getMtu());
for (Service service : peripheral.services()) {
    System.out.println("Service: " + service.uuid());

    for (Characteristic characteristic : service.characteristics()) {
        System.out.println("  Characteristic: " + characteristic.uuid());
        System.out.println("    read=" + characteristic.canRead()
            + " notify=" + characteristic.canNotify()
            + " writeRequest=" + characteristic.canWriteRequest()
            + " writeCommand=" + characteristic.canWriteCommand());
    }
}

peripheral.disconnect();
let peripheral = adapter.scan_get_results().unwrap().remove(selected_index);

peripheral.connect().unwrap();

println!("MTU: {}", peripheral.mtu().unwrap());
for service in peripheral.services().unwrap() {
    println!("Service: {}", service.uuid());

    for characteristic in service.characteristics() {
        println!("  Characteristic: {}", characteristic.uuid());
        println!("    Capabilities: {:?}", characteristic.capabilities());
    }
}

peripheral.disconnect().unwrap();
const peripheral = adapter.scanGetResults()[selectedIndex];

await peripheral.connect();

console.log(`MTU: ${peripheral.mtu()}`);
for (const service of peripheral.services()) {
  console.log(`Service: ${service.uuid}`);
  for (const characteristic of service.characteristics) {
    console.log(`  Characteristic: ${characteristic.uuid}`);
    console.log(`    Capabilities: ${characteristic.capabilities.join(' ')}`);
  }
}

await peripheral.disconnect();
const peripheral = adapter.scanGetResults()[selectedIndex];

await peripheral.connect();

console.log(`MTU: ${peripheral.mtu()}`);
for (const service of peripheral.services()) {
  console.log(`Service: ${service.uuid}`);
  for (const characteristic of service.characteristics) {
    console.log(`  Characteristic: ${characteristic.uuid}`);
    console.log(`    Capabilities: ${characteristic.capabilities.join(' ')}`);
  }
}

await peripheral.disconnect();
val peripheral = adapter.scanGetResults()[selectedIndex]

peripheral.connect()

println("MTU: ${peripheral.mtu}")
for (service in peripheral.services()) {
    println("Service: ${service.uuid}")
    for (characteristic in service.characteristics) {
        println("  Characteristic: ${characteristic.uuid}")
        println("    notify=${characteristic.canNotify} read=${characteristic.canRead}")
    }
}

peripheral.disconnect()
val peripheral = selectedPeripheral

peripheral.connect()

Log.d("SimpleBLE", "MTU: ${peripheral.mtu}")
val services = peripheral.services()
for (service in services) {
    Log.d("SimpleBLE", "Service: ${service.uuid}")

    for (characteristic in service.characteristics) {
        Log.d("SimpleBLE", "  Characteristic: ${characteristic.uuid}")
        Log.d("SimpleBLE", "    notify=${characteristic.canNotify} read=${characteristic.canRead}")
    }
}

peripheral.disconnect()

Selection tips

  • Prefer filtering by advertised service UUID when your peripheral advertises it.
  • If several peripherals use the same name, show the address/identifier and RSSI to the user.
  • Treat macOS/iOS identifiers as host-local UUIDs, not stable global MAC addresses.
  • Always disconnect when your workflow is done, especially in command-line tools and tests.

After you can connect and list characteristics, continue to Read, Write, Notify.

On this page