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     * Returns the service this characteristic belongs to.
287     * @return The asscociated service
288     */
289    public BluetoothGattService getService() {
290        return mService;
291    }
292
293    /**
294     * Sets the service associated with this device.
295     * @hide
296     */
297    /*package*/ void setService(BluetoothGattService service) {
298        mService = service;
299    }
300
301    /**
302     * Returns the UUID of this characteristic
303     *
304     * @return UUID of this characteristic
305     */
306    public UUID getUuid() {
307        return mUuid;
308    }
309
310    /**
311     * Returns the instance ID for this characteristic.
312     *
313     * <p>If a remote device offers multiple characteristics with the same UUID,
314     * the instance ID is used to distuinguish between characteristics.
315     *
316     * @return Instance ID of this characteristic
317     */
318    public int getInstanceId() {
319        return mInstance;
320    }
321
322    /**
323     * Returns the properties of this characteristic.
324     *
325     * <p>The properties contain a bit mask of property flags indicating
326     * the features of this characteristic.
327     *
328     * @return Properties of this characteristic
329     */
330    public int getProperties() {
331        return mProperties;
332    }
333
334    /**
335     * Returns the permissions for this characteristic.
336     *
337     * @return Permissions of this characteristic
338     */
339    public int getPermissions() {
340        return mPermissions;
341    }
342
343    /**
344     * Gets the write type for this characteristic.
345     *
346     * @return Write type for this characteristic
347     */
348    public int getWriteType() {
349        return mWriteType;
350    }
351
352    /**
353     * Set the write type for this characteristic
354     *
355     * <p>Setting the write type of a characteristic determines how the
356     * {@link BluetoothGatt#writeCharacteristic} function write this
357     * characteristic.
358     *
359     * @param writeType The write type to for this characteristic. Can be one
360     *                  of:
361     *                  {@link #WRITE_TYPE_DEFAULT},
362     *                  {@link #WRITE_TYPE_NO_RESPONSE} or
363     *                  {@link #WRITE_TYPE_SIGNED}.
364     */
365    public void setWriteType(int writeType) {
366        mWriteType = writeType;
367    }
368
369    /**
370     * Set the desired key size.
371     * @hide
372     */
373    public void setKeySize(int keySize) {
374        mKeySize = keySize;
375    }
376
377    /**
378     * Returns a list of descriptors for this characteristic.
379     *
380     * @return Descriptors for this characteristic
381     */
382    public List<BluetoothGattDescriptor> getDescriptors() {
383        return mDescriptors;
384    }
385
386    /**
387     * Returns a descriptor with a given UUID out of the list of
388     * descriptors for this characteristic.
389     *
390     * @return GATT descriptor object or null if no descriptor with the
391     *         given UUID was found.
392     */
393    public BluetoothGattDescriptor getDescriptor(UUID uuid) {
394        for(BluetoothGattDescriptor descriptor : mDescriptors) {
395            if (descriptor.getUuid().equals(uuid)) {
396                return descriptor;
397            }
398        }
399        return null;
400    }
401
402    /**
403     * Get the stored value for this characteristic.
404     *
405     * <p>This function returns the stored value for this characteristic as
406     * retrieved by calling {@link BluetoothGatt#readCharacteristic}. The cached
407     * value of the characteristic is updated as a result of a read characteristic
408     * operation or if a characteristic update notification has been received.
409     *
410     * @return Cached value of the characteristic
411     */
412    public byte[] getValue() {
413        return mValue;
414    }
415
416    /**
417     * Return the stored value of this characteristic.
418     *
419     * <p>The formatType parameter determines how the characteristic value
420     * is to be interpreted. For example, settting formatType to
421     * {@link #FORMAT_UINT16} specifies that the first two bytes of the
422     * characteristic value at the given offset are interpreted to generate the
423     * return value.
424     *
425     * @param formatType The format type used to interpret the characteristic
426     *                   value.
427     * @param offset Offset at which the integer value can be found.
428     * @return Cached value of the characteristic or null of offset exceeds
429     *         value size.
430     */
431    public Integer getIntValue(int formatType, int offset) {
432        if ((offset + getTypeLen(formatType)) > mValue.length) return null;
433
434        switch (formatType) {
435            case FORMAT_UINT8:
436                return unsignedByteToInt(mValue[offset]);
437
438            case FORMAT_UINT16:
439                return unsignedBytesToInt(mValue[offset], mValue[offset+1]);
440
441            case FORMAT_UINT32:
442                return unsignedBytesToInt(mValue[offset],   mValue[offset+1],
443                                          mValue[offset+2], mValue[offset+3]);
444            case FORMAT_SINT8:
445                return unsignedToSigned(unsignedByteToInt(mValue[offset]), 8);
446
447            case FORMAT_SINT16:
448                return unsignedToSigned(unsignedBytesToInt(mValue[offset],
449                                                           mValue[offset+1]), 16);
450
451            case FORMAT_SINT32:
452                return unsignedToSigned(unsignedBytesToInt(mValue[offset],
453                        mValue[offset+1], mValue[offset+2], mValue[offset+3]), 32);
454        }
455
456        return null;
457    }
458
459    /**
460     * Return the stored value of this characteristic.
461     * <p>See {@link #getValue} for details.
462     *
463     * @param formatType The format type used to interpret the characteristic
464     *                   value.
465     * @param offset Offset at which the float value can be found.
466     * @return Cached value of the characteristic at a given offset or null
467     *         if the requested offset exceeds the value size.
468     */
469    public Float getFloatValue(int formatType, int offset) {
470        if ((offset + getTypeLen(formatType)) > mValue.length) return null;
471
472        switch (formatType) {
473            case FORMAT_SFLOAT:
474                return bytesToFloat(mValue[offset], mValue[offset+1]);
475
476            case FORMAT_FLOAT:
477                return bytesToFloat(mValue[offset],   mValue[offset+1],
478                                    mValue[offset+2], mValue[offset+3]);
479        }
480
481        return null;
482    }
483
484    /**
485     * Return the stored value of this characteristic.
486     * <p>See {@link #getValue} for details.
487     *
488     * @param offset Offset at which the string value can be found.
489     * @return Cached value of the characteristic
490     */
491    public String getStringValue(int offset) {
492        if (offset > mValue.length) return null;
493        byte[] strBytes = new byte[mValue.length - offset];
494        for (int i=0; i != (mValue.length-offset); ++i) strBytes[i] = mValue[offset+i];
495        return new String(strBytes);
496    }
497
498    /**
499     * Updates the locally stored value of this characteristic.
500     *
501     * <p>This function modifies the locally stored cached value of this
502     * characteristic. To send the value to the remote device, call
503     * {@link BluetoothGatt#writeCharacteristic} to send the value to the
504     * remote device.
505     *
506     * @param value New value for this characteristic
507     * @return true if the locally stored value has been set, false if the
508     *              requested value could not be stored locally.
509     */
510    public boolean setValue(byte[] value) {
511        mValue = value;
512        return true;
513    }
514
515    /**
516     * Set the locally stored value of this characteristic.
517     * <p>See {@link #setValue(byte[])} for details.
518     *
519     * @param value New value for this characteristic
520     * @param formatType Integer format type used to transform the value parameter
521     * @param offset Offset at which the value should be placed
522     * @return true if the locally stored value has been set
523     */
524    public boolean setValue(int value, int formatType, int offset) {
525        int len = offset + getTypeLen(formatType);
526        if (mValue == null) mValue = new byte[len];
527        if (len > mValue.length) return false;
528
529        switch (formatType) {
530            case FORMAT_SINT8:
531                value = intToSignedBits(value, 8);
532                // Fall-through intended
533            case FORMAT_UINT8:
534                mValue[offset] = (byte)(value & 0xFF);
535                break;
536
537            case FORMAT_SINT16:
538                value = intToSignedBits(value, 16);
539                // Fall-through intended
540            case FORMAT_UINT16:
541                mValue[offset++] = (byte)(value & 0xFF);
542                mValue[offset] = (byte)((value >> 8) & 0xFF);
543                break;
544
545            case FORMAT_SINT32:
546                value = intToSignedBits(value, 32);
547                // Fall-through intended
548            case FORMAT_UINT32:
549                mValue[offset++] = (byte)(value & 0xFF);
550                mValue[offset++] = (byte)((value >> 8) & 0xFF);
551                mValue[offset++] = (byte)((value >> 16) & 0xFF);
552                mValue[offset] = (byte)((value >> 24) & 0xFF);
553                break;
554
555            default:
556                return false;
557        }
558        return true;
559    }
560
561    /**
562     * Set the locally stored value of this characteristic.
563     * <p>See {@link #setValue(byte[])} for details.
564     *
565     * @param mantissa Mantissa for this characteristic
566     * @param exponent  exponent value for this characteristic
567     * @param formatType Float format type used to transform the value parameter
568     * @param offset Offset at which the value should be placed
569     * @return true if the locally stored value has been set
570     */
571    public boolean setValue(int mantissa, int exponent, int formatType, int offset) {
572        int len = offset + getTypeLen(formatType);
573        if (mValue == null) mValue = new byte[len];
574        if (len > mValue.length) return false;
575
576        switch (formatType) {
577            case FORMAT_SFLOAT:
578                mantissa = intToSignedBits(mantissa, 12);
579                exponent = intToSignedBits(exponent, 4);
580                mValue[offset++] = (byte)(mantissa & 0xFF);
581                mValue[offset] = (byte)((mantissa >> 8) & 0x0F);
582                mValue[offset] += (byte)((exponent & 0x0F) << 4);
583                break;
584
585            case FORMAT_FLOAT:
586                mantissa = intToSignedBits(mantissa, 24);
587                exponent = intToSignedBits(exponent, 8);
588                mValue[offset++] = (byte)(mantissa & 0xFF);
589                mValue[offset++] = (byte)((mantissa >> 8) & 0xFF);
590                mValue[offset++] = (byte)((mantissa >> 16) & 0xFF);
591                mValue[offset] += (byte)(exponent & 0xFF);
592                break;
593
594            default:
595                return false;
596        }
597
598        return true;
599    }
600
601    /**
602     * Set the locally stored value of this characteristic.
603     * <p>See {@link #setValue(byte[])} for details.
604     *
605     * @param value New value for this characteristic
606     * @return true if the locally stored value has been set
607     */
608    public boolean setValue(String value) {
609        mValue = value.getBytes();
610        return true;
611    }
612
613    /**
614     * Returns the size of a give value type.
615     */
616    private int getTypeLen(int formatType) {
617        return formatType & 0xF;
618    }
619
620    /**
621     * Convert a signed byte to an unsigned int.
622     */
623    private int unsignedByteToInt(byte b) {
624        return b & 0xFF;
625    }
626
627    /**
628     * Convert signed bytes to a 16-bit unsigned int.
629     */
630    private int unsignedBytesToInt(byte b0, byte b1) {
631        return (unsignedByteToInt(b0) + (unsignedByteToInt(b1) << 8));
632    }
633
634    /**
635     * Convert signed bytes to a 32-bit unsigned int.
636     */
637    private int unsignedBytesToInt(byte b0, byte b1, byte b2, byte b3) {
638        return (unsignedByteToInt(b0) + (unsignedByteToInt(b1) << 8))
639             + (unsignedByteToInt(b2) << 16) + (unsignedByteToInt(b3) << 24);
640    }
641
642    /**
643     * Convert signed bytes to a 16-bit short float value.
644     */
645    private float bytesToFloat(byte b0, byte b1) {
646        int mantissa = unsignedToSigned(unsignedByteToInt(b0)
647                        + ((unsignedByteToInt(b1) & 0x0F) << 8), 12);
648        int exponent = unsignedToSigned(unsignedByteToInt(b1) >> 4, 4);
649        return (float)(mantissa * Math.pow(10, exponent));
650    }
651
652    /**
653     * Convert signed bytes to a 32-bit short float value.
654     */
655    private float bytesToFloat(byte b0, byte b1, byte b2, byte b3) {
656        int mantissa = unsignedToSigned(unsignedByteToInt(b0)
657                        + (unsignedByteToInt(b1) << 8)
658                        + (unsignedByteToInt(b2) << 16), 24);
659        return (float)(mantissa * Math.pow(10, b3));
660    }
661
662    /**
663     * Convert an unsigned integer value to a two's-complement encoded
664     * signed value.
665     */
666    private int unsignedToSigned(int unsigned, int size) {
667        if ((unsigned & (1 << size-1)) != 0) {
668            unsigned = -1 * ((1 << size-1) - (unsigned & ((1 << size-1) - 1)));
669        }
670        return unsigned;
671    }
672
673    /**
674     * Convert an integer into the signed bits of a given length.
675     */
676    private int intToSignedBits(int i, int size) {
677        if (i < 0) {
678            i = (1 << size-1) + (i & ((1 << size-1) - 1));
679        }
680        return i;
681    }
682}
683