Release 8.0.0.15764
[platform/core/csapi/tizenfx.git] / src / Tizen.Network.Bluetooth / Tizen.Network.Bluetooth / BluetoothGattImpl.cs
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
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  */
16
17 using System;
18 using System.Collections.Generic;
19 using System.Runtime.CompilerServices;
20 using System.Runtime.InteropServices;
21 using System.Text;
22 using System.Threading.Tasks;
23
24 namespace Tizen.Network.Bluetooth
25 {
26     internal class BluetoothGattServerImpl
27     {
28         private BluetoothGattServerHandle _handle;
29         internal event EventHandler<NotificationSentEventArg> _notificationSent;
30         int _requestId = 0;
31         Dictionary<int, TaskCompletionSource<bool>> _sendIndicationTaskSource = new Dictionary<int, TaskCompletionSource<bool>>();
32         private Interop.Bluetooth.BtGattServerNotificationSentCallback _sendIndicationCallback;
33         private Interop.Bluetooth.BtGattForeachCallback _serviceForeachCallback;
34
35         internal BluetoothGattServerImpl()
36         {
37             _sendIndicationCallback = SendIndicationCallback;
38
39             int err = Interop.Bluetooth.BtGattServerInitialize();
40             GattUtil.ThrowForError(err, "Failed to initialize server");
41
42             err = Interop.Bluetooth.BtGattServerCreate(out _handle);
43             GattUtil.ThrowForError(err, "Failed to create server");
44         }
45
46         internal void Start()
47         {
48             int err = Interop.Bluetooth.BtGattServerStart();
49             GattUtil.ThrowForError(err, "Failed to start server");
50         }
51
52         internal void RegisterGattService(BluetoothGattServer server, BluetoothGattService service)
53         {
54             int err = Interop.Bluetooth.BtGattServerRegisterService(_handle, service.GetHandle());
55             GattUtil.ThrowForError(err, "Failed to Register service");
56
57             service.SetParent(server);
58         }
59
60         internal void UnregisterGattService(BluetoothGattService service)
61         {
62             int err = Interop.Bluetooth.BtGattServerUnregisterService(_handle, service.GetHandle());
63             GattUtil.ThrowForError(err, "Failed to Unregister service");
64
65             service.UnregisterService();
66         }
67
68         internal void UnregisterAllGattServices(BluetoothGattServer server)
69         {
70             int err = Interop.Bluetooth.BtGattServerUnregisterAllServices(_handle);
71             GattUtil.ThrowForError(err, "Failed to Unregister all services");
72         }
73
74         internal BluetoothGattService GetService(BluetoothGattServer server, string uuid)
75         {
76             BluetoothGattAttributeHandle serviceHandle;
77             int err = Interop.Bluetooth.BtGattServerGetService(_handle, uuid, out serviceHandle);
78             if (err.IsFailed())
79             {
80                 GattUtil.Error(err, string.Format("Failed to get service with UUID ({0})", uuid));
81                 return null;
82             }
83
84             BluetoothGattService service = new BluetoothGattService(new BluetoothGattServiceImpl(serviceHandle), uuid); ;
85             service.SetParent(server);
86             return service;
87         }
88
89         internal IEnumerable<BluetoothGattService> GetServices(BluetoothGattServer server)
90         {
91             List<BluetoothGattService> attribututeList = new List<BluetoothGattService>();
92             _serviceForeachCallback = (total, index, attributeHandle, userData) =>
93             {
94                 BluetoothGattAttributeHandle handle = new BluetoothGattAttributeHandle(attributeHandle, false);
95                 BluetoothGattService service = BluetoothGattServiceImpl.CreateBluetoothGattService(handle, ""); ;
96                 if (service != null)
97                 {
98                     service.SetParent(server);
99                     attribututeList.Add(service);
100                 }
101                 return true;
102             };
103
104             int err = Interop.Bluetooth.BtGattServerForeachServices(_handle, _serviceForeachCallback, IntPtr.Zero);
105             GattUtil.Error(err, "Failed to get all services");
106
107             return attribututeList;
108         }
109
110         internal void SendResponse(int requestId, int request_type, int status, byte[] value, int offset)
111         {
112             int err = Interop.Bluetooth.BtGattServerSendResponse(requestId, request_type, offset, status, value, value.Length);
113             GattUtil.ThrowForError(err, string.Format("Failed to send response for request Id {0}", requestId));
114         }
115
116         void SendIndicationCallback(int result, string clientAddress, IntPtr serverHandle, IntPtr characteristicHandle, bool completed, IntPtr userData)
117         {
118             int requestId = (int)userData;
119             if (_sendIndicationTaskSource.ContainsKey(requestId))
120             {
121                 _notificationSent?.Invoke(this, new NotificationSentEventArg(null, clientAddress, result, completed));
122                 if (completed)
123                 {
124                     _sendIndicationTaskSource[requestId].SetResult(true);
125                 }
126                 else
127                 {
128                     _sendIndicationTaskSource[requestId].SetResult(false);
129                 }
130                 _sendIndicationTaskSource.Remove(requestId);
131             }
132         }
133
134         internal Task<bool> SendIndicationAsync(BluetoothGattServer server, BluetoothGattCharacteristic characteristic, string clientAddress)
135         {
136             TaskCompletionSource<bool> task = new TaskCompletionSource<bool>();
137             int requestId = 0;
138
139             lock (this)
140             {
141                 requestId = _requestId++;
142                 _sendIndicationTaskSource[requestId] = task;
143             }
144
145             int err = Interop.Bluetooth.BtGattServerNotify(characteristic.GetHandle(), _sendIndicationCallback, clientAddress, (IntPtr)requestId);
146             if (err.IsFailed())
147             {
148                 GattUtil.Error(err, string.Format("Failed to send value changed indication for characteristic uuid {0}", characteristic.Uuid));
149                 task.SetResult(false);
150                 _sendIndicationTaskSource.Remove(requestId);
151                 BluetoothErrorFactory.ThrowBluetoothException(err);
152             }
153             return task.Task;
154         }
155
156         internal BluetoothGattServerHandle GetHandle()
157         {
158             return _handle;
159         }
160     }
161
162     internal class BluetoothGattClientImpl
163     {
164         private BluetoothGattClientHandle _handle;
165         int _requestId = 0;
166         Dictionary<int, TaskCompletionSource<bool>> _readValueTaskSource = new Dictionary<int, TaskCompletionSource<bool>>();
167         private Interop.Bluetooth.BtGattClientRequestCompletedCallback _readValueCallback;
168         Dictionary<int, TaskCompletionSource<bool>> _writeValueTaskSource = new Dictionary<int, TaskCompletionSource<bool>>();
169         private Interop.Bluetooth.BtGattClientRequestCompletedCallback _writeValueCallback;
170         private Interop.Bluetooth.BtGattForeachCallback _serviceForeachCallback;
171
172         internal BluetoothGattClientImpl(string remoteAddress)
173         {
174             _readValueCallback = ReadValueCallback;
175             _writeValueCallback = WriteValueCallback;
176
177             if (BluetoothAdapter.IsBluetoothEnabled)
178             {
179                 int err = Interop.Bluetooth.BtGattClientCreate(remoteAddress, out _handle);
180                 GattUtil.ThrowForError(err, "Failed to get native client handle");
181             }
182             else
183             {
184                 BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NotEnabled);
185             }
186         }
187
188         internal void Connect(string remoteAddress, bool autoConnect)
189         {
190             int err = Interop.Bluetooth.GattConnect(remoteAddress, autoConnect);
191             GattUtil.ThrowForError(err, "Failed to connect to remote address");
192         }
193
194         internal void Disconnect(string remoteAddress)
195         {
196             int err = Interop.Bluetooth.GattDisconnect(remoteAddress);
197             GattUtil.ThrowForError(err, "Failed to disconnect to remote address");
198         }
199
200         internal string GetRemoteAddress()
201         {
202             string remoteAddress;
203             int err = Interop.Bluetooth.BtGattClientGetRemoteAddress(_handle, out remoteAddress);
204             GattUtil.ThrowForError(err, "Failed to get remote address for this client");
205
206             return remoteAddress;
207         }
208
209         internal BluetoothGattService GetService(BluetoothGattClient client, string uuid)
210         {
211             BluetoothGattAttributeHandle serviceHandle;
212             int err = Interop.Bluetooth.BtGattClientGetService(_handle, uuid, out serviceHandle);
213             if (err.IsFailed())
214             {
215                 GattUtil.Error(err, string.Format("Failed to get service with UUID ({0})", uuid));
216                 return null;
217             }
218
219             BluetoothGattService service = new BluetoothGattService(new BluetoothGattServiceImpl(serviceHandle), uuid); ;
220             service.SetParent(client);
221             return service;
222         }
223
224         internal IEnumerable<BluetoothGattService> GetServices(BluetoothGattClient client)
225         {
226             List<BluetoothGattService> attribututeList = new List<BluetoothGattService>();
227             _serviceForeachCallback = (total, index, attributeHandle, userData) =>
228             {
229                 BluetoothGattAttributeHandle handle = new BluetoothGattAttributeHandle(attributeHandle, false);
230                 BluetoothGattService service = BluetoothGattServiceImpl.CreateBluetoothGattService(handle, "");
231                 if (service != null)
232                 {
233                     service.SetParent(client);
234                     attribututeList.Add(service);
235                 }
236                 return true;
237             };
238
239             int err = Interop.Bluetooth.BtGattClientForeachServices(_handle, _serviceForeachCallback, IntPtr.Zero);
240             GattUtil.Error(err, "Failed to get all services");
241
242             return attribututeList;
243         }
244
245         void ReadValueCallback(int result, IntPtr requestHandle, IntPtr userData)
246         {
247             int requestId = (int)userData;
248             if (_readValueTaskSource.ContainsKey(requestId))
249             {
250                 if (result == (int)BluetoothError.None)
251                 {
252                     _readValueTaskSource[requestId].SetResult(true);
253                 }
254                 else
255                 {
256                     _readValueTaskSource[requestId].SetResult(false);
257                 }
258             }
259             _readValueTaskSource.Remove(requestId);
260         }
261
262         internal Task<bool> ReadValueAsyncTask(BluetoothGattAttributeHandle handle)
263         {
264             TaskCompletionSource<bool> task = new TaskCompletionSource<bool>();
265             int requestId = 0;
266
267             lock (this)
268             {
269                 requestId = _requestId++;
270                 _readValueTaskSource[requestId] = task;
271             }
272
273             int err = Interop.Bluetooth.BtGattClientReadValue(handle, _readValueCallback, (IntPtr)requestId);
274             if (err.IsFailed())
275             {
276                 GattUtil.Error(err, "Failed to read value from remote device");
277                 task.SetResult(false);
278                 _readValueTaskSource.Remove(requestId);
279                 BluetoothErrorFactory.ThrowBluetoothException(err);
280             }
281             return task.Task;
282         }
283
284         void WriteValueCallback(int result, IntPtr requestHandle, IntPtr userData)
285         {
286             int requestId = (int)userData;
287             if (_writeValueTaskSource.ContainsKey(requestId))
288             {
289                 if (result == (int)BluetoothError.None)
290                 {
291                     _writeValueTaskSource[requestId].SetResult(true);
292                 }
293                 else
294                 {
295                     _writeValueTaskSource[requestId].SetResult(false);
296                 }
297             }
298             _writeValueTaskSource.Remove(requestId);
299         }
300
301         internal Task<bool> WriteValueAsyncTask(BluetoothGattAttributeHandle handle)
302         {
303             TaskCompletionSource<bool> task = new TaskCompletionSource<bool>();
304             int requestId = 0;
305
306             lock (this)
307             {
308                 requestId = _requestId++;
309                 _writeValueTaskSource[requestId] = task;
310             }
311
312             int err = Interop.Bluetooth.BtGattClientWriteValue(handle, _writeValueCallback, (IntPtr)requestId);
313             if (err.IsFailed())
314             {
315                 GattUtil.Error(err, "Failed to write value to remote device");
316                 task.SetResult(false);
317                 _writeValueTaskSource.Remove(requestId);
318                 BluetoothErrorFactory.ThrowBluetoothException(err);
319             }
320             return task.Task;
321         }
322
323         internal BluetoothGattClientHandle GetHandle()
324         {
325             return _handle;
326         }
327     }
328
329     internal class BluetoothGattServiceImpl : BluetoothGattAttributeImpl
330     {
331         private Interop.Bluetooth.BtGattForeachCallback _characteristicForeachCallback;
332         private Interop.Bluetooth.BtGattForeachCallback _includedServiceForeachCallback;
333
334         internal BluetoothGattServiceImpl(string uuid, BluetoothGattServiceType type)
335         {
336             int err = Interop.Bluetooth.BtGattServiceCreate(uuid, (int)type, out _handle);
337             GattUtil.ThrowForError(err, "Failed to get native service handle");
338         }
339
340         internal BluetoothGattServiceImpl(BluetoothGattAttributeHandle handle)
341         {
342             _handle = handle;
343         }
344
345         internal static BluetoothGattService CreateBluetoothGattService(BluetoothGattAttributeHandle handle, string uuid)
346         {
347             if (uuid == "")
348             {
349                 int err = Interop.Bluetooth.BtGattGetUuid(handle, out uuid);
350                 GattUtil.ThrowForError(err, "Failed to get UUID");
351             }
352
353             BluetoothGattServiceImpl impl = new BluetoothGattServiceImpl(handle);
354             return new BluetoothGattService(impl, uuid);
355         }
356
357         internal void AddCharacteristic(BluetoothGattCharacteristic characteristic)
358         {
359             int err = Interop.Bluetooth.BtGattServiceAddCharacteristic(_handle, characteristic.GetHandle());
360             GattUtil.ThrowForError(err, string.Format("Failed to add characteristic with UUID ({0})", characteristic.Uuid));
361         }
362
363         internal BluetoothGattCharacteristic GetCharacteristic(BluetoothGattService service, string uuid)
364         {
365             BluetoothGattAttributeHandle attributeHandle;
366             int err = Interop.Bluetooth.BtGattServiceGetCharacteristic(_handle, uuid, out attributeHandle);
367             if (err.IsFailed())
368             {
369                 GattUtil.Error(err, string.Format("Failed to get Characteristic with UUID ({0})", uuid));
370                 return null;
371             }
372
373             BluetoothGattCharacteristic Characteristic = BluetoothGattCharacteristicImpl.CreateBluetoothGattGattCharacteristic(attributeHandle, uuid);
374             if (Characteristic != null)
375             {
376                 Characteristic.SetParent(service);
377             }
378             return Characteristic;
379         }
380
381         internal IEnumerable<BluetoothGattCharacteristic> GetCharacteristics(BluetoothGattService service)
382         {
383             List<BluetoothGattCharacteristic> attribututeList = new List<BluetoothGattCharacteristic>();
384             _characteristicForeachCallback = (total, index, attributeHandle, userData) =>
385             {
386                 BluetoothGattAttributeHandle handle = new BluetoothGattAttributeHandle(attributeHandle, false);
387                 BluetoothGattCharacteristic Characteristic = BluetoothGattCharacteristicImpl.CreateBluetoothGattGattCharacteristic(handle, "");
388                 if (Characteristic != null)
389                 {
390                     Characteristic.SetParent(service);
391                     attribututeList.Add(Characteristic);
392                 }
393                 return true;
394             };
395
396             int err = Interop.Bluetooth.BtGattServiceForeachCharacteristics(service.GetHandle(), _characteristicForeachCallback, IntPtr.Zero);
397             GattUtil.Error(err, "Failed to get all Characteristic");
398
399             return attribututeList;
400         }
401
402         internal void AddIncludeService(BluetoothGattService includedService)
403         {
404             int err = Interop.Bluetooth.BtGattServiceAddIncludedService(_handle, includedService.GetHandle());
405             GattUtil.ThrowForError(err, string.Format("Failed to add service with UUID ({0})", includedService.Uuid));
406         }
407
408         internal BluetoothGattService GetIncludeService(BluetoothGattService parentService, string uuid)
409         {
410             BluetoothGattAttributeHandle attributeHandle;
411             int err = Interop.Bluetooth.BtGattServiceGetIncludedService(_handle, uuid, out attributeHandle);
412             if (err.IsFailed())
413             {
414                 GattUtil.Error(err, string.Format("Failed to get included service with UUID ({0})", uuid));
415                 return null;
416             }
417
418             BluetoothGattService service = new BluetoothGattService(new BluetoothGattServiceImpl(attributeHandle), uuid);
419             service.SetParent(parentService);
420             return service;
421         }
422
423         internal IEnumerable<BluetoothGattService> GetIncludeServices(BluetoothGattService parentService)
424         {
425             List<BluetoothGattService> attribututeList = new List<BluetoothGattService>();
426             _includedServiceForeachCallback = (total, index, attributeHandle, userData) =>
427             {
428                 BluetoothGattAttributeHandle handle = new BluetoothGattAttributeHandle(attributeHandle, false);
429                 BluetoothGattService service = BluetoothGattServiceImpl.CreateBluetoothGattService(handle, "");
430                 if (service != null)
431                 {
432                     service.SetParent(parentService);
433                     attribututeList.Add(service);
434                 }
435                 return true;
436             };
437
438             int err = Interop.Bluetooth.BtGattServiceForeachIncludedServices(parentService.GetHandle(), _includedServiceForeachCallback, IntPtr.Zero);
439             GattUtil.Error(err, "Failed to get all services");
440
441             return attribututeList;
442         }
443     }
444
445     internal class BluetoothGattCharacteristicImpl : BluetoothGattAttributeImpl
446     {
447         private Interop.Bluetooth.BtGattForeachCallback _descriptorForeachCallback;
448
449         internal BluetoothGattCharacteristicImpl(string uuid, BluetoothGattPermission permission, BluetoothGattProperty property, byte[] value)
450         {
451             int err = Interop.Bluetooth.BtGattCharacteristicCreate(uuid, (int)permission, (int)property, value, value.Length, out _handle);
452             GattUtil.ThrowForError(err, "Failed to get native characteristic handle");
453         }
454
455         internal BluetoothGattCharacteristicImpl(BluetoothGattAttributeHandle handle)
456         {
457             _handle = handle;
458         }
459
460         internal static BluetoothGattCharacteristic CreateBluetoothGattGattCharacteristic(BluetoothGattAttributeHandle handle, string uuid)
461         {
462             int permission;
463             int err = Interop.Bluetooth.BtGattCharacteristicGetPermissions(handle, out permission);
464             GattUtil.ThrowForError(err, "Failed to get permissions");
465
466             if (uuid == "")
467             {
468                 err = Interop.Bluetooth.BtGattGetUuid(handle, out uuid);
469                 GattUtil.ThrowForError(err, "Failed to get UUID");
470             }
471
472             BluetoothGattCharacteristicImpl impl = new BluetoothGattCharacteristicImpl(handle);
473             return new BluetoothGattCharacteristic(impl, uuid, (BluetoothGattPermission)permission);
474         }
475
476         internal void SetCharacteristicValueChangedEvent(Interop.Bluetooth.BtClientCharacteristicValueChangedCallback callback)
477         {
478             int err = Interop.Bluetooth.BtGattClientSetCharacteristicValueChangedCallback(_handle, callback, IntPtr.Zero);
479             GattUtil.Error(err, "Failed to set client characteristic value changed callback");
480         }
481
482         internal void UnsetCharacteristicValueChangedEvent()
483         {
484             int err = Interop.Bluetooth.BtGattClientUnsetCharacteristicValueChangedCallback(_handle);
485             GattUtil.Error(err, "Failed to unset client characteristic value changed callback");
486         }
487
488         internal void SetNotificationStateChangedEvent(Interop.Bluetooth.BtGattServerNotificationStateChangeCallback callback)
489         {
490             int err = Interop.Bluetooth.BtGattServeSetNotificationStateChangeCallback(_handle, callback, IntPtr.Zero);
491             GattUtil.Error(err, "Failed to set characteristic notification state changed callback");
492         }
493
494         internal BluetoothGattProperty GetProperties()
495         {
496             int properties = 0 ;
497             int err = Interop.Bluetooth.BtGattCharacteristicGetProperties(_handle, out properties);
498             GattUtil.Error(err, "Failed to get characteristic properties");
499             return (BluetoothGattProperty)properties;
500         }
501
502         internal void SetProperties(BluetoothGattProperty perperties)
503         {
504             int err = Interop.Bluetooth.BtGattCharacteristicSetProperties(_handle, (int)perperties);
505             GattUtil.Error(err, "Failed to set characteristic properties");
506         }
507
508         internal BluetoothGattWriteType GetWriteType()
509         {
510             int writeType;
511             int err = Interop.Bluetooth.BtGattCharacteristicGetWriteType(_handle, out writeType);
512             GattUtil.Error(err, "Failed to get characteristic writetype");
513             return (BluetoothGattWriteType) writeType;
514         }
515
516         internal void SetWriteType(BluetoothGattWriteType writeType)
517         {
518             int err = Interop.Bluetooth.BtGattCharacteristicSetWriteType(_handle, (int)writeType);
519             GattUtil.Error(err, "Failed to get characteristic writetype");
520         }
521
522         internal void AddDescriptor(BluetoothGattDescriptor descriptor)
523         {
524             int err = Interop.Bluetooth.BtGattCharacteristicAddDescriptor(_handle, descriptor.GetHandle());
525             GattUtil.ThrowForError(err, string.Format("Failed to add descriptor with UUID ({0})", descriptor.Uuid));
526         }
527
528         internal BluetoothGattDescriptor GetDescriptor(BluetoothGattCharacteristic characteristic, string uuid)
529         {
530             BluetoothGattAttributeHandle handle;
531             int err = Interop.Bluetooth.BtGattCharacteristicGetDescriptor(_handle, uuid, out handle);
532             if (err.IsFailed())
533             {
534                 GattUtil.Error(err, string.Format("Failed to get descriptor with UUID ({0})", uuid));
535                 return null;
536             }
537             BluetoothGattDescriptor descriptor = BluetoothGattDescriptorImpl.CreateBluetoothGattDescriptor(handle, uuid);
538             if (descriptor != null)
539             {
540                 descriptor.SetParent(characteristic);
541             }
542             return descriptor;
543         }
544
545         internal IEnumerable<BluetoothGattDescriptor> GetDescriptors(BluetoothGattCharacteristic characteristic)
546         {
547             List<BluetoothGattDescriptor> attribututeList = new List<BluetoothGattDescriptor>();
548             _descriptorForeachCallback = (total, index, attributeHandle, userData) =>
549             {
550                 BluetoothGattAttributeHandle handle = new BluetoothGattAttributeHandle(attributeHandle, false);
551                 BluetoothGattDescriptor descriptor = BluetoothGattDescriptorImpl.CreateBluetoothGattDescriptor(handle, "");
552                 if (descriptor != null)
553                 {
554                     descriptor.SetParent(characteristic);
555                     attribututeList.Add(descriptor);
556                 }
557                 return true;
558             };
559
560             int err = Interop.Bluetooth.BtGattCharacteristicForeachDescriptors(characteristic.GetHandle(), _descriptorForeachCallback, IntPtr.Zero);
561             GattUtil.Error(err, "Failed to get all descriptor");
562
563             return attribututeList;
564         }
565     }
566
567     internal class BluetoothGattDescriptorImpl : BluetoothGattAttributeImpl
568     {
569         internal BluetoothGattDescriptorImpl(string uuid, BluetoothGattPermission permission, byte[] value)
570         {
571             int err = Interop.Bluetooth.BtGattDescriptorCreate(uuid, (int)permission, value, value.Length, out _handle);
572             GattUtil.ThrowForError(err, "Failed to get native descriptor handle");
573         }
574
575         internal BluetoothGattDescriptorImpl(BluetoothGattAttributeHandle handle)
576         {
577             _handle = handle;
578         }
579
580         internal static BluetoothGattDescriptor CreateBluetoothGattDescriptor(BluetoothGattAttributeHandle handle, string uuid)
581         {
582             int permission;
583             int err = Interop.Bluetooth.BtGattDescriptorGetPermissions(handle, out permission);
584             GattUtil.ThrowForError(err, string.Format("Failed to get permissions with UUID ({0})", uuid));
585
586             if (uuid == "")
587             {
588                 int ret = Interop.Bluetooth.BtGattGetUuid(handle, out uuid);
589                 GattUtil.ThrowForError(ret, "Failed to get UUID");
590             }
591
592             BluetoothGattDescriptorImpl impl = new BluetoothGattDescriptorImpl(handle);
593             return new BluetoothGattDescriptor(impl, uuid, (BluetoothGattPermission)permission);
594         }
595     }
596
597     internal abstract class BluetoothGattAttributeImpl
598     {
599         protected BluetoothGattAttributeHandle _handle;
600
601         internal string GetUuid()
602         {
603             string uuid;
604             int err = Interop.Bluetooth.BtGattGetUuid(_handle, out uuid);
605             GattUtil.Error(err, "Failed to get attribute uuid");
606
607             return uuid;
608         }
609
610         internal byte[] GetValue()
611         {
612             IntPtr nativeValue;
613             int nativeValueLength;
614             int err = Interop.Bluetooth.BtGattGetValue(_handle, out nativeValue, out nativeValueLength);
615             GattUtil.Error(err, "Failed to get attribute value");
616
617             return GattUtil.IntPtrToByteArray(nativeValue, nativeValueLength);
618         }
619
620         internal void SetValue(byte[] value)
621         {
622             int err = Interop.Bluetooth.BtGattSetValue(_handle, value, value.Length);
623             GattUtil.ThrowForError(err, "Failed to set attribute value");
624         }
625
626         internal string GetValue(int offset)
627         {
628             byte[] value = GetValue();
629
630             int nullPos = value.Length - offset;
631             for (int i = offset; i < value.Length; ++i)
632             {
633                 if (value[i] == '\0')
634                 {
635                     nullPos = i;
636                     break;
637                 }
638             }
639
640             string strValue = "";
641             strValue = Encoding.UTF8.GetString(value, offset, nullPos - offset);
642             return strValue;
643         }
644
645         internal int GetValue(IntDataType type, int offset)
646         {
647             int value;
648             int err = Interop.Bluetooth.BtGattGetIntValue(_handle, (int)type, offset, out value);
649             GattUtil.Error(err, "Failed to get attribute int value at offset");
650             return value;
651         }
652
653         internal void SetValue(IntDataType type, int value, int offset)
654         {
655             int err = Interop.Bluetooth.BtGattSetIntValue(_handle, (int)type, value, offset);
656             GattUtil.ThrowForError(err, "Failed to set attribute int value at offset");
657         }
658
659         internal float GetValue(FloatDataType type, int offset)
660         {
661             float value;
662             int err = Interop.Bluetooth.BtGattGetFloatValue(_handle, (int)type, offset, out value);
663             GattUtil.Error(err, "Failed to get attribute float value at offset");
664             return value;
665         }
666
667         internal void SetValue(FloatDataType type, int mantissa, int exponent, int offset)
668         {
669             int err = Interop.Bluetooth.BtGattSetFloatValue(_handle, (int)type, mantissa, exponent, offset);
670             GattUtil.ThrowForError(err, "Failed to set attribute float value at offset");
671         }
672
673         internal void SetReadValueRequestedEventCallback(Interop.Bluetooth.BtGattServerReadValueRequestedCallback callback)
674         {
675             int err = Interop.Bluetooth.BtGattServerSetReadValueRequestedCallback(_handle, callback, IntPtr.Zero);
676             GattUtil.ThrowForError(err, "Failed to set attribute read value requested callback");
677         }
678
679         internal void SetWriteValueRequestedEventCallback(Interop.Bluetooth.BtGattServerWriteValueRequestedCallback callback)
680         {
681             int err = Interop.Bluetooth.BtGattServerSetWriteValueRequestedCallback(_handle, callback, IntPtr.Zero);
682             GattUtil.ThrowForError(err, "Failed to set attribute write value requested callback");
683         }
684
685         internal BluetoothGattAttributeHandle GetHandle()
686         {
687             return _handle;
688         }
689
690         internal void ReleaseHandleOwnership()
691         {
692             _handle.ReleaseOwnership();
693         }
694     }
695
696
697     internal class BluetoothGattAttributeHandle : BluetoothGattHandle
698     {
699         public BluetoothGattAttributeHandle(IntPtr nativeHandle, bool hasOwnership) : base(nativeHandle, hasOwnership)
700         {
701         }
702
703         public BluetoothGattAttributeHandle()
704         {
705         }
706
707         protected override bool ReleaseHandle()
708         {
709             if (_hasOwnership == true)
710             {
711                 Interop.Bluetooth.BtGattDestroy(handle);
712             }
713             SetHandle(IntPtr.Zero);
714             return true;
715         }
716     }
717
718     internal class BluetoothGattClientHandle : BluetoothGattHandle
719     {
720         protected override bool ReleaseHandle()
721         {
722             if (_hasOwnership == true)
723             {
724                 Interop.Bluetooth.BtGattClientDestroy(handle);
725             }
726             SetHandle(IntPtr.Zero);
727             return true;
728         }
729     }
730
731     internal class BluetoothGattServerHandle : BluetoothGattHandle
732     {
733         protected override bool ReleaseHandle()
734         {
735             if (_hasOwnership == true)
736             {
737                 int err;
738
739                 err = Interop.Bluetooth.BtGattServerDestroy(handle);
740                 if (err.IsFailed())
741                 {
742                     Log.Error(Globals.LogTag, "Failed to destroy the server instance");
743                     return false;
744                 }
745
746                 err = Interop.Bluetooth.BtGattServerDeinitialize();
747                 if (err.IsFailed())
748                 {
749                     Log.Error(Globals.LogTag, "Failed to deinitialize");
750                     SetHandle(IntPtr.Zero);
751                     return false;
752                 }
753             }
754             SetHandle(IntPtr.Zero);
755             return true;
756         }
757     }
758
759     internal abstract class BluetoothGattHandle : SafeHandle
760     {
761         protected bool _hasOwnership;
762
763         public BluetoothGattHandle() : base(IntPtr.Zero, true)
764         {
765             _hasOwnership = true;
766         }
767
768         public BluetoothGattHandle(IntPtr nativeHandle, bool hasOwnership) : base(nativeHandle, true)
769         {
770             _hasOwnership = hasOwnership;
771         }
772
773         public override bool IsInvalid
774         {
775             get { return handle == IntPtr.Zero; }
776         }
777
778         public void ReleaseOwnership()
779         {
780             _hasOwnership = false;
781         }
782     }
783
784     internal static class GattUtil
785     {
786         internal static byte[] IntPtrToByteArray(IntPtr nativeValue, int lenght)
787         {
788             byte[] value = new byte[lenght];
789             if (nativeValue != IntPtr.Zero)
790             {
791                 Marshal.Copy(nativeValue, value, 0, lenght);
792             }
793             return value;
794         }
795
796         internal static void Error(int err, string message, [CallerFilePath] string file = "", [CallerMemberName] string func = "", [CallerLineNumber] int line = 0)
797         {
798             if (err.IsFailed())
799             {
800                 Log.Error(Globals.LogTag, string.Format("{0}, err: {1}", message, (BluetoothError)err), file, func, line);
801             }
802         }
803
804         internal static void ThrowForError(int err, string message, [CallerFilePath] string file = "", [CallerMemberName] string func = "", [CallerLineNumber] int line = 0)
805         {
806             if (err.IsFailed())
807             {
808                 Log.Error(Globals.LogTag, string.Format("{0}, err: {1}", message, (BluetoothError)err), file, func, line);
809                 BluetoothErrorFactory.ThrowBluetoothException(err);
810             }
811         }
812
813         internal static bool IsFailed(this int err)
814         {
815             return err != (int)BluetoothError.None;
816         }
817     }
818 }