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