-->

How to send the text data to CC2541 keyfob via And

2019-05-25 04:59发布

问题:

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.

回答1:

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);
}
  • [1] bluetooth.org
  • [2] getService
  • [3] writeCharacteristic
  • [4] devzone.nordicsemi.com


回答2:

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.