Oscar
Oscar

Reputation: 13

BLE Trouble Supporting Different Android Devices

We are creating an Android app that connects to a device using the Bluegiga BLE113. We are having issues pairing the device to certain Android devices. Samsung devices seem to be having no problem but others like Oneplus and LG don't always cooperate. We are getting notifications like "Couldn't pair because of an incorrect PIN or passkey" or "Pairing rejected" even though there is no PIN or passkey.

Anyone encounter issues like these and know what's going on?

Upvotes: 1

Views: 2237

Answers (2)

SJoshi
SJoshi

Reputation: 1976

I just wrote an entire post on Pairing with the BLE113 (BGScript) - please take a look here:

http://www.sureshjoshi.com/embedded/bgscript-pairing-hell/

Additionally, check out my Github with examples:

https://github.com/sureshjoshi/ble113-firmware-examples

And just for simplicity, here is an entire BGScript code file for you:

# Connection and Pairing
dim is_connected
dim current_bond_handle

const LED_PIN = $01  # P0_0
const LED_PORT = 0

const ENCRYPTED_VALUE = 42

const TICKS_PER_SECOND = 32760
const ENCRYPTION_TIMEOUT_SECONDS = 1
const ENCRYPTION_TIMER_HANDLE = 0


# Incoming data event listener
event attributes_value(connection, reason, handle, offset, value_len, value_data)

    if handle = device_reset then
        # Command 1 received, reset device
        if value_data(0:1) = 1 then  
            call system_reset(0)
        end if
    end if
end

event system_boot(major, minor, patch, build, ll_version, protocol_version, hw)

    is_connected = 0
    current_bond_handle = $ff

    # configure P0.0 as output, others as input
    call hardware_io_port_config_direction(LED_PORT, LED_PIN)

    # Set advertisement interval
    call gap_set_adv_parameters(320, 480, 7)

    # Put module into discoverable/connectable mode
    call gap_set_mode(gap_general_discoverable, gap_undirected_connectable)

    # Set Bondable mode
    call sm_set_bondable_mode(1)

    # Turn on the LED
    call hardware_io_port_write(LED_PORT, LED_PIN, LED_PIN)
end


event hardware_soft_timer(handle) 
    # Other side hasn't tried an encrypted link yet even though we are
    # bonded as far as we know, so try to start it from this end
    if handle = ENCRYPTION_TIMER_HANDLE then
        call sm_encrypt_start(0, 1)
    end if 
end


# Custom read requests
event attributes_user_read_request(connection, handle, offset, maxsize)

    if handle = xgatt_encrypted_value then 
        call attributes_user_read_response(connection, 0, 1, ENCRYPTED_VALUE)
    end if
end

event connection_status(connection, flags, address, address_type, conn_interval, timeout, latency, bonding)
    # Set up a connection interval of between 6*1.25ms to 10*1.25ms (7.5-12.5ms)
    # Android and iOS respond to connection interval updates, but cannot set them (they also have minimums)
    if is_connected = 0 then
        call connection_update(connection, 6, 10, latency, timeout)
    end if
    is_connected = 1

    # Use whatever bonding handle we're given (used in case of bond failure)
    current_bond_handle = bonding

    # If we're not yet encrypted, request encryption 
    if (flags & $02) != $02 then 
         # Request encryption if not encrypted already
        if bonding = $ff then
            call sm_encrypt_start(connection, 1)
        else
            # Start one-shot encryption attempt timer in case the remote side doesn't attempt an encrypted link within 1 second 
            # (this might happen if you bond with a smartphone and then remove the pairing info from the phone side, but not the local module side)
            # Only seems to work on iOS - Android rejects the pairing a few times - works eventually...
            call hardware_set_soft_timer(ENCRYPTION_TIMEOUT_SECONDS * TICKS_PER_SECOND, ENCRYPTION_TIMER_HANDLE, 1)
        end if
    end if
end

# Disconnection event listener
event connection_disconnected(handle, result)

    # Reset the current_bond_handle
    current_bond_handle = $ff

    # Make peripheral discoverable
    call gap_set_mode(gap_general_discoverable, gap_undirected_connectable)
end

event sm_bonding_fail(handle, result)

    # If bonding fails, handle it gracefully based on the following possible results:
    # - 0x018B - Out of bonds (no space left, all 8 bonding slots taken)
    # - 0x0205 - Authentication failure (shouldn't happen with "just works" mode, but might otherwise)
    # - 0x0206 - Pin or key missing (probably local or remote device is missing the key, but not both)
    # - 0x0301 - Passkey entry failed (also shouldn't happen in "just works" mode unless bonding is cancelled)
    # - 0x0302 - OOB data not available (only occurs if OOB is required and not supported on both ends)
    # - 0x0303 - Authentication requirements (I/O capabilities required but not supported)
    # - 0x0304 - Confirm value failed (PIN entry/comparison attempted but failed)
    # - 0x0305 - Pairing not supported (also occurs if bond info removed from remote device but not local module)
    # - 0x0306 - Encryption key size (key size insufficient to meet security requirements)
    # - 0x0307 - Command not supported (SMP command is not supported on this device)
    # - 0x0308 - Unspecified reason (may occur if bond info is present remotely but not locally)
    # - 0x0309 - Repeated attempts (too little time has elapsed since last pairing/security request)
    # - 0x030A - Invalid parameters (bad parameters sent during pairing/bonding process)


    # NOTE: The most common cases:
    # - 0x018B, which means you ran out of space and must remove at least one bond in order to bond again
    # - 0x0206, which typically means the pairing info was removed on the remote device but not locally
    # - 0x0301, which typically means the user cancelled the pairing request or entered the wrong passkey
    # - 0x0305, which is like 0x0206 but is often generated instead if the remote device is a smartphone
    # - 0x0308, which typically means the pairing info was removed on the local device but not remotely
    if result = $018b then
        # Only solved by removing bonds - requires the user to reset the bonds...
    end if

    if result = $0301 then
        # Usually solved simply by trying again
        # Seems to solve most problems on iOS 
        # On Android, pairing rejected a few times if Android deleted pairing without informing device
        call sm_encrypt_start(0, 1)
    end if

    if result = $0305 || result = $0206 then
        # Remove local bonding info first, then the remote device needs to reconnect
        # If current_bond_handle is $ff, that means we don't have a bonding handle - so not much we can do
        if current_bond_handle != $ff then
            call sm_delete_bonding(current_bond_handle)
        end if

        # Sometimes takes a few tries
        call connection_disconnect(0)
    end if

    if result = $0308 then
        # Remove remote bonding info first, then the remote device needs to reconnect
        # Android can recover automatically, iOS cannot
        # Instead of disconnecting, just force a re-encryption... Usually works
        call sm_encrypt_start(0, 1)
    end if
end

Upvotes: 0

Ted
Ted

Reputation: 76

Are you connecting to the Android device with bondable mode enabled?

i.e.: call sm_set_bondable_mode(1) in BGScript

If so, you could be getting "Pairing rejected" if the bonding info is out of sync. To fix this, try clearing the bonding information with:

call sm_delete_bonding(handle)(result)

Bonding can get out of sync if you do something like this:

  1. Pair the BLE113 and Android
  2. Disconnect the BLE113 from the Android
  3. "Unpair" the BLE113 on the Android
  4. Cycle the Bluetooth power on the Android
  5. Try to connect again

Upvotes: 1

Related Questions