a1c31340faad11d82f3bbab5cfcc819b3915f3e4
[platform/core/csapi/tizenfx.git] / src / Tizen.Network.Bluetooth / Tizen.Network.Bluetooth / BluetoothGatt.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.InteropServices;
20 using System.Text;
21 using System.Threading.Tasks;
22
23 namespace Tizen.Network.Bluetooth
24 {
25     /// <summary>
26     /// The Bluetooth GATT server.
27     /// </summary>
28     /// <since_tizen> 3 </since_tizen>
29     public class BluetoothGattServer : IDisposable
30     {
31         private static BluetoothGattServer _instance;
32         private BluetoothGattServerImpl _impl;
33
34         private BluetoothGattServer()
35         {
36             _impl = new BluetoothGattServerImpl();
37         }
38
39         /// <summary>
40         /// (event) This event is called when the indication acknowledgement is received for each notified client.
41         /// </summary>
42         /// <since_tizen> 3 </since_tizen>
43         public event EventHandler<NotificationSentEventArg> NotificationSent
44         {
45             add
46             {
47                 _impl._notificationSent += value;
48             }
49             remove
50             {
51                 _impl._notificationSent -= value;
52             }
53         }
54
55         /// <summary>
56         /// Creates the Bluetooth GATT server.
57         /// </summary>
58         /// <returns>The BluetoothGattServer instance.</returns>
59         /// <feature>http://tizen.org/feature/network.bluetooth.le.gatt.server</feature>
60         /// <exception cref="NotSupportedException">Thrown when the BT/BTLE is not supported.</exception>
61         /// <exception cref="InvalidOperationException">Thrown when the create GATT server fails.</exception>
62         /// <since_tizen> 3 </since_tizen>
63         public static BluetoothGattServer CreateServer()
64         {
65             if (_instance == null)
66             {
67                 BluetoothGattServer server = new BluetoothGattServer();
68                 if (server.IsValid())
69                 {
70                     _instance = server;
71                 }
72             }
73             return _instance;
74         }
75
76         /// <summary>
77         /// Registers the server along with the GATT services of the application it is hosting.
78         /// </summary>
79         /// <feature>http://tizen.org/feature/network.bluetooth.le.gatt.server</feature>
80         /// <exception cref="NotSupportedException">Thrown when the BT/BTLE is not supported.</exception>
81         /// <exception cref="InvalidOperationException">Thrown when the register server application fails.</exception>
82         /// <since_tizen> 3 </since_tizen>
83         public void Start()
84         {
85             _impl.Start();
86         }
87
88         /// <summary>
89         /// Registers a specified service to this server.
90         /// </summary>
91         /// <param name="service">The service, which needs to be registered with this server.</param>
92         /// <feature>http://tizen.org/feature/network.bluetooth.le.gatt.server</feature>
93         /// <exception cref="NotSupportedException">Thrown when the BT/BTLE is not supported.</exception>
94         /// <exception cref="InvalidOperationException">Thrown when the register service fails.</exception>
95         /// <since_tizen> 3 </since_tizen>
96         public void RegisterGattService(BluetoothGattService service)
97         {
98             if (service.IsRegistered())
99             {
100                 BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.InvalidParameter);
101             }
102             _impl.RegisterGattService(this, service);
103         }
104
105         /// <summary>
106         /// Unregisters a specified service from this server.
107         /// </summary>
108         /// <param name="service">The service, which needs to be unregistered from this server.</param>
109         /// <remarks>
110         /// Once unregistered, the service object will become invalid and should not be used to access sevices or any children attribute's methods/members.
111         /// </remarks>
112         /// <feature>http://tizen.org/feature/network.bluetooth.le.gatt.server</feature>
113         /// <exception cref="NotSupportedException">Thrown when the BT/BTLE is not supported.</exception>
114         /// <exception cref="InvalidOperationException">Thrown when the unregister service fails.</exception>
115         /// <since_tizen> 3 </since_tizen>
116         public void UnregisterGattService(BluetoothGattService service)
117         {
118             if (service.GetGattServer() != this)
119             {
120                 BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.InvalidParameter);
121             }
122
123             _impl.UnregisterGattService(service);
124         }
125
126         /// <summary>
127         /// Unregisters all services from this server.
128         /// </summary>
129         /// <remarks>
130         /// Once unregistered, servicees will become invalid and should not be used to access sevices or any children attribute's methods/members.
131         /// </remarks>
132         /// <feature>http://tizen.org/feature/network.bluetooth.le.gatt.server</feature>
133         /// <exception cref="NotSupportedException">Thrown when the BT/BTLE is not supported.</exception>
134         /// <exception cref="InvalidOperationException">Thrown when the unregister all services fail.</exception>
135         /// <since_tizen> 3 </since_tizen>
136         public void UnregisterGattServices()
137         {
138             _impl.UnregisterAllGattServices(this);
139         }
140
141         /// <summary>
142         /// Gets service with given UUID that belongs to this server.
143         /// </summary>
144         /// <param name="uuid">The UUID for the service to get.</param>
145         /// <returns>The Service with the given UUID if it exists, null otherwise.</returns>
146         /// <feature>http://tizen.org/feature/network.bluetooth.le.gatt.server</feature>
147         /// <exception cref="NotSupportedException">Thrown when the BT/BTLE is not supported.</exception>
148         /// <exception cref="InvalidOperationException">Thrown when the service is not registered.</exception>
149         /// <since_tizen> 3 </since_tizen>
150         public BluetoothGattService GetService(string uuid)
151         {
152             return _impl.GetService(this, uuid);
153         }
154
155         /// <summary>
156         /// Gets the list of services that belongs to this server.
157         /// </summary>
158         /// <returns>The list of services that belongs to this server.</returns>
159         /// <feature>http://tizen.org/feature/network.bluetooth.le.gatt.server</feature>
160         /// <exception cref="NotSupportedException">Thrown when the BT/BTLE is not supported.</exception>
161         /// <exception cref="InvalidOperationException">Thrown when the service is not registered.</exception>
162         /// <since_tizen> 3 </since_tizen>
163         public IEnumerable<BluetoothGattService> GetServices()
164         {
165             return _impl.GetServices(this);
166         }
167
168         /// <summary>
169         /// Sends indication for the value change of the characteristic to the remote devices.
170         /// </summary>
171         /// <param name="characteristic">The characteristic whose the value is changed.</param>
172         /// <param name="clientAddress">The remote device address to send, notify, or indicate and if set to NULL, then notify/indicate all is enabled.</param>
173         /// <returns>true on success, false otherwise.</returns>
174         /// <feature>http://tizen.org/feature/network.bluetooth.le.gatt.server</feature>
175         /// <exception cref="NotSupportedException">Thrown when the BT/BTLE is not supported.</exception>
176         /// <exception cref="InvalidOperationException">Thrown when the BT/BTLE is not enabled
177         /// or when the remote device is disconnected, or when service is not registered, or when the CCCD is not enabled.</exception>
178         /// <since_tizen> 3 </since_tizen>
179         public async Task<bool> SendIndicationAsync(BluetoothGattCharacteristic characteristic, string clientAddress)
180         {
181             return await _impl.SendIndicationAsync(this, characteristic, clientAddress);
182         }
183
184         /// <summary>
185         /// Sends the notification for the value change of the characteristic to the remote devices.
186         /// </summary>
187         /// <param name="characteristic">The characteristic, which has a changed value.</param>
188         /// <param name="clientAddress">The remote device address to send, notify, or indicate and if set to NULL, then notify/indicate all is enabled.</param>
189         /// <feature>http://tizen.org/feature/network.bluetooth.le.gatt.server</feature>
190         /// <exception cref="NotSupportedException">Thrown when the BT/BTLE is not supported.</exception>
191         /// <exception cref="InvalidOperationException">Thrown when the BT/BTLE is not enabled
192         /// or when the remote device is disconnected, or when service is not registered, or when the CCCD is not enabled.</exception>
193         /// <since_tizen> 3 </since_tizen>
194         public void SendNotification(BluetoothGattCharacteristic characteristic, string clientAddress)
195         {
196             _impl.SendNotification(characteristic, clientAddress);
197         }
198
199         /// <summary>
200         /// Sends a response to the remote device as a result of a read/write request.
201         /// </summary>
202         /// <param name="requestId">The identification of a read/write request.</param>
203         /// <param name="type">The request type for read/write.</param>
204         /// <param name="status">The error value in case of failure, 0 for success.</param>
205         /// <param name="value">The value to be sent.</param>
206         /// <param name="offset">The offset from where the value is read.</param>
207         /// <feature>http://tizen.org/feature/network.bluetooth.le.gatt.server</feature>
208         /// <exception cref="NotSupportedException">Thrown when the BT/BTLE is not supported.</exception>
209         /// <exception cref="InvalidOperationException">Thrown when the BT/BTLE is not enabled
210         /// or when the remote device is disconnected, or the send response procedure fails.</exception>
211         /// <since_tizen> 3 </since_tizen>
212         public void SendResponse(int requestId, BluetoothGattRequestType type, int status, byte[] value, int offset)
213         {
214             _impl.SendResponse(requestId, (int)type, status, value, offset);
215         }
216
217         internal bool IsValid()
218         {
219             return _impl.GetHandle().IsInvalid == false;
220         }
221
222         /// <summary>
223         /// Destroys the current object.
224         /// </summary>
225         ~BluetoothGattServer()
226         {
227             Dispose(false);
228         }
229
230         /// <summary>
231         /// Destroys the current object.
232         /// </summary>
233         /// <feature>http://tizen.org/feature/network.bluetooth.le.gatt.server</feature>
234         /// <since_tizen> 6 </since_tizen>
235         public void Dispose()
236         {
237             Dispose(true);
238             GC.SuppressFinalize(this);
239         }
240
241         /// <summary>
242         /// Releases all the resources currently used by this instance.
243         /// </summary>
244         /// <param name="disposing">true if the managed resources should be disposed, otherwise false.</param>
245         /// <since_tizen> 6 </since_tizen>
246         protected virtual void Dispose(bool disposing)
247         {
248             if (disposing)
249             {
250                 _impl?.GetHandle()?.Dispose();
251                 _instance = null;
252             }
253         }
254     }
255
256     /// <summary>
257     /// The Bluetooth GATT client.
258     /// </summary>
259     /// <since_tizen> 3 </since_tizen>
260     public class BluetoothGattClient : IDisposable
261     {
262         private BluetoothGattClientImpl _impl;
263         private string _remoteAddress = string.Empty;
264         private TaskCompletionSource<bool> _taskForConnection;
265         private TaskCompletionSource<bool> _taskForDisconnection;
266         private static event EventHandler<GattConnectionStateChangedEventArgs> s_connectionStateChanged;
267         private static Interop.Bluetooth.GattConnectionStateChangedCallBack s_connectionStateChangeCallback;
268
269         internal BluetoothGattClient(string remoteAddress)
270         {
271             _impl = new BluetoothGattClientImpl(remoteAddress);
272             _remoteAddress = remoteAddress;
273             StaticConnectionStateChanged += OnConnectionStateChanged;
274         }
275
276         /// <summary>
277         /// Creates the Bluetooth GATT client.
278         /// </summary>
279         /// <returns>The BluetoothGattClient instance.</returns>
280         /// <feature>http://tizen.org/feature/network.bluetooth.le.gatt.client</feature>
281         /// <exception cref="NotSupportedException">Thrown when the BT/BTLE is not supported.</exception>
282         /// <exception cref="InvalidOperationException">Thrown when the create GATT client fails.</exception>
283         /// <since_tizen> 6 </since_tizen>
284         public static BluetoothGattClient CreateClient(string remoteAddress)
285         {
286             BluetoothGattClient client = new BluetoothGattClient(remoteAddress);
287             return client.Isvalid() ? client : null;
288         }
289
290         /// <summary>
291         /// The ConnectionStateChanged event is raised when the gatt connection state is changed.
292         /// </summary>
293         /// <since_tizen> 6 </since_tizen>
294         public event EventHandler<GattConnectionStateChangedEventArgs> ConnectionStateChanged;
295
296         private void OnConnectionStateChanged(Object s, GattConnectionStateChangedEventArgs e)
297         {
298             if (e.RemoteAddress == _remoteAddress)
299             {
300                 if (_taskForConnection != null && !_taskForConnection.Task.IsCompleted)
301                 {
302                     if (e.Result == (int)BluetoothError.None)
303                     {
304                         _taskForConnection.SetResult(true);
305                     }
306                     else
307                     {
308                         _taskForConnection.SetException(BluetoothErrorFactory.CreateBluetoothException((int)e.Result));
309                     }
310                     _taskForConnection = null;
311                 }
312
313                 if (_taskForDisconnection != null && !_taskForDisconnection.Task.IsCompleted)
314                 {
315                     if (e.Result == (int)BluetoothError.None)
316                     {
317                         _taskForDisconnection.SetResult(true);
318                     }
319                     else
320                     {
321                         _taskForDisconnection.SetException(BluetoothErrorFactory.CreateBluetoothException(e.Result));
322                     }
323                     _taskForDisconnection = null;
324                 }
325
326                 if (e.Result == (int)BluetoothError.None)
327                 {
328                     ConnectionStateChanged?.Invoke(this, e);
329                 }
330             }
331         }
332
333         private static event EventHandler<GattConnectionStateChangedEventArgs> StaticConnectionStateChanged
334         {
335             add
336             {
337                 if (s_connectionStateChanged == null)
338                 {
339                     RegisterConnectionStateChangedEvent();
340                 }
341                 s_connectionStateChanged += value;
342             }
343             remove
344             {
345                 s_connectionStateChanged -= value;
346                 if (s_connectionStateChanged == null)
347                 {
348                     UnregisterConnectionStateChangedEvent();
349                 }
350             }
351         }
352
353         private static void RegisterConnectionStateChangedEvent()
354         {
355             s_connectionStateChangeCallback = (int result, bool connected, string remoteDeviceAddress, IntPtr userData) =>
356             {
357                 Log.Info(Globals.LogTag, "Setting gatt connection state changed callback");
358                 GattConnectionStateChangedEventArgs e = new GattConnectionStateChangedEventArgs(result, connected, remoteDeviceAddress);
359                 s_connectionStateChanged?.Invoke(null, e);
360             };
361
362             int ret = Interop.Bluetooth.SetGattConnectionStateChangedCallback(s_connectionStateChangeCallback, IntPtr.Zero);
363             if (ret != (int)BluetoothError.None)
364             {
365                 Log.Error(Globals.LogTag, "Failed to set gatt connection state changed callback, Error - " + (BluetoothError)ret);
366                 BluetoothErrorFactory.ThrowBluetoothException(ret);
367             }
368         }
369
370         private static void UnregisterConnectionStateChangedEvent()
371         {
372             int ret = Interop.Bluetooth.UnsetGattConnectionStateChangedCallback();
373             if (ret != (int)BluetoothError.None)
374             {
375                 Log.Error(Globals.LogTag, "Failed to unset gatt connection state changed callback, Error - " + (BluetoothError)ret);
376                 BluetoothErrorFactory.ThrowBluetoothException(ret);
377             }
378         }
379
380         /// <summary>
381         /// Connects to the remote GATT server asynchronously.
382         /// </summary>
383         /// <param name="autoConnect">The flag for reconnecting when the connection is disconnceted.</param>
384         /// <returns> A task indicating whether the method is done or not.</returns>
385         /// <feature>http://tizen.org/feature/network.bluetooth.le.gatt.client</feature>
386         /// <privilege>http://tizen.org/privilege/bluetooth</privilege>
387         /// <exception cref="NotSupportedException">Thrown when the BT/BTLE is not supported.</exception>
388         /// <exception cref="InvalidOperationException">Thrown when the create GATT client fails.</exception>
389         /// <since_tizen> 6 </since_tizen>
390         public Task ConnectAsync(bool autoConnect)
391         {
392             if (_taskForConnection != null && !_taskForConnection.Task.IsCompleted)
393             {
394                 BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NowInProgress);
395             }
396             _taskForConnection = new TaskCompletionSource<bool>();
397             _impl.Connect(_remoteAddress, autoConnect);
398             return _taskForConnection.Task;
399         }
400
401         /// <summary>
402         /// Disconnects to the remote GATT server asynchronously.
403         /// </summary>
404         /// <returns> A task indicating whether the method is done or not.</returns>
405         /// <feature>http://tizen.org/feature/network.bluetooth.le.gatt.client</feature>
406         /// <privilege>http://tizen.org/privilege/bluetooth</privilege>
407         /// <exception cref="NotSupportedException">Thrown when the BT/BTLE is not supported.</exception>
408         /// <exception cref="InvalidOperationException">Thrown when the create GATT client fails.</exception>
409         /// <since_tizen> 6 </since_tizen>
410         public Task DisconnectAsync()
411         {
412             if (_taskForDisconnection != null && !_taskForDisconnection.Task.IsCompleted)
413             {
414                 BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NowInProgress);
415             }
416             _taskForDisconnection = new TaskCompletionSource<bool>();
417             _impl.Disconnect(_remoteAddress);
418             return _taskForDisconnection.Task;
419         }
420
421         /// <summary>
422         /// Destroy Bluetooth GATT client
423         /// </summary>
424         /// <since_tizen> 3 </since_tizen>
425         public void DestroyClient()
426         {
427             _impl.GetHandle().Dispose();
428         }
429
430         /// <summary>
431         /// The address of the remote device.
432         /// </summary>
433         /// <exception cref="InvalidOperationException">Thrown when the BT/BTLE is not enabled
434         /// or when the remote device is disconnected.</exception>
435         /// <since_tizen> 3 </since_tizen>
436         public string RemoteAddress
437         {
438             get
439             {
440                 if (string.IsNullOrEmpty(_remoteAddress))
441                 {
442                     _remoteAddress = _impl.GetRemoteAddress();
443                 }
444                 return _remoteAddress;
445             }
446         }
447
448         /// <summary>
449         /// Gets the service with the given UUID that belongs to the remote device.
450         /// </summary>
451         /// <param name="uuid">The UUID for the service to get.</param>
452         /// <returns>The service with the given UUID if it exists, null otherwise.</returns>
453         /// <exception cref="InvalidOperationException">Thrown when the BT/BTLE is not enabled
454         /// or when the remote device is disconnected, or when the get service fails.</exception>
455         /// <since_tizen> 3 </since_tizen>
456         public BluetoothGattService GetService(string uuid)
457         {
458             return _impl.GetService(this, uuid);
459         }
460
461         /// <summary>
462         /// Gets list of services that belongs to the remote device.
463         /// </summary>
464         /// <returns>The list of services that belongs to the remote device.</returns>
465         /// <exception cref="InvalidOperationException">Thrown when the BT/BTLE is not enabled
466         /// or when the remote device is disconnected, or when the get service fails.</exception>
467         /// <since_tizen> 3 </since_tizen>
468         public IEnumerable<BluetoothGattService> GetServices()
469         {
470             return _impl.GetServices(this);
471         }
472
473         /// <summary>
474         /// Reads the value of a given characteristic from the remote device asynchronously.
475         /// </summary>
476         /// <param name="characteristic">The characteristic to be read.</param>
477         /// <returns>true on success, false otherwise.</returns>
478         /// <exception cref="InvalidOperationException">Thrown when the BT/BTLE is not enabled
479         /// or when the remote device is disconnected, or when the read attribute value fails.</exception>
480         /// <since_tizen> 3 </since_tizen>
481         public async Task<bool> ReadValueAsync(BluetoothGattCharacteristic characteristic)
482         {
483             return await _impl.ReadValueAsyncTask(characteristic.GetHandle());
484         }
485
486         /// <summary>
487         /// Reads the value of the given descriptor from the remote device asynchronously.
488         /// </summary>
489         /// <param name="descriptor">The descriptor to be read.</param>
490         /// <returns>true on success, false otherwise.</returns>
491         /// <exception cref="InvalidOperationException">Thrown when the BT/BTLE is not enabled
492         /// or when the remote device is disconnected, or when the read attribute value fails.</exception>
493         /// <since_tizen> 3 </since_tizen>
494         public async Task<bool> ReadValueAsync(BluetoothGattDescriptor descriptor)
495         {
496             return await _impl.ReadValueAsyncTask(descriptor.GetHandle());
497         }
498
499         /// <summary>
500         /// Writes the value of a given characteristic to the remote device asynchronously.
501         /// </summary>
502         /// <param name="characteristic">The characteristic to be written.</param>
503         /// <returns>true on success, false otherwise.</returns>
504         /// <exception cref="InvalidOperationException">Thrown when the BT/BTLE is not enabled
505         /// or when the remote device is disconnected or when the write attribute value fails.</exception>
506         /// <since_tizen> 3 </since_tizen>
507         public async Task<bool> WriteValueAsync(BluetoothGattCharacteristic characteristic)
508         {
509             return await _impl.WriteValueAsyncTask(characteristic.GetHandle());
510         }
511
512         /// <summary>
513         /// Writes the value of the given descriptor to the remote device asynchronously.
514         /// </summary>
515         /// <param name="descriptor">The descriptor to be written.</param>
516         /// <returns>true on success, false otherwise.</returns>
517         /// <exception cref="InvalidOperationException">Thrown when the BT/BTLE is not enabled
518         /// or when the remote device is disconnected, or when the write attribute value fails.</exception>
519         /// <since_tizen> 3 </since_tizen>
520         public async Task<bool> WriteValueAsync(BluetoothGattDescriptor descriptor)
521         {
522             return await _impl.WriteValueAsyncTask(descriptor.GetHandle());
523         }
524
525         internal bool Isvalid()
526         {
527             return _impl.GetHandle().IsInvalid == false;
528         }
529
530         /// <summary>
531         /// Destroys the current object.
532         /// </summary>
533         ~BluetoothGattClient()
534         {
535             Dispose(false);
536         }
537
538         /// <summary>
539         /// Destroys the current object.
540         /// </summary>
541         /// <feature>http://tizen.org/feature/network.bluetooth.le.gatt.client</feature>
542         /// <since_tizen> 6 </since_tizen>
543         public void Dispose()
544         {
545             Dispose(true);
546             GC.SuppressFinalize(this);
547         }
548
549         /// <summary>
550         /// Releases all the resources currently used by this instance.
551         /// </summary>
552         /// <param name="disposing">true if the managed resources should be disposed, otherwise false.</param>
553         /// <since_tizen> 6 </since_tizen>
554         protected virtual void Dispose(bool disposing)
555         {
556             if (disposing)
557             {
558                 _impl?.GetHandle()?.Dispose();
559                 _impl = null;
560                 StaticConnectionStateChanged -= OnConnectionStateChanged;
561             }
562         }
563     }
564
565     /// <summary>
566     /// The Bluetooth GATT service.
567     /// </summary>
568     /// <since_tizen> 3 </since_tizen>
569     public class BluetoothGattService
570     {
571         private BluetoothGattServiceImpl _impl;
572         private BluetoothGattClient _parentClient = null;
573         private BluetoothGattServer _parentServer = null;
574         private BluetoothGattService _parentService = null;
575
576         /// <summary>
577         /// The constructor.
578         /// </summary>
579         /// <param name="uuid">The UUID of the service.</param>
580         /// <param name="type">The type of service.</param>
581         /// <exception cref="InvalidOperationException">Thrown when the create GATT service procedure fails.</exception>
582         /// <since_tizen> 3 </since_tizen>
583         public BluetoothGattService(string uuid, BluetoothGattServiceType type)
584         {
585             Uuid = uuid;
586             _impl = new BluetoothGattServiceImpl(uuid, type);
587         }
588
589         internal BluetoothGattService(BluetoothGattServiceImpl impl, string uuid)
590         {
591             Uuid = uuid;
592             _impl = impl;
593         }
594
595         /// <summary>
596         /// Specification name from the UUID.
597         /// </summary>
598         /// <since_tizen> 3 </since_tizen>
599         public string Uuid { get; }
600
601         /// <summary>
602         /// Adds a characteristic to this service.
603         /// </summary>
604         /// <param name="characteristic">The characteristic to be added.</param>
605         /// <returns>true on success, false otherwise.</returns>
606         /// <exception cref="InvalidOperationException">Thrown when the add GATT characteristic procedure fails.</exception>
607         /// <since_tizen> 3 </since_tizen>
608         public void AddCharacteristic(BluetoothGattCharacteristic characteristic)
609         {
610             if (GetGattClient() != null)
611             {
612                 BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NotSupported);
613             }
614
615             if (characteristic.GetService() != null)
616             {
617                 BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.InvalidParameter);
618             }
619
620             _impl.AddCharacteristic(characteristic);
621             characteristic.SetParent(this);
622         }
623
624         /// <summary>
625         /// Gets the characteristic with the given UUID that belongs to this service.
626         /// </summary>
627         /// <param name="uuid">The UUID for the characteristic to get.</param>
628         /// <returns>The characteristic with a given UUID if it exists, null otherwise.</returns>
629         /// <since_tizen> 3 </since_tizen>
630         public BluetoothGattCharacteristic GetCharacteristic(string uuid)
631         {
632             return _impl.GetCharacteristic(this, uuid);
633         }
634
635         /// <summary>
636         /// Gets list of the characteristic that belongs to this service.
637         /// </summary>
638         /// <returns>The list of the characteristic that belongs to this service.</returns>
639         /// <since_tizen> 3 </since_tizen>
640         public IEnumerable<BluetoothGattCharacteristic> GetCharacteristics()
641         {
642             return _impl.GetCharacteristics(this);
643         }
644
645         /// <summary>
646         /// Includes a service to this service.
647         /// </summary>
648         /// <param name="service">The service to be included.</param>
649         /// <returns>true on success, false otherwise</returns>
650         /// <exception cref="InvalidOperationException">Thrown when the add GATT service procedure fails.</exception>///
651         /// <since_tizen> 3 </since_tizen>
652         public void AddService(BluetoothGattService service)
653         {
654             if (GetGattClient() != null)
655             {
656                 BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NotSupported);
657             }
658
659             if (service.IsRegistered())
660             {
661                 BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.InvalidParameter);
662             }
663
664             _impl.AddIncludeService(service);
665             service.SetParent(this);
666         }
667
668         /// <summary>
669         /// Gets the included service.
670         /// </summary>
671         /// <param name="uuid">The UUID for the service to get.</param>
672         /// <returns>The service with a given UUID if it exists, null otherwise.</returns>
673         /// <since_tizen> 3 </since_tizen>
674         public BluetoothGattService GetIncludeService(string uuid)
675         {
676             return _impl.GetIncludeService(this, uuid);
677         }
678
679         /// <summary>
680         /// Gets the included service list of this service.
681         /// </summary>
682         /// <returns>The included service list of this service.</returns>
683         /// <since_tizen> 3 </since_tizen>
684         public IEnumerable<BluetoothGattService> GetIncludeServices()
685         {
686             return _impl.GetIncludeServices(this);
687         }
688
689         /// <summary>
690         /// Gets the server instance which the specified service belongs to.
691         /// </summary>
692         /// <returns>The server instance which the specified service belongs to.</returns>
693         /// <since_tizen> 3 </since_tizen>
694         public BluetoothGattServer GetGattServer()
695         {
696             return _parentServer;
697         }
698
699         /// <summary>
700         /// Gets the client instance which the specified service belongs to.
701         /// </summary>
702         /// <returns>The client instance which the specified service belongs to.</returns>
703         /// <since_tizen> 3 </since_tizen>
704         public BluetoothGattClient GetGattClient()
705         {
706             return _parentClient;
707         }
708
709         internal BluetoothGattAttributeHandle GetHandle()
710         {
711             return _impl.GetHandle();
712         }
713
714         internal void SetParent(BluetoothGattService parent)
715         {
716             if (!IsRegistered())
717             {
718                 _parentService = parent;
719                 _impl.ReleaseHandleOwnership();
720             }
721         }
722
723         internal void SetParent(BluetoothGattClient parent)
724         {
725             if (!IsRegistered())
726             {
727                 _parentClient = parent;
728                 _impl.ReleaseHandleOwnership();
729             }
730         }
731
732         internal void SetParent(BluetoothGattServer parent)
733         {
734             if (!IsRegistered())
735             {
736                 _parentServer = parent;
737                 _impl.ReleaseHandleOwnership();
738             }
739         }
740
741         internal void UnregisterService()
742         {
743             _parentServer = null;
744             _parentClient = null;
745             _parentService = null;
746         }
747
748         internal bool IsRegistered()
749         {
750             return _parentClient != null || _parentServer != null || _parentService != null;
751         }
752     }
753
754     /// <summary>
755     /// The Bluetooth GATT characteristic.
756     /// </summary>
757     /// <since_tizen> 3 </since_tizen>
758     public class BluetoothGattCharacteristic : BluetoothGattAttribute
759     {
760         private BluetoothGattCharacteristicImpl _impl;
761         private BluetoothGattService _parent = null;
762
763         private Interop.Bluetooth.BtClientCharacteristicValueChangedCallback _characteristicValueChangedCallback;
764         private Interop.Bluetooth.BtGattServerNotificationStateChangeCallback _notificationStateChangedCallback;
765
766         private EventHandler<ValueChangedEventArgs> _characteristicValueChanged;
767         internal EventHandler<NotificationStateChangedEventArg> _notificationStateChanged;
768
769         /// <summary>
770         /// The constructor.
771         /// </summary>
772         /// <param name="uuid">The UUID of the characterstic.</param>
773         /// <param name="permissions">Permissions for the characterstic.</param>
774         /// <param name="properties">Properties set for the characterstic.</param>
775         /// <param name="value">The value associated with the characterstic.</param>
776         /// <remarks>throws in case of internal error.</remarks>
777         /// <exception cref="InvalidOperationException">Thrown when the create GATT characteristics procedure fails.</exception>
778         /// <since_tizen> 3 </since_tizen>
779         public BluetoothGattCharacteristic(string uuid, BluetoothGattPermission permissions, BluetoothGattProperty properties, byte[] value) : base(uuid, permissions)
780         {
781             _impl = new BluetoothGattCharacteristicImpl(uuid, permissions, properties, value);
782         }
783
784         internal BluetoothGattCharacteristic(BluetoothGattCharacteristicImpl impl, string uuid, BluetoothGattPermission permission) : base(uuid, permission)
785         {
786             _impl = impl;
787         }
788
789         /// <summary>
790         /// The CharacteristicValueChanged event is raised when the server notifies for change in this characteristic value.
791         /// </summary>
792         /// <remarks>
793         /// Adding the event handle on characteristic on the server side will not have any effect.
794         /// </remarks>
795         /// <since_tizen> 3 </since_tizen>
796         public event EventHandler<ValueChangedEventArgs> ValueChanged
797         {
798             add
799             {
800                 if (Client != null)
801                 {
802                     if (_characteristicValueChanged == null)
803                     {
804                         _characteristicValueChangedCallback = (gattHandle, characteristicValue, len, userData) =>
805                         {
806                             _characteristicValueChanged?.Invoke(this, new ValueChangedEventArgs(characteristicValue, len));
807                         };
808
809                         _impl.SetCharacteristicValueChangedEvent(_characteristicValueChangedCallback);
810                     }
811                     _characteristicValueChanged = value;
812                 }
813             }
814             remove
815             {
816                 if (Client != null)
817                 {
818                     _characteristicValueChanged = null;
819                     if (_characteristicValueChanged == null)
820                     {
821                         _impl.UnsetCharacteristicValueChangedEvent();
822                     }
823
824                 }
825             }
826         }
827
828         /// <summary>
829         /// The NotificationStateChanged event is called when the client enables or disables the Notification/Indication for particular characteristics.
830         /// </summary>
831         /// <remarks>
832         /// Adding event handle on the characteristic on the client side will not have any effect.
833         /// </remarks>
834         /// <since_tizen> 3 </since_tizen>
835         public event EventHandler<NotificationStateChangedEventArg> NotificationStateChanged
836         {
837             add
838             {
839                 if (Server != null)
840                 {
841                     if (_notificationStateChangedCallback == null)
842                     {
843                         _notificationStateChangedCallback = (notify, serverHandle, characteristicHandle, userData) =>
844                         {
845                             _notificationStateChanged?.Invoke(this, new NotificationStateChangedEventArg(Server, notify));
846                         };
847
848                         _impl.SetNotificationStateChangedEvent(_notificationStateChangedCallback);
849                     }
850
851                     _notificationStateChanged = value;
852                 }
853             }
854             remove
855             {
856                 if (Server != null)
857                 {
858                     _notificationStateChanged = null;
859                     // CAPI does not allow unsetting ReadValueRequestedEventCallback.
860                 }
861             }
862         }
863
864         /// <summary>
865         /// The property for this characteristic.
866         /// </summary>
867         /// <since_tizen> 3 </since_tizen>
868         public BluetoothGattProperty Properties
869         {
870             get
871             {
872                 return _impl.GetProperties();
873             }
874             set
875             {
876                 if (Server != null)
877                 {
878                     _impl.SetProperties(value);
879                 }
880             }
881         }
882
883         /// <summary>
884         /// The write type to be used for write operations.
885         /// </summary>
886         /// <since_tizen> 3 </since_tizen>
887         public BluetoothGattWriteType WriteType
888         {
889             get
890             {
891                 return _impl.GetWriteType();
892             }
893             set
894             {
895                 _impl.SetWriteType(value);
896             }
897         }
898
899         internal override BluetoothGattClient Client
900         {
901             get
902             {
903                 return _parent?.GetGattClient();
904             }
905         }
906
907         internal override BluetoothGattServer Server
908         {
909             get
910             {
911                 return _parent?.GetGattServer();
912             }
913         }
914
915         internal override BluetoothGattAttributeImpl Impl
916         {
917             get
918             {
919                 return _impl;
920             }
921         }
922
923         /// <summary>
924         /// Adds a descriptor to this characteristic.
925         /// </summary>
926         /// <param name="descriptor">The descriptor to be added.</param>
927         /// <returns>true on success, false otherwise.</returns>
928         /// <exception cref="InvalidOperationException">Thrown when the add GATT descriptor procedure fails.</exception>
929         /// <since_tizen> 3 </since_tizen>
930         public void AddDescriptor(BluetoothGattDescriptor descriptor)
931         {
932             if (Client != null)
933             {
934                 BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.NotSupported);
935             }
936
937             if (descriptor.GetCharacteristic() != null)
938             {
939                 BluetoothErrorFactory.ThrowBluetoothException((int)BluetoothError.InvalidParameter);
940             }
941
942             _impl.AddDescriptor(descriptor);
943             descriptor.SetParent(this);
944         }
945
946         /// <summary>
947         /// Gets the descriptor with the given UUID that belongs to this characteristic.
948         /// </summary>
949         /// <param name="uuid">The UUID for the descriptor to get.</param>
950         /// <returns>The descriptor with a given UUID if it exists, null otherwise.</returns>
951         /// <since_tizen> 3 </since_tizen>
952         public BluetoothGattDescriptor GetDescriptor(string uuid)
953         {
954             return _impl.GetDescriptor(this, uuid);
955         }
956
957         /// <summary>
958         /// Gets the list of descriptors that belongs to this characteristic.
959         /// </summary>
960         /// <returns>The list of descriptors that belongs to this characteristic.</returns>
961         /// <since_tizen> 3 </since_tizen>
962         public IEnumerable<BluetoothGattDescriptor> GetDescriptors()
963         {
964             return _impl.GetDescriptors(this);
965         }
966
967         /// <summary>
968         /// Gets the service instance, which the specified characterstic belongs to.
969         /// </summary>
970         /// <returns>The characteristic instance, the specified characterstic belongs to.</returns>
971         /// <since_tizen> 3 </since_tizen>
972         public BluetoothGattService GetService()
973         {
974             return _parent;
975         }
976
977         internal void SetParent(BluetoothGattService parent)
978         {
979             if (_parent == null)
980             {
981                 _parent = parent;
982                 ReleaseHandleOwnership();
983             }
984          }
985     }
986
987     /// <summary>
988     /// The Bluetooth GATT descriptor.
989     /// </summary>
990     /// <since_tizen> 3 </since_tizen>
991     public class BluetoothGattDescriptor : BluetoothGattAttribute
992     {
993         private BluetoothGattCharacteristic _parent = null;
994         private BluetoothGattDescriptorImpl _impl;
995
996         /// <summary>
997         /// The constructor.
998         /// </summary>
999         /// <param name="uuid">The UUID of the descriptor.</param>
1000         /// <param name="permisions">Permissions for the descriptor.</param>
1001         /// <param name="value">The value associated with the descriptor.</param>
1002         /// <remarks>throws in case of internal error.</remarks>
1003         /// <exception cref="InvalidOperationException">Thrown when the create GATT descriptor procedure fails.</exception>
1004         /// <since_tizen> 3 </since_tizen>
1005         public BluetoothGattDescriptor(string uuid, BluetoothGattPermission permisions, byte[] value) : base (uuid, permisions)
1006         {
1007             _impl = new BluetoothGattDescriptorImpl(uuid, permisions, value);
1008         }
1009
1010         internal BluetoothGattDescriptor(BluetoothGattDescriptorImpl impl, string uuid, BluetoothGattPermission permission) : base(uuid, permission)
1011         {
1012             _impl = impl;
1013         }
1014
1015         internal override BluetoothGattClient Client
1016         {
1017             get
1018             {
1019                 return _parent?.Client;
1020             }
1021         }
1022
1023         internal override BluetoothGattServer Server
1024         {
1025             get
1026             {
1027                 return _parent?.Server;
1028             }
1029         }
1030
1031         internal override BluetoothGattAttributeImpl Impl
1032         {
1033             get
1034             {
1035                 return _impl;
1036             }
1037         }
1038
1039         /// <summary>
1040         /// Gets the characteristic instance, which the specified descriptor belongs to.
1041         /// </summary>
1042         /// <returns>The characteristic instance, the specified descriptor belongs to.</returns>
1043         /// <since_tizen> 3 </since_tizen>
1044         public BluetoothGattCharacteristic GetCharacteristic()
1045         {
1046             return _parent;
1047         }
1048
1049         internal void SetParent(BluetoothGattCharacteristic parent)
1050         {
1051             if (_parent == null)
1052             {
1053                 _parent = parent;
1054                 ReleaseHandleOwnership();
1055             }
1056         }
1057     }
1058
1059     /// <summary>
1060     /// The Bluetooth GATT attribute.
1061     /// </summary>
1062     /// <since_tizen> 3 </since_tizen>
1063     public abstract class BluetoothGattAttribute
1064     {
1065         private Interop.Bluetooth.BtGattServerReadValueRequestedCallback _readValueRequestedCallback;
1066         private Interop.Bluetooth.BtGattServerWriteValueRequestedCallback _writeValueRequestedCallback;
1067
1068         private EventHandler<ReadRequestedEventArgs> _readValueRequested;
1069         private EventHandler<WriteRequestedEventArgs> _writeValueRequested;
1070
1071         /// <summary>
1072         /// The constructor.
1073         /// </summary>
1074         /// <param name="uuid">The UUID of the GATT attribute.</param>
1075         /// <param name="permission">Permission for the GATT attribute.</param>
1076         /// <since_tizen> 3 </since_tizen>
1077         public BluetoothGattAttribute(string uuid, BluetoothGattPermission permission)
1078         {
1079             Uuid = uuid;
1080             Permissions = permission;
1081         }
1082
1083         // Events
1084
1085         /// <summary>
1086         /// This event is called when the client request to read the value of a characteristic or a descriptor.
1087         /// </summary>
1088         /// <exception cref="InvalidOperationException">Thrown when the set read value requested callback procedure fails.</exception>
1089         /// <since_tizen> 3 </since_tizen>
1090         public event EventHandler<ReadRequestedEventArgs> ReadRequested
1091         {
1092             add
1093             {
1094                 if (Server == null) return;
1095                 if (_readValueRequestedCallback == null)
1096                 {
1097                     _readValueRequestedCallback = (clientAddress, requestId, serverHandle, gattHandle, offset, userData) =>
1098                     {
1099                         _readValueRequested?.Invoke(this, new ReadRequestedEventArgs(Server, clientAddress, requestId, offset));
1100                     };
1101                     Impl.SetReadValueRequestedEventCallback(_readValueRequestedCallback);
1102                 }
1103                 _readValueRequested = value;
1104             }
1105             remove
1106             {
1107                 if (Server == null) return;
1108                 _readValueRequested = null;
1109                 // CAPI does not allow unsetting ReadValueRequestedEventCallback.
1110             }
1111         }
1112
1113         /// <summary>
1114         /// This event is called when a value of a characteristic or a descriptor has been changed by a client.
1115         /// </summary>
1116         /// <exception cref="InvalidOperationException">Thrown when the set write value requested callback procedure fails.</exception>
1117         /// <since_tizen> 3 </since_tizen>
1118         public event EventHandler<WriteRequestedEventArgs> WriteRequested
1119         {
1120             add
1121             {
1122                 if (Server == null) return;
1123                 if (_writeValueRequested == null)
1124                 {
1125                     _writeValueRequestedCallback = (clientAddress, requestId, serverHandle, gattHandle, response_needed, offset, valueToWrite, len, userData) =>
1126                     {
1127                         _writeValueRequested?.Invoke(this, new WriteRequestedEventArgs(Server, clientAddress, requestId, valueToWrite, offset, response_needed));
1128                     };
1129                     Impl.SetWriteValueRequestedEventCallback(_writeValueRequestedCallback);
1130                 }
1131                 _writeValueRequested = value;
1132             }
1133             remove
1134             {
1135                 if (Server == null) return;
1136                 _writeValueRequested = null;
1137                 // CAPI does not allow unsetting ReadValueRequestedEventCallback.
1138             }
1139         }
1140
1141         /// <summary>
1142         /// The attribute's UUID.
1143         /// </summary>
1144         /// <since_tizen> 3 </since_tizen>
1145         public string Uuid { get; }
1146
1147         /// <summary>
1148         /// Permissions for this attribute.
1149         /// </summary>
1150         /// <since_tizen> 3 </since_tizen>
1151         public BluetoothGattPermission Permissions { get; }
1152
1153         /// <summary>
1154         /// The value of this descriptor.
1155         /// </summary>
1156         /// <since_tizen> 3 </since_tizen>
1157         public byte[] Value
1158         {
1159             get
1160             {
1161                 return Impl.GetValue();
1162             }
1163             set
1164             {
1165                 Impl.SetValue(value);
1166             }
1167         }
1168
1169         internal abstract BluetoothGattClient Client { get; }
1170         internal abstract BluetoothGattServer Server { get; }
1171         internal abstract BluetoothGattAttributeImpl Impl { get; }
1172
1173         /// <summary>
1174         /// Returns a string value at the specified offset.
1175         /// </summary>
1176         /// <param name="offset">An offset in the attribute value buffer.</param>
1177         /// <returns>The string value at specified offset.</returns>
1178         /// <since_tizen> 3 </since_tizen>
1179         public string GetValue(int offset)
1180         {
1181             return Impl.GetValue(offset);
1182         }
1183
1184         /// <summary>
1185         /// Sets the string value as a specified offset.
1186         /// </summary>
1187         /// <param name="value">value to set</param>
1188         /// <exception cref="InvalidOperationException">Throws exception if the value is null.</exception>
1189         /// <since_tizen> 3 </since_tizen>
1190         public void SetValue(string value)
1191         {
1192             if (string.IsNullOrEmpty(value))
1193                 GattUtil.ThrowForError((int)BluetoothError.InvalidParameter, "value should not be null");
1194
1195             byte[] val = Encoding.UTF8.GetBytes(value);
1196             Impl.SetValue(val);
1197         }
1198
1199         /// <summary>
1200         /// Returns a value at specified offset as the int value of the specified type.
1201         /// </summary>
1202         /// <param name="type">The type of the int value.</param>
1203         /// <param name="offset">An offset in the attribute value buffer.</param>
1204         /// <returns>The int value at given offset.</returns>
1205         /// <exception cref="InvalidOperationException">Throws exception if (offset + size of int value) is greater than the length of the value buffer.</exception>
1206         /// <since_tizen> 3 </since_tizen>
1207         public int GetValue(IntDataType type, int offset)
1208         {
1209             return Impl.GetValue(type, offset);
1210         }
1211
1212         /// <summary>
1213         /// Updates a value at the specified offset by the int value of the specified type.
1214         /// </summary>
1215         /// <param name="type">The type of the int value.</param>
1216         /// <param name="value">The value to set.</param>
1217         /// <param name="offset">An offset in the attribute value buffer.</param>
1218         /// <exception cref="InvalidOperationException">Throws exception if (offset + size of int value) is greater than the length of the value buffer.</exception>
1219         /// <since_tizen> 3 </since_tizen>
1220         public void SetValue(IntDataType type, int value, int offset)
1221         {
1222             Impl.SetValue(type, value, offset);
1223         }
1224
1225         /// <summary>
1226         /// Returns a value at the specified offset as the float value of the specified type.
1227         /// </summary>
1228         /// <param name="type">The type of the float value.</param>
1229         /// <param name="offset">An offset in the attribute value buffer.</param>
1230         /// <returns>The float value at given offset.</returns>
1231         /// <exception cref="InvalidOperationException">Throws exception if (offset + size of float value) is greater than the length of the value buffer.</exception>
1232         /// <since_tizen> 3 </since_tizen>
1233         public float GetValue(FloatDataType type, int offset)
1234         {
1235             return Impl.GetValue(type, offset);
1236         }
1237
1238         /// <summary>
1239         /// Updates the value at the specified offset by the float value of the specified type.
1240         /// </summary>
1241         /// <param name="type">The type of the float value.</param>
1242         /// <param name="mantissa">The mantissa of the float value.</param>
1243         /// <param name="exponent">An exponent of the float value.</param>
1244         /// <param name="offset">An offset in the attribute value buffer.</param>
1245         /// <exception cref="InvalidOperationException">Throws exception if (offset + size of float value) is greater than the length of the value buffer.</exception>
1246         /// <since_tizen> 3 </since_tizen>
1247         public void SetValue(FloatDataType type, int mantissa, int exponent, int offset)
1248         {
1249             Impl.SetValue(type, mantissa, exponent, offset);
1250         }
1251
1252         internal void ReleaseHandleOwnership()
1253         {
1254             Impl.ReleaseHandleOwnership();
1255         }
1256
1257         internal BluetoothGattAttributeHandle GetHandle()
1258         {
1259             return Impl.GetHandle();
1260         }
1261     }
1262 }