2

I am developing an application where I have to connect to Bluetooth device on Android 4.3.

And I want to change the name of CC2541 Keyfob via the Android application.

My ideas is:

1.There has a Plain Text that I can type the name what I want in my Android application.

2.After I type the name, I push the button to send this text.

3.If the CC2541 receive this text from Android application , it will change the text in the deviceName[] of the following code in keyfobdemo.c:

static uint8 deviceName[] =
{
// complete name
0x0b, // length of first data structure (11 bytes excluding length byte)
0x09, // AD Type = Complete local name
0x4b, // 'K'
0x65, // 'e'
0x79, // 'y'
0x66, // 'f'
0x6f, // 'o'
0x62, // 'b'
0x64, // 'd'
0x65, // 'e'
0x6d, // 'm'
0x6f, // 'o'
};

The question like the following:

1.How to send the text data to CC2541 keyfob in Android application 4.3 ??

2.How to receive the text data on CC2541 side ??

3.Did I need to use any profile ??

Sorry about my English, and these question.

Thanks for your direction.


Edit

I have trying to use 0x2A00 to get the Device Name service , but it seen not working when I call the Device_Name function.

The Name_Service is null.

private static final UUID Device_Name_UUID = UUID.fromString("00002a00-0000-1000-8000-00805f9b34fb");
private static final UUID Write_UUID = UUID.fromString("00001800-0000-1000-8000-00805f9b34fb");





    public void Device_Name(){
        BluetoothGattService Name_Service = mBluetoothGatt.getService(Write_UUID );
        if(Name_Service == null) {
            Log.d(TAG, "Name_Service service not found!");
            return;
        }

        BluetoothGattCharacteristic DeviceName = Name_Service.getCharacteristic(Device_Name_UUID);
        if(DeviceName == null) {
            Log.d(TAG, "DeviceName charateristic not found!");
            return;
        }



    }


Log.v(TAG, "readCharacteristic(DeviceName) = " + mBluetoothGatt.readCharacteristic(DeviceName));

String i = "123";       
DeviceName.setValue(i);
Log.v(TAG, "writeCharacteristic(DeviceName) = " + mBluetoothGatt.writeCharacteristic(DeviceName));

it show the following Log:

V/BluetoothLeService( 3680): readCharacteristic(DeviceName) = true
V/BluetoothLeService( 3680): writeCharacteristic(DeviceName) = false
D/audio_hw_primary( 1752): found out /dev/snd/pcmC0D0p
W/audio_hw_primary( 1752): out_write() limiting sleep time 45351 to 23219
W/audio_hw_primary( 1752): out_write() limiting sleep time 34263 to 23219
W/audio_hw_primary( 1752): out_write() limiting sleep time 33696 to 23219
D/BtGatt.btif( 2646): btif_gattc_upstreams_evt: Event 3
I/BtGatt.btif( 2646): set_read_value unformat.len = 13 
D/BtGatt.GattService( 2646): onReadCharacteristic() - address=90:59:AF:0B:8A:AB, status=0, length=13
D/BluetoothGatt( 3680): onCharacteristicRead() - Device=90:59:AF:0B:8A:AB UUID=00002a00-0000-1000-8000-00805f9b34fb Status=0

it read successful,and I can get the name of device.

And I reference the Bluetooth Page-Device Name , the format is UTF-8 String. But it writeCharacteristic false.

Wun
  • 6,211
  • 11
  • 56
  • 101
  • The problem with your code is that you cannot do getService with a non-service UUID. The device name attribute is _always_ found in the Generic Access Profile service ("00001800-0000-1000-8000-00805f9b34fb") – Vegar Westerlund Nov 19 '13 at 23:07
  • @VegarWesterlund: I read Characteristic , but write false by writeCharacteristic. Do you have suggested ?? – Wun Nov 22 '13 at 02:36

2 Answers2

3

I don't know about the Android BLE API, but I can tell you how this is supposed to work with Bluetooth Low Energy.

The device name is stored in the GATT server (a local database on the cc2541 device). If you connect to the BLE device you should be able to do a discover to figure out the structure of the database and find the ATT handle for the device name.

The GATT server is built up of attributes with a UUID (loosely defining the type of attribute) an attribute handle (the identifier used in this instance of the GATT server) and a value. According to [1] the UUID for the device name is 0x2A00. So you can search by type and find the handle with this UUID.

Once you have the UUID it's just a matter of using the GATT client in the Android API to send a write request to this handle with the new value

Edit: Looking at the API I think you should use getService(0x18, 0x00) [2] to get the primary service (which should contain the device name) and then writeCharacteristic[3] to update the name.

From [4] it looks like the code should look something like this (not tested):

public void writeCharacteristic(byte[] value) {
    BluetoothGattService gap_service = mBluetoothGatt.getService(
            UUID.fromString("00001800-0000-1000-8000-00805F9B34FB"));
    if (gap_service == null) {
        System.out.println("gap_service null";);
        return;
    }
    BluetoothGattCharacteristic dev_name = gap_service.getCharacteristic(
            UUID.fromString("00002A00-0000-1000-8000-00805F9B34FB"));
    if (dev_name == null) {
        System.out.println("dev_name null";);
        return;
    }
    dev_name.setValue(value);
    boolean status = mBluetoothGatt.writeCharacteristic(dev_name);
    System.out.println("Write Status: " + status);
}
Vegar Westerlund
  • 1,604
  • 3
  • 16
  • 24
  • Tahnks for you, Westerlund. But I still trying to use 0X2A00 to write the device name , not success yet... – Wun Nov 18 '13 at 06:12
  • @martin-wun: Are you using 0x2a00 as the UUID or the handle? You first need to find the attribute handle for UUID 0x2a00. There are several different ways of doing this, not sure what is easiest on Android. Then when you want to do the write you need to specify the handle, not the UUID. – Vegar Westerlund Nov 18 '13 at 08:19
  • Ok, so the handle is a dead end. The Android API abstracts that away so you don't have to think about it. I think I found what you need here[1]. I will update my answer. [1] https://devzone.nordicsemi.com/index.php/writing-to-a-characteristic-using-the-android-4-3-api – Vegar Westerlund Nov 19 '13 at 22:24
  • I read Characteristic , but write false by writeCharacteristic. Do you have suggested ?? – Wun Nov 22 '13 at 02:35
  • @Wun you always need to wait for the callback before you write/read/set notifications/etc. The BLE library on Android only handles one at a time, or the immediate response is false and your action is ignored – AllDayAmazing Feb 03 '15 at 19:59
0

This is my solution, adding to Vegar's background information about GATT, profiles, etc.

This is based on the simpleBLEPeripheral application in the CC2541 SDK, and the sensortag Android application. The simpleBLEPeripheral characteristic lets you read a multiple byte characteristic, I modified it to enable writes. The simpleGATTprofile.c simpleProfile_WriteAttrCB() method needs an additional case statement:

  case SIMPLEPROFILE_CHAR5_UUID:

    //Validate the value
    // Make sure it's not too long

    if ( len >= SIMPLEPROFILE_CHAR5_LEN )
    {
      status = ATT_ERR_INVALID_VALUE_SIZE;
    }

    //Write the value
    if ( status == SUCCESS )
    {
      uint8 *pCurValue = (uint8 *)pAttr->pValue;
      osal_memcpy(pCurValue+offset, pValue, len);

      notifyApp = SIMPLEPROFILE_CHAR5;    
    }

    break;

On the Android side, the following code is placed in DeviceActivity.java. Please forgive the messy code, it's a quick hack. It takes a string, finds the hex representation, which is then sent as a characteristic update to the CC2541.

 void writeString() {
    UUID servUuid = SensorTagGatt.UUID_STR_SERV;
    UUID configUuid = SensorTagGatt.UUID_STR_DATA;
    BluetoothGattService serv = mBtGatt.getService(servUuid);
    BluetoothGattCharacteristic config = serv.getCharacteristic(configUuid);

    int OAD_BLOCK_SIZE = 18;
    int OAD_BUFFER_SIZE = OAD_BLOCK_SIZE + 2;
    int GATT_WRITE_TIMEOUT = 300; // Milliseconds

    String msg = new String();
    byte[] mOadBuffer = hexStringToByteArray("e04fd020ea3a6910a2d808002b30309daabbccdd");

    // Send block
    config.setValue(mOadBuffer);
    boolean success = mBtLeService.writeCharacteristic(config);

    if (success) {
        // Update stats
        if (!mBtLeService.waitIdle(GATT_WRITE_TIMEOUT)) {
            success = false;
            msg = "GATT write timeout\n";
        }
    } else {
        msg = "GATT writeCharacteristic failed\n";
    }
    if (!success) {
        Toast.makeText(this,msg,Toast.LENGTH_SHORT).show();
    }

}

public static byte[] hexStringToByteArray(String s) {
    int len = s.length();
    byte[] data = new byte[len / 2];
    for (int i = 0; i < len; i += 2) {
        data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                + Character.digit(s.charAt(i+1), 16));
    }
    return data;
}

The key is to make sure your UUIDs match up, otherwise nothing will work.

Dan Luong
  • 41
  • 3