[Bluetooth][Non-ACR] Define Interop callback to global variable (#2005)
[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             Characteristic.SetParent(service);
375             return Characteristic;
376         }
377
378         internal IEnumerable<BluetoothGattCharacteristic> GetCharacteristics(BluetoothGattService service)
379         {
380             List<BluetoothGattCharacteristic> attribututeList = new List<BluetoothGattCharacteristic>();
381             _characteristicForeachCallback = (total, index, attributeHandle, userData) =>
382             {
383                 BluetoothGattAttributeHandle handle = new BluetoothGattAttributeHandle(attributeHandle, false);
384                 BluetoothGattCharacteristic Characteristic = BluetoothGattCharacteristicImpl.CreateBluetoothGattGattCharacteristic(handle, "");
385                 if (Characteristic != null)
386                 {
387                     Characteristic.SetParent(service);
388                     attribututeList.Add(Characteristic);
389                 }
390                 return true;
391             };
392
393             int err = Interop.Bluetooth.BtGattServiceForeachCharacteristics(service.GetHandle(), _characteristicForeachCallback, IntPtr.Zero);
394             GattUtil.Error(err, "Failed to get all Characteristic");
395
396             return attribututeList;
397         }
398
399         internal void AddIncludeService(BluetoothGattService includedService)
400         {
401             int err = Interop.Bluetooth.BtGattServiceAddIncludedService(_handle, includedService.GetHandle());
402             GattUtil.ThrowForError(err, string.Format("Failed to add service with UUID ({0})", includedService.Uuid));
403         }
404
405         internal BluetoothGattService GetIncludeService(BluetoothGattService parentService, string uuid)
406         {
407             BluetoothGattAttributeHandle attributeHandle;
408             int err = Interop.Bluetooth.BtGattServiceGetIncludedService(_handle, uuid, out attributeHandle);
409             if (err.IsFailed())
410             {
411                 GattUtil.Error(err, string.Format("Failed to get included service with UUID ({0})", uuid));
412                 return null;
413             }
414
415             BluetoothGattService service = new BluetoothGattService(new BluetoothGattServiceImpl(attributeHandle), uuid);
416             service.SetParent(parentService);
417             return service;
418         }
419
420         internal IEnumerable<BluetoothGattService> GetIncludeServices(BluetoothGattService parentService)
421         {
422             List<BluetoothGattService> attribututeList = new List<BluetoothGattService>();
423             _includedServiceForeachCallback = (total, index, attributeHandle, userData) =>
424             {
425                 BluetoothGattAttributeHandle handle = new BluetoothGattAttributeHandle(attributeHandle, false);
426                 BluetoothGattService service = BluetoothGattServiceImpl.CreateBluetoothGattService(handle, "");
427                 if (service != null)
428                 {
429                     service.SetParent(parentService);
430                     attribututeList.Add(service);
431                 }
432                 return true;
433             };
434
435             int err = Interop.Bluetooth.BtGattServiceForeachIncludedServices(parentService.GetHandle(), _includedServiceForeachCallback, IntPtr.Zero);
436             GattUtil.Error(err, "Failed to get all services");
437
438             return attribututeList;
439         }
440     }
441
442     internal class BluetoothGattCharacteristicImpl : BluetoothGattAttributeImpl
443     {
444         private Interop.Bluetooth.BtGattForeachCallback _descriptorForeachCallback;
445
446         internal BluetoothGattCharacteristicImpl(string uuid, BluetoothGattPermission permission, BluetoothGattProperty property, byte[] value)
447         {
448             int err = Interop.Bluetooth.BtGattCharacteristicCreate(uuid, (int)permission, (int)property, value, value.Length, out _handle);
449             GattUtil.ThrowForError(err, "Failed to get native characteristic handle");
450         }
451
452         internal BluetoothGattCharacteristicImpl(BluetoothGattAttributeHandle handle)
453         {
454             _handle = handle;
455         }
456
457         internal static BluetoothGattCharacteristic CreateBluetoothGattGattCharacteristic(BluetoothGattAttributeHandle handle, string uuid)
458         {
459             int permission;
460             int err = Interop.Bluetooth.BtGattCharacteristicGetPermissions(handle, out permission);
461             GattUtil.ThrowForError(err, "Failed to get permissions");
462
463             if (uuid == "")
464             {
465                 err = Interop.Bluetooth.BtGattGetUuid(handle, out uuid);
466                 GattUtil.ThrowForError(err, "Failed to get UUID");
467             }
468
469             BluetoothGattCharacteristicImpl impl = new BluetoothGattCharacteristicImpl(handle);
470             return new BluetoothGattCharacteristic(impl, uuid, (BluetoothGattPermission)permission);
471         }
472
473         internal void SetCharacteristicValueChangedEvent(Interop.Bluetooth.BtClientCharacteristicValueChangedCallback callback)
474         {
475             int err = Interop.Bluetooth.BtGattClientSetCharacteristicValueChangedCallback(_handle, callback, IntPtr.Zero);
476             GattUtil.Error(err, "Failed to set client characteristic value changed callback");
477         }
478
479         internal void UnsetCharacteristicValueChangedEvent()
480         {
481             int err = Interop.Bluetooth.BtGattClientUnsetCharacteristicValueChangedCallback(_handle);
482             GattUtil.Error(err, "Failed to unset client characteristic value changed callback");
483         }
484
485         internal void SetNotificationStateChangedEvent(Interop.Bluetooth.BtGattServerNotificationStateChangeCallback callback)
486         {
487             int err = Interop.Bluetooth.BtGattServeSetNotificationStateChangeCallback(_handle, callback, IntPtr.Zero);
488             GattUtil.Error(err, "Failed to set characteristic notification state changed callback");
489         }
490
491         internal BluetoothGattProperty GetProperties()
492         {
493             int properties = 0 ;
494             int err = Interop.Bluetooth.BtGattCharacteristicGetProperties(_handle, out properties);
495             GattUtil.Error(err, "Failed to get characteristic properties");
496             return (BluetoothGattProperty)properties;
497         }
498
499         internal void SetProperties(BluetoothGattProperty perperties)
500         {
501             int err = Interop.Bluetooth.BtGattCharacteristicSetProperties(_handle, (int)perperties);
502             GattUtil.Error(err, "Failed to set characteristic properties");
503         }
504
505         internal BluetoothGattWriteType GetWriteType()
506         {
507             int writeType;
508             int err = Interop.Bluetooth.BtGattCharacteristicGetWriteType(_handle, out writeType);
509             GattUtil.Error(err, "Failed to get characteristic writetype");
510             return (BluetoothGattWriteType) writeType;
511         }
512
513         internal void SetWriteType(BluetoothGattWriteType writeType)
514         {
515             int err = Interop.Bluetooth.BtGattCharacteristicSetWriteType(_handle, (int)writeType);
516             GattUtil.Error(err, "Failed to get characteristic writetype");
517         }
518
519         internal void AddDescriptor(BluetoothGattDescriptor descriptor)
520         {
521             int err = Interop.Bluetooth.BtGattCharacteristicAddDescriptor(_handle, descriptor.GetHandle());
522             GattUtil.ThrowForError(err, string.Format("Failed to add descriptor with UUID ({0})", descriptor.Uuid));
523         }
524
525         internal BluetoothGattDescriptor GetDescriptor(BluetoothGattCharacteristic characteristic, string uuid)
526         {
527             BluetoothGattAttributeHandle handle;
528             int err = Interop.Bluetooth.BtGattCharacteristicGetDescriptor(_handle, uuid, out handle);
529             if (err.IsFailed())
530             {
531                 GattUtil.Error(err, string.Format("Failed to get descriptor with UUID ({0})", uuid));
532                 return null;
533             }
534             BluetoothGattDescriptor descriptor = BluetoothGattDescriptorImpl.CreateBluetoothGattDescriptor(handle, uuid);
535             descriptor.SetParent(characteristic);
536             return descriptor;
537         }
538
539         internal IEnumerable<BluetoothGattDescriptor> GetDescriptors(BluetoothGattCharacteristic characteristic)
540         {
541             List<BluetoothGattDescriptor> attribututeList = new List<BluetoothGattDescriptor>();
542             _descriptorForeachCallback = (total, index, attributeHandle, userData) =>
543             {
544                 BluetoothGattAttributeHandle handle = new BluetoothGattAttributeHandle(attributeHandle, false);
545                 BluetoothGattDescriptor descriptor = BluetoothGattDescriptorImpl.CreateBluetoothGattDescriptor(handle, "");
546                 if (descriptor != null)
547                 {
548                     descriptor.SetParent(characteristic);
549                     attribututeList.Add(descriptor);
550                 }
551                 return true;
552             };
553
554             int err = Interop.Bluetooth.BtGattCharacteristicForeachDescriptors(characteristic.GetHandle(), _descriptorForeachCallback, IntPtr.Zero);
555             GattUtil.Error(err, "Failed to get all descriptor");
556
557             return attribututeList;
558         }
559     }
560
561     internal class BluetoothGattDescriptorImpl : BluetoothGattAttributeImpl
562     {
563         internal BluetoothGattDescriptorImpl(string uuid, BluetoothGattPermission permission, byte[] value)
564         {
565             int err = Interop.Bluetooth.BtGattDescriptorCreate(uuid, (int)permission, value, value.Length, out _handle);
566             GattUtil.ThrowForError(err, "Failed to get native descriptor handle");
567         }
568
569         internal BluetoothGattDescriptorImpl(BluetoothGattAttributeHandle handle)
570         {
571             _handle = handle;
572         }
573
574         internal static BluetoothGattDescriptor CreateBluetoothGattDescriptor(BluetoothGattAttributeHandle handle, string uuid)
575         {
576             int permission;
577             int err = Interop.Bluetooth.BtGattDescriptorGetPermissions(handle, out permission);
578             GattUtil.ThrowForError(err, string.Format("Failed to get permissions with UUID ({0})", uuid));
579
580             if (uuid == "")
581             {
582                 int ret = Interop.Bluetooth.BtGattGetUuid(handle, out uuid);
583                 GattUtil.ThrowForError(ret, "Failed to get UUID");
584             }
585
586             BluetoothGattDescriptorImpl impl = new BluetoothGattDescriptorImpl(handle);
587             return new BluetoothGattDescriptor(impl, uuid, (BluetoothGattPermission)permission);
588         }
589     }
590
591     internal abstract class BluetoothGattAttributeImpl
592     {
593         protected BluetoothGattAttributeHandle _handle;
594
595         internal string GetUuid()
596         {
597             string uuid;
598             int err = Interop.Bluetooth.BtGattGetUuid(_handle, out uuid);
599             GattUtil.Error(err, "Failed to get attribute uuid");
600
601             return uuid;
602         }
603
604         internal byte[] GetValue()
605         {
606             IntPtr nativeValue;
607             int nativeValueLength;
608             int err = Interop.Bluetooth.BtGattGetValue(_handle, out nativeValue, out nativeValueLength);
609             GattUtil.Error(err, "Failed to get attribute value");
610
611             return GattUtil.IntPtrToByteArray(nativeValue, nativeValueLength);
612         }
613
614         internal void SetValue(byte[] value)
615         {
616             int err = Interop.Bluetooth.BtGattSetValue(_handle, value, value.Length);
617             GattUtil.ThrowForError(err, "Failed to set attribute value");
618         }
619
620         internal string GetValue(int offset)
621         {
622             byte[] value = GetValue();
623
624             int nullPos = value.Length - offset;
625             for (int i = offset; i < value.Length; ++i)
626             {
627                 if (value[i] == '\0')
628                 {
629                     nullPos = i;
630                     break;
631                 }
632             }
633
634             string strValue = "";
635             strValue = Encoding.UTF8.GetString(value, offset, nullPos - offset);
636             return strValue;
637         }
638
639         internal int GetValue(IntDataType type, int offset)
640         {
641             int value;
642             int err = Interop.Bluetooth.BtGattGetIntValue(_handle, (int)type, offset, out value);
643             GattUtil.Error(err, "Failed to get attribute int value at offset");
644             return value;
645         }
646
647         internal void SetValue(IntDataType type, int value, int offset)
648         {
649             int err = Interop.Bluetooth.BtGattSetIntValue(_handle, (int)type, value, offset);
650             GattUtil.ThrowForError(err, "Failed to set attribute int value at offset");
651         }
652
653         internal float GetValue(FloatDataType type, int offset)
654         {
655             float value;
656             int err = Interop.Bluetooth.BtGattGetFloatValue(_handle, (int)type, offset, out value);
657             GattUtil.Error(err, "Failed to get attribute float value at offset");
658             return value;
659         }
660
661         internal void SetValue(FloatDataType type, int mantissa, int exponent, int offset)
662         {
663             int err = Interop.Bluetooth.BtGattSetFloatValue(_handle, (int)type, mantissa, exponent, offset);
664             GattUtil.ThrowForError(err, "Failed to set attribute float value at offset");
665         }
666
667         internal void SetReadValueRequestedEventCallback(Interop.Bluetooth.BtGattServerReadValueRequestedCallback callback)
668         {
669             int err = Interop.Bluetooth.BtGattServerSetReadValueRequestedCallback(_handle, callback, IntPtr.Zero);
670             GattUtil.ThrowForError(err, "Failed to set attribute read value requested callback");
671         }
672
673         internal void SetWriteValueRequestedEventCallback(Interop.Bluetooth.BtGattServerWriteValueRequestedCallback callback)
674         {
675             int err = Interop.Bluetooth.BtGattServerSetWriteValueRequestedCallback(_handle, callback, IntPtr.Zero);
676             GattUtil.ThrowForError(err, "Failed to set attribute write value requested callback");
677         }
678
679         internal BluetoothGattAttributeHandle GetHandle()
680         {
681             return _handle;
682         }
683
684         internal void ReleaseHandleOwnership()
685         {
686             _handle.ReleaseOwnership();
687         }
688     }
689
690
691     internal class BluetoothGattAttributeHandle : BluetoothGattHandle
692     {
693         public BluetoothGattAttributeHandle(IntPtr nativeHandle, bool hasOwnership) : base(nativeHandle, hasOwnership)
694         {
695         }
696
697         public BluetoothGattAttributeHandle()
698         {
699         }
700
701         protected override bool ReleaseHandle()
702         {
703             if (_hasOwnership == true)
704             {
705                 Interop.Bluetooth.BtGattDestroy(handle);
706             }
707             SetHandle(IntPtr.Zero);
708             return true;
709         }
710     }
711
712     internal class BluetoothGattClientHandle : BluetoothGattHandle
713     {
714         protected override bool ReleaseHandle()
715         {
716             if (_hasOwnership == true)
717             {
718                 Interop.Bluetooth.BtGattClientDestroy(handle);
719             }
720             SetHandle(IntPtr.Zero);
721             return true;
722         }
723     }
724
725     internal class BluetoothGattServerHandle : BluetoothGattHandle
726     {
727         protected override bool ReleaseHandle()
728         {
729             if (_hasOwnership == true)
730             {
731                 int err;
732
733                 err = Interop.Bluetooth.BtGattServerDestroy(handle);
734                 if (err.IsFailed())
735                 {
736                     Log.Error(Globals.LogTag, "Failed to destroy the server instance");
737                     return false;
738                 }
739
740                 err = Interop.Bluetooth.BtGattServerDeinitialize();
741                 if (err.IsFailed())
742                 {
743                     Log.Error(Globals.LogTag, "Failed to deinitialize");
744                     SetHandle(IntPtr.Zero);
745                     return false;
746                 }
747             }
748             SetHandle(IntPtr.Zero);
749             return true;
750         }
751     }
752
753     internal abstract class BluetoothGattHandle : SafeHandle
754     {
755         protected bool _hasOwnership;
756
757         public BluetoothGattHandle() : base(IntPtr.Zero, true)
758         {
759             _hasOwnership = true;
760         }
761
762         public BluetoothGattHandle(IntPtr nativeHandle, bool hasOwnership) : base(nativeHandle, true)
763         {
764             _hasOwnership = hasOwnership;
765         }
766
767         public override bool IsInvalid
768         {
769             get { return handle == IntPtr.Zero; }
770         }
771
772         public void ReleaseOwnership()
773         {
774             _hasOwnership = false;
775         }
776     }
777
778     internal static class GattUtil
779     {
780         internal static byte[] IntPtrToByteArray(IntPtr nativeValue, int lenght)
781         {
782             byte[] value = new byte[lenght];
783             if (nativeValue != IntPtr.Zero)
784             {
785                 Marshal.Copy(nativeValue, value, 0, lenght);
786             }
787             return value;
788         }
789
790         internal static void Error(int err, string message, [CallerFilePath] string file = "", [CallerMemberName] string func = "", [CallerLineNumber] int line = 0)
791         {
792             if (err.IsFailed())
793             {
794                 Log.Error(Globals.LogTag, string.Format("{0}, err: {1}", message, (BluetoothError)err), file, func, line);
795             }
796         }
797
798         internal static void ThrowForError(int err, string message, [CallerFilePath] string file = "", [CallerMemberName] string func = "", [CallerLineNumber] int line = 0)
799         {
800             if (err.IsFailed())
801             {
802                 Log.Error(Globals.LogTag, string.Format("{0}, err: {1}", message, (BluetoothError)err), file, func, line);
803                 BluetoothErrorFactory.ThrowBluetoothException(err);
804             }
805         }
806
807         internal static bool IsFailed(this int err)
808         {
809             return err != (int)BluetoothError.None;
810         }
811     }
812 }