1/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package android.bluetooth;
17
18import java.util.ArrayList;
19import java.util.IllegalFormatConversionException;
20import java.util.List;
21import java.util.UUID;
22
23/**
24 * Represents a Bluetooth GATT Characteristic
25 *
26 * <p>A GATT characteristic is a basic data element used to construct a GATT service,
27 * {@link BluetoothGattService}. The characteristic contains a value as well as
28 * additional information and optional GATT descriptors, {@link BluetoothGattDescriptor}.
29 */
30public class BluetoothGattCharacteristic {
31
32    /**
33     * Characteristic proprty: Characteristic is broadcastable.
34     */
35    public static final int PROPERTY_BROADCAST = 0x01;
36
37    /**
38     * Characteristic property: Characteristic is readable.
39     */
40    public static final int PROPERTY_READ = 0x02;
41
42    /**
43     * Characteristic property: Characteristic can be written without response.
44     */
45    public static final int PROPERTY_WRITE_NO_RESPONSE = 0x04;
46
47    /**
48     * Characteristic property: Characteristic can be written.
49     */
50    public static final int PROPERTY_WRITE = 0x08;
51
52    /**
53     * Characteristic property: Characteristic supports notification
54     */
55    public static final int PROPERTY_NOTIFY = 0x10;
56
57    /**
58     * Characteristic property: Characteristic supports indication
59     */
60    public static final int PROPERTY_INDICATE = 0x20;
61
62    /**
63     * Characteristic property: Characteristic supports write with signature
64     */
65    public static final int PROPERTY_SIGNED_WRITE = 0x40;
66
67    /**
68     * Characteristic property: Characteristic has extended properties
69     */
70    public static final int PROPERTY_EXTENDED_PROPS = 0x80;
71
72    /**
73     * Characteristic read permission
74     */
75    public static final int PERMISSION_READ = 0x01;
76
77    /**
78     * Characteristic permission: Allow encrypted read operations
79     */
80    public static final int PERMISSION_READ_ENCRYPTED = 0x02;
81
82    /**
83     * Characteristic permission: Allow reading with man-in-the-middle protection
84     */
85    public static final int PERMISSION_READ_ENCRYPTED_MITM = 0x04;
86
87    /**
88     * Characteristic write permission
89     */
90    public static final int PERMISSION_WRITE = 0x10;
91
92    /**
93     * Characteristic permission: Allow encrypted writes
94     */
95    public static final int PERMISSION_WRITE_ENCRYPTED = 0x20;
96
97    /**
98     * Characteristic permission: Allow encrypted writes with man-in-the-middle
99     * protection
100     */
101    public static final int PERMISSION_WRITE_ENCRYPTED_MITM = 0x40;
102
103    /**
104     * Characteristic permission: Allow signed write operations
105     */
106    public static final int PERMISSION_WRITE_SIGNED = 0x80;
107
108    /**
109     * Characteristic permission: Allow signed write operations with
110     * man-in-the-middle protection
111     */
112    public static final int PERMISSION_WRITE_SIGNED_MITM = 0x100;
113
114    /**
115     * Write characteristic, requesting acknoledgement by the remote device
116     */
117    public static final int WRITE_TYPE_DEFAULT = 0x02;
118
119    /**
120     * Wrtite characteristic without requiring a response by the remote device
121     */
122    public static final int WRITE_TYPE_NO_RESPONSE = 0x01;
123
124    /**
125     * Write characteristic including authentication signature
126     */
127    public static final int WRITE_TYPE_SIGNED = 0x04;
128
129    /**
130     * Characteristic value format type uint8
131     */
132    public static final int FORMAT_UINT8 = 0x11;
133
134    /**
135     * Characteristic value format type uint16
136     */
137    public static final int FORMAT_UINT16 = 0x12;
138
139    /**
140     * Characteristic value format type uint32
141     */
142    public static final int FORMAT_UINT32 = 0x14;
143
144    /**
145     * Characteristic value format type sint8
146     */
147    public static final int FORMAT_SINT8 = 0x21;
148
149    /**
150     * Characteristic value format type sint16
151     */
152    public static final int FORMAT_SINT16 = 0x22;
153
154    /**
155     * Characteristic value format type sint32
156     */
157    public static final int FORMAT_SINT32 = 0x24;
158
159    /**
160     * Characteristic value format type sfloat (16-bit float)
161     */
162    public static final int FORMAT_SFLOAT = 0x32;
163
164    /**
165     * Characteristic value format type float (32-bit float)
166     */
167    public static final int FORMAT_FLOAT = 0x34;
168
169
170    /**
171     * The UUID of this characteristic.
172     * @hide
173     */
174    protected UUID mUuid;
175
176    /**
177     * Instance ID for this characteristic.
178     * @hide
179     */
180    protected int mInstance;
181
182    /**
183     * Characteristic properties.
184     * @hide
185     */
186    protected int mProperties;
187
188    /**
189     * Characteristic permissions.
190     * @hide
191     */
192    protected int mPermissions;
193
194    /**
195     * Key size (default = 16).
196     * @hide
197     */
198    protected int mKeySize = 16;
199
200    /**
201     * Write type for this characteristic.
202     * See WRITE_TYPE_* constants.
203     * @hide
204     */
205    protected int mWriteType;
206
207    /**
208     * Back-reference to the service this characteristic belongs to.
209     * @hide
210     */
211    protected BluetoothGattService mService;
212
213    /**
214     * The cached value of this characteristic.
215     * @hide
216     */
217    protected byte[] mValue;
218
219    /**
220     * List of descriptors included in this characteristic.
221     */
222    protected List<BluetoothGattDescriptor> mDescriptors;
223
224    /**
225     * Create a new BluetoothGattCharacteristic.
226     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
227     *
228     * @param uuid The UUID for this characteristic
229     * @param properties Properties of this characteristic
230     * @param permissions Permissions for this characteristic
231     */
232    public BluetoothGattCharacteristic(UUID uuid, int properties, int permissions) {
233        initCharacteristic(null, uuid, 0, properties, permissions);
234    }
235
236    /**
237     * Create a new BluetoothGattCharacteristic
238     * @hide
239     */
240    /*package*/ BluetoothGattCharacteristic(BluetoothGattService service,
241                                            UUID uuid, int instanceId,
242                                            int properties, int permissions) {
243        initCharacteristic(service, uuid, instanceId, properties, permissions);
244    }
245
246    private void initCharacteristic(BluetoothGattService service,
247                                    UUID uuid, int instanceId,
248                                    int properties, int permissions) {
249        mUuid = uuid;
250        mInstance = instanceId;
251        mProperties = properties;
252        mPermissions = permissions;
253        mService = service;
254        mValue = null;
255        mDescriptors = new ArrayList<BluetoothGattDescriptor>();
256
257        if ((mProperties & PROPERTY_WRITE_NO_RESPONSE) != 0) {
258            mWriteType = WRITE_TYPE_NO_RESPONSE;
259        } else {
260            mWriteType = WRITE_TYPE_DEFAULT;
261        }
262    }
263
264    /**
265     * Returns the deisred key size.
266     * @hide
267     */
268    /*package*/ int getKeySize() {
269        return mKeySize;
270    }
271
272    /**
273     * Adds a descriptor to this characteristic.
274     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
275     *
276     * @param descriptor Descriptor to be added to this characteristic.
277     * @return true, if the descriptor was added to the characteristic
278     */
279    public boolean addDescriptor(BluetoothGattDescriptor descriptor) {
280        mDescriptors.add(descriptor);
281        descriptor.setCharacteristic(this);
282        return true;
283    }
284
285    /**
286     * Get a descriptor by UUID and isntance id.
287     * @hide
288     */
289    /*package*/  BluetoothGattDescriptor getDescriptor(UUID uuid, int instanceId) {
290        for(BluetoothGattDescriptor descriptor : mDescriptors) {
291            if (descriptor.getUuid().equals(uuid)
292             && descriptor.getInstanceId() == instanceId) {
293                return descriptor;
294            }
295        }
296        return null;
297    }
298
299    /**
300     * Returns the service this characteristic belongs to.
301     * @return The asscociated service
302     */
303    public BluetoothGattService getService() {
304        return mService;
305    }
306
307    /**
308     * Sets the service associated with this device.
309     * @hide
310     */
311    /*package*/ void setService(BluetoothGattService service) {
312        mService = service;
313    }
314
315    /**
316     * Returns the UUID of this characteristic
317     *
318     * @return UUID of this characteristic
319     */
320    public UUID getUuid() {
321        return mUuid;
322    }
323
324    /**
325     * Returns the instance ID for this characteristic.
326     *
327     * <p>If a remote device offers multiple characteristics with the same UUID,
328     * the instance ID is used to distuinguish between characteristics.
329     *
330     * @return Instance ID of this characteristic
331     */
332    public int getInstanceId() {
333        return mInstance;
334    }
335
336    /**
337     * Returns the properties of this characteristic.
338     *
339     * <p>The properties contain a bit mask of property flags indicating
340     * the features of this characteristic.
341     *
342     * @return Properties of this characteristic
343     */
344    public int getProperties() {
345        return mProperties;
346    }
347
348    /**
349     * Returns the permissions for this characteristic.
350     *
351     * @return Permissions of this characteristic
352     */
353    public int getPermissions() {
354        return mPermissions;
355    }
356
357    /**
358     * Gets the write type for this characteristic.
359     *
360     * @return Write type for this characteristic
361     */
362    public int getWriteType() {
363        return mWriteType;
364    }
365
366    /**
367     * Set the write type for this characteristic
368     *
369     * <p>Setting the write type of a characteristic determines how the
370     * {@link BluetoothGatt#writeCharacteristic} function write this
371     * characteristic.
372     *
373     * @param writeType The write type to for this characteristic. Can be one
374     *                  of:
375     *                  {@link #WRITE_TYPE_DEFAULT},
376     *                  {@link #WRITE_TYPE_NO_RESPONSE} or
377     *                  {@link #WRITE_TYPE_SIGNED}.
378     */
379    public void setWriteType(int writeType) {
380        mWriteType = writeType;
381    }
382
383    /**
384     * Set the desired key size.
385     * @hide
386     */
387    public void setKeySize(int keySize) {
388        mKeySize = keySize;
389    }
390
391    /**
392     * Returns a list of descriptors for this characteristic.
393     *
394     * @return Descriptors for this characteristic
395     */
396    public List<BluetoothGattDescriptor> getDescriptors() {
397        return mDescriptors;
398    }
399
400    /**
401     * Returns a descriptor with a given UUID out of the list of
402     * descriptors for this characteristic.
403     *
404     * @return GATT descriptor object or null if no descriptor with the
405     *         given UUID was found.
406     */
407    public BluetoothGattDescriptor getDescriptor(UUID uuid) {
408        for(BluetoothGattDescriptor descriptor : mDescriptors) {
409            if (descriptor.getUuid().equals(uuid)) {
410                return descriptor;
411            }
412        }
413        return null;
414    }
415
416    /**
417     * Get the stored value for this characteristic.
418     *
419     * <p>This function returns the stored value for this characteristic as
420     * retrieved by calling {@link BluetoothGatt#readCharacteristic}. The cached
421     * value of the characteristic is updated as a result of a read characteristic
422     * operation or if a characteristic update notification has been received.
423     *
424     * @return Cached value of the characteristic
425     */
426    public byte[] getValue() {
427        return mValue;
428    }
429
430    /**
431     * Return the stored value of this characteristic.
432     *
433     * <p>The formatType parameter determines how the characteristic value
434     * is to be interpreted. For example, settting formatType to
435     * {@link #FORMAT_UINT16} specifies that the first two bytes of the
436     * characteristic value at the given offset are interpreted to generate the
437     * return value.
438     *
439     * @param formatType The format type used to interpret the characteristic
440     *                   value.
441     * @param offset Offset at which the integer value can be found.
442     * @return Cached value of the characteristic or null of offset exceeds
443     *         value size.
444     */
445    public Integer getIntValue(int formatType, int offset) {
446        if ((offset + getTypeLen(formatType)) > mValue.length) return null;
447
448        switch (formatType) {
449            case FORMAT_UINT8:
450                return unsignedByteToInt(mValue[offset]);
451
452            case FORMAT_UINT16:
453                return unsignedBytesToInt(mValue[offset], mValue[offset+1]);
454
455            case FORMAT_UINT32:
456                return unsignedBytesToInt(mValue[offset],   mValue[offset+1],
457                                          mValue[offset+2], mValue[offset+3]);
458            case FORMAT_SINT8:
459                return unsignedToSigned(unsignedByteToInt(mValue[offset]), 8);
460
461            case FORMAT_SINT16:
462                return unsignedToSigned(unsignedBytesToInt(mValue[offset],
463                                                           mValue[offset+1]), 16);
464
465            case FORMAT_SINT32:
466                return unsignedToSigned(unsignedBytesToInt(mValue[offset],
467                        mValue[offset+1], mValue[offset+2], mValue[offset+3]), 32);
468        }
469
470        return null;
471    }
472
473    /**
474     * Return the stored value of this characteristic.
475     * <p>See {@link #getValue} for details.
476     *
477     * @param formatType The format type used to interpret the characteristic
478     *                   value.
479     * @param offset Offset at which the float value can be found.
480     * @return Cached value of the characteristic at a given offset or null
481     *         if the requested offset exceeds the value size.
482     */
483    public Float getFloatValue(int formatType, int offset) {
484        if ((offset + getTypeLen(formatType)) > mValue.length) return null;
485
486        switch (formatType) {
487            case FORMAT_SFLOAT:
488                return bytesToFloat(mValue[offset], mValue[offset+1]);
489
490            case FORMAT_FLOAT:
491                return bytesToFloat(mValue[offset],   mValue[offset+1],
492                                    mValue[offset+2], mValue[offset+3]);
493        }
494
495        return null;
496    }
497
498    /**
499     * Return the stored value of this characteristic.
500     * <p>See {@link #getValue} for details.
501     *
502     * @param offset Offset at which the string value can be found.
503     * @return Cached value of the characteristic
504     */
505    public String getStringValue(int offset) {
506        if (offset > mValue.length) return null;
507        byte[] strBytes = new byte[mValue.length - offset];
508        for (int i=0; i != (mValue.length-offset); ++i) strBytes[i] = mValue[offset+i];
509        return new String(strBytes);
510    }
511
512    /**
513     * Updates the locally stored value of this characteristic.
514     *
515     * <p>This function modifies the locally stored cached value of this
516     * characteristic. To send the value to the remote device, call
517     * {@link BluetoothGatt#writeCharacteristic} to send the value to the
518     * remote device.
519     *
520     * @param value New value for this characteristic
521     * @return true if the locally stored value has been set, false if the
522     *              requested value could not be stored locally.
523     */
524    public boolean setValue(byte[] value) {
525        mValue = value;
526        return true;
527    }
528
529    /**
530     * Set the locally stored value of this characteristic.
531     * <p>See {@link #setValue(byte[])} for details.
532     *
533     * @param value New value for this characteristic
534     * @param formatType Integer format type used to transform the value parameter
535     * @param offset Offset at which the value should be placed
536     * @return true if the locally stored value has been set
537     */
538    public boolean setValue(int value, int formatType, int offset) {
539        int len = offset + getTypeLen(formatType);
540        if (mValue == null) mValue = new byte[len];
541        if (len > mValue.length) return false;
542
543        switch (formatType) {
544            case FORMAT_SINT8:
545                value = intToSignedBits(value, 8);
546                // Fall-through intended
547            case FORMAT_UINT8:
548                mValue[offset] = (byte)(value & 0xFF);
549                break;
550
551            case FORMAT_SINT16:
552                value = intToSignedBits(value, 16);
553                // Fall-through intended
554            case FORMAT_UINT16:
555                mValue[offset++] = (byte)(value & 0xFF);
556                mValue[offset] = (byte)((value >> 8) & 0xFF);
557                break;
558
559            case FORMAT_SINT32:
560                value = intToSignedBits(value, 32);
561                // Fall-through intended
562            case FORMAT_UINT32:
563                mValue[offset++] = (byte)(value & 0xFF);
564                mValue[offset++] = (byte)((value >> 8) & 0xFF);
565                mValue[offset++] = (byte)((value >> 16) & 0xFF);
566                mValue[offset] = (byte)((value >> 24) & 0xFF);
567                break;
568
569            default:
570                return false;
571        }
572        return true;
573    }
574
575    /**
576     * Set the locally stored value of this characteristic.
577     * <p>See {@link #setValue(byte[])} for details.
578     *
579     * @param mantissa Mantissa for this characteristic
580     * @param exponent  exponent value for this characteristic
581     * @param formatType Float format type used to transform the value parameter
582     * @param offset Offset at which the value should be placed
583     * @return true if the locally stored value has been set
584     */
585    public boolean setValue(int mantissa, int exponent, int formatType, int offset) {
586        int len = offset + getTypeLen(formatType);
587        if (mValue == null) mValue = new byte[len];
588        if (len > mValue.length) return false;
589
590        switch (formatType) {
591            case FORMAT_SFLOAT:
592                mantissa = intToSignedBits(mantissa, 12);
593                exponent = intToSignedBits(exponent, 4);
594                mValue[offset++] = (byte)(mantissa & 0xFF);
595                mValue[offset] = (byte)((mantissa >> 8) & 0x0F);
596                mValue[offset] += (byte)((exponent & 0x0F) << 4);
597                break;
598
599            case FORMAT_FLOAT:
600                mantissa = intToSignedBits(mantissa, 24);
601                exponent = intToSignedBits(exponent, 8);
602                mValue[offset++] = (byte)(mantissa & 0xFF);
603                mValue[offset++] = (byte)((mantissa >> 8) & 0xFF);
604                mValue[offset++] = (byte)((mantissa >> 16) & 0xFF);
605                mValue[offset] += (byte)(exponent & 0xFF);
606                break;
607
608            default:
609                return false;
610        }
611
612        return true;
613    }
614
615    /**
616     * Set the locally stored value of this characteristic.
617     * <p>See {@link #setValue(byte[])} for details.
618     *
619     * @param value New value for this characteristic
620     * @return true if the locally stored value has been set
621     */
622    public boolean setValue(String value) {
623        mValue = value.getBytes();
624        return true;
625    }
626
627    /**
628     * Returns the size of a give value type.
629     */
630    private int getTypeLen(int formatType) {
631        return formatType & 0xF;
632    }
633
634    /**
635     * Convert a signed byte to an unsigned int.
636     */
637    private int unsignedByteToInt(byte b) {
638        return b & 0xFF;
639    }
640
641    /**
642     * Convert signed bytes to a 16-bit unsigned int.
643     */
644    private int unsignedBytesToInt(byte b0, byte b1) {
645        return (unsignedByteToInt(b0) + (unsignedByteToInt(b1) << 8));
646    }
647
648    /**
649     * Convert signed bytes to a 32-bit unsigned int.
650     */
651    private int unsignedBytesToInt(byte b0, byte b1, byte b2, byte b3) {
652        return (unsignedByteToInt(b0) + (unsignedByteToInt(b1) << 8))
653             + (unsignedByteToInt(b2) << 16) + (unsignedByteToInt(b3) << 24);
654    }
655
656    /**
657     * Convert signed bytes to a 16-bit short float value.
658     */
659    private float bytesToFloat(byte b0, byte b1) {
660        int mantissa = unsignedToSigned(unsignedByteToInt(b0)
661                        + ((unsignedByteToInt(b1) & 0x0F) << 8), 12);
662        int exponent = unsignedToSigned(unsignedByteToInt(b1) >> 4, 4);
663        return (float)(mantissa * Math.pow(10, exponent));
664    }
665
666    /**
667     * Convert signed bytes to a 32-bit short float value.
668     */
669    private float bytesToFloat(byte b0, byte b1, byte b2, byte b3) {
670        int mantissa = unsignedToSigned(unsignedByteToInt(b0)
671                        + (unsignedByteToInt(b1) << 8)
672                        + (unsignedByteToInt(b2) << 16), 24);
673        return (float)(mantissa * Math.pow(10, b3));
674    }
675
676    /**
677     * Convert an unsigned integer value to a two's-complement encoded
678     * signed value.
679     */
680    private int unsignedToSigned(int unsigned, int size) {
681        if ((unsigned & (1 << size-1)) != 0) {
682            unsigned = -1 * ((1 << size-1) - (unsigned & ((1 << size-1) - 1)));
683        }
684        return unsigned;
685    }
686
687    /**
688     * Convert an integer into the signed bits of a given length.
689     */
690    private int intToSignedBits(int i, int size) {
691        if (i < 0) {
692            i = (1 << size-1) + (i & ((1 << size-1) - 1));
693        }
694        return i;
695    }
696}
697