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